diff --git a/clients/cli/common.c b/clients/cli/common.c index 3656cdbf82..e37d9d8c8b 100644 --- a/clients/cli/common.c +++ b/clients/cli/common.c @@ -36,19 +36,122 @@ #include "utils.h" -extern GMainLoop *loop; +/*****************************************************************************/ -const NmcMetaGenericInfo *const nmc_fields_ip4_config[] = { - NMC_META_GENERIC ("GROUP"), /* 0 */ - NMC_META_GENERIC ("ADDRESS"), /* 1 */ - NMC_META_GENERIC ("GATEWAY"), /* 2 */ - NMC_META_GENERIC ("ROUTE"), /* 3 */ - NMC_META_GENERIC ("DNS"), /* 4 */ - NMC_META_GENERIC ("DOMAIN"), /* 5 */ - NMC_META_GENERIC ("WINS"), /* 6 */ +static gconstpointer +_metagen_ip4_config_get_fcn (const NMMetaEnvironment *environment, + gpointer environment_user_data, + const NmcMetaGenericInfo *info, + gpointer target, + NMMetaAccessorGetType get_type, + NMMetaAccessorGetFlags get_flags, + NMMetaAccessorGetOutFlags *out_flags, + gpointer *out_to_free) +{ + NMIPConfig *cfg4 = target; + GPtrArray *ptr_array; + char **arr; + const char *const*arrc; + guint i = 0; + + nm_assert (info->info_type < _NMC_GENERIC_INFO_TYPE_IP4_CONFIG_NUM); + + NMC_HANDLE_TERMFORMAT (NM_META_TERM_COLOR_NORMAL); + + switch (info->info_type) { + case NMC_GENERIC_INFO_TYPE_IP4_CONFIG_ADDRESS: + if (!NM_FLAGS_HAS (get_flags, NM_META_ACCESSOR_GET_FLAGS_ACCEPT_STRV)) + return NULL; + ptr_array = nm_ip_config_get_addresses (cfg4); + if (ptr_array) { + arr = g_new (char *, ptr_array->len + 1); + for (i = 0; i < ptr_array->len; i++) { + NMIPAddress *addr = g_ptr_array_index (ptr_array, i); + + arr[i] = g_strdup_printf ("%s/%u", + nm_ip_address_get_address (addr), + nm_ip_address_get_prefix (addr)); + } + arr[i] = NULL; + } else + arr = NULL; + goto arr_out; + case NMC_GENERIC_INFO_TYPE_IP4_CONFIG_GATEWAY: + return nm_ip_config_get_gateway (cfg4); + case NMC_GENERIC_INFO_TYPE_IP4_CONFIG_ROUTE: + if (!NM_FLAGS_HAS (get_flags, NM_META_ACCESSOR_GET_FLAGS_ACCEPT_STRV)) + return NULL; + ptr_array = nm_ip_config_get_routes (cfg4); + if (ptr_array) { + arr = g_new (char *, ptr_array->len + 1); + for (i = 0; i < ptr_array->len; i++) { + NMIPRoute *route = g_ptr_array_index (ptr_array, i); + const char *next_hop; + + next_hop = nm_ip_route_get_next_hop (route); + if (!next_hop) + next_hop = "0.0.0.0"; + + arr[i] = g_strdup_printf ("dst = %s/%u, nh = %s%c mt = %u", + nm_ip_route_get_dest (route), + nm_ip_route_get_prefix (route), + next_hop, + nm_ip_route_get_metric (route) == -1 ? '\0' : ',', + (guint32) nm_ip_route_get_metric (route)); + } + arr[i] = NULL; + } else + arr = NULL; + goto arr_out; + case NMC_GENERIC_INFO_TYPE_IP4_CONFIG_DNS: + if (!NM_FLAGS_HAS (get_flags, NM_META_ACCESSOR_GET_FLAGS_ACCEPT_STRV)) + return NULL; + arrc = nm_ip_config_get_nameservers (cfg4); + goto arrc_out; + case NMC_GENERIC_INFO_TYPE_IP4_CONFIG_DOMAIN: + if (!NM_FLAGS_HAS (get_flags, NM_META_ACCESSOR_GET_FLAGS_ACCEPT_STRV)) + return NULL; + arrc = nm_ip_config_get_domains (cfg4); + goto arrc_out; + case NMC_GENERIC_INFO_TYPE_IP4_CONFIG_WINS: + if (!NM_FLAGS_HAS (get_flags, NM_META_ACCESSOR_GET_FLAGS_ACCEPT_STRV)) + return NULL; + arrc = nm_ip_config_get_wins_servers (cfg4); + goto arrc_out; + default: + break; + } + + g_return_val_if_reached (NULL); + +arrc_out: + *out_flags |= NM_META_ACCESSOR_GET_OUT_FLAGS_STRV; + return arrc; + +arr_out: + *out_flags |= NM_META_ACCESSOR_GET_OUT_FLAGS_STRV; + *out_to_free = arr; + return arr; +} + +const NmcMetaGenericInfo *const metagen_ip4_config[_NMC_GENERIC_INFO_TYPE_IP4_CONFIG_NUM + 1] = { +#define _METAGEN_IP4_CONFIG(type, name) \ + [type] = NMC_META_GENERIC(name, .info_type = type, .get_fcn = _metagen_ip4_config_get_fcn) + _METAGEN_IP4_CONFIG (NMC_GENERIC_INFO_TYPE_IP4_CONFIG_ADDRESS, "ADDRESS"), + _METAGEN_IP4_CONFIG (NMC_GENERIC_INFO_TYPE_IP4_CONFIG_GATEWAY, "GATEWAY"), + _METAGEN_IP4_CONFIG (NMC_GENERIC_INFO_TYPE_IP4_CONFIG_ROUTE, "ROUTE"), + _METAGEN_IP4_CONFIG (NMC_GENERIC_INFO_TYPE_IP4_CONFIG_DNS, "DNS"), + _METAGEN_IP4_CONFIG (NMC_GENERIC_INFO_TYPE_IP4_CONFIG_DOMAIN, "DOMAIN"), + _METAGEN_IP4_CONFIG (NMC_GENERIC_INFO_TYPE_IP4_CONFIG_WINS, "WINS"), +}; + +static const NmcMetaGenericInfo *const metagen_ip4_config_group[] = { + NMC_META_GENERIC_WITH_NESTED ("IP4", metagen_ip4_config, .name_header = N_("GROUP")), NULL, }; +/*****************************************************************************/ + const NmcMetaGenericInfo *const nmc_fields_dhcp4_config[] = { NMC_META_GENERIC ("GROUP"), /* 0 */ NMC_META_GENERIC ("OPTION"), /* 1 */ @@ -74,87 +177,25 @@ const NmcMetaGenericInfo *const nmc_fields_dhcp6_config[] = { gboolean print_ip4_config (NMIPConfig *cfg4, const NmcConfig *nmc_config, - const char *group_prefix, const char *one_field) { - GPtrArray *ptr_array; - char **addr_arr = NULL; - char **route_arr = NULL; - char **dns_arr = NULL; - char **domain_arr = NULL; - char **wins_arr = NULL; - int i = 0; - const NMMetaAbstractInfo *const*tmpl; - NmcOutputField *arr; - NMC_OUTPUT_DATA_DEFINE_SCOPED (out); + gs_free_error GError *error = NULL; + gs_free char *field_str = NULL; if (cfg4 == NULL) return FALSE; - tmpl = (const NMMetaAbstractInfo *const*) nmc_fields_ip4_config; - out_indices = parse_output_fields (one_field, - tmpl, FALSE, NULL, NULL); - arr = nmc_dup_fields_array (tmpl, NMC_OF_FLAG_FIELD_NAMES); - g_ptr_array_add (out.output_data, arr); + if (one_field) + field_str = g_strdup_printf ("IP4.%s", one_field); - /* addresses */ - ptr_array = nm_ip_config_get_addresses (cfg4); - if (ptr_array) { - addr_arr = g_new (char *, ptr_array->len + 1); - for (i = 0; i < ptr_array->len; i++) { - NMIPAddress *addr = (NMIPAddress *) g_ptr_array_index (ptr_array, i); - - addr_arr[i] = g_strdup_printf ("%s/%u", - nm_ip_address_get_address (addr), - nm_ip_address_get_prefix (addr)); - } - addr_arr[i] = NULL; + if (!nmc_print (nmc_config, + (gpointer[]) { cfg4, NULL }, + NULL, + (const NMMetaAbstractInfo *const*) metagen_ip4_config_group, + field_str, + &error)) { + return FALSE; } - - /* routes */ - ptr_array = nm_ip_config_get_routes (cfg4); - if (ptr_array) { - route_arr = g_new (char *, ptr_array->len + 1); - for (i = 0; i < ptr_array->len; i++) { - NMIPRoute *route = (NMIPRoute *) g_ptr_array_index (ptr_array, i); - const char *next_hop; - - next_hop = nm_ip_route_get_next_hop (route); - if (!next_hop) - next_hop = "0.0.0.0"; - - route_arr[i] = g_strdup_printf ("dst = %s/%u, nh = %s%c mt = %u", - nm_ip_route_get_dest (route), - nm_ip_route_get_prefix (route), - next_hop, - nm_ip_route_get_metric (route) == -1 ? '\0' : ',', - (guint32) nm_ip_route_get_metric (route)); - } - route_arr[i] = NULL; - } - - /* DNS */ - dns_arr = g_strdupv ((char **) nm_ip_config_get_nameservers (cfg4)); - - /* domains */ - domain_arr = g_strdupv ((char **) nm_ip_config_get_domains (cfg4)); - - /* WINS */ - wins_arr = g_strdupv ((char **) nm_ip_config_get_wins_servers (cfg4)); - - arr = nmc_dup_fields_array (tmpl, NMC_OF_FLAG_SECTION_PREFIX); - set_val_strc (arr, 0, group_prefix); - set_val_arr (arr, 1, addr_arr); - set_val_strc (arr, 2, nm_ip_config_get_gateway (cfg4)); - set_val_arr (arr, 3, route_arr); - set_val_arr (arr, 4, dns_arr); - set_val_arr (arr, 5, domain_arr); - set_val_arr (arr, 6, wins_arr); - g_ptr_array_add (out.output_data, arr); - - print_data_prepare_width (out.output_data); - print_data (nmc_config, out_indices, NULL, 0, &out); - return TRUE; } @@ -840,7 +881,7 @@ nmc_secrets_requested (NMSecretAgentSimple *agent, } success = get_secrets_from_user (request_id, title, msg, connection, nmc->nmc_config.in_editor || nmc->ask, - nmc->show_secrets, nmc->pwds_hash, secrets); + nmc->nmc_config.show_secrets, nmc->pwds_hash, secrets); if (success) nm_secret_agent_simple_response (agent, request_id, secrets); else { @@ -1085,6 +1126,38 @@ nmc_rl_gen_func_basic (const char *text, int state, const char *const*words) return NULL; } +static struct { + bool initialized; + guint idx; + char **values; +} _rl_compentry_func_wrap = { 0 }; + +static char * +_rl_compentry_func_wrap_fcn (const char *text, int state) +{ + g_return_val_if_fail (_rl_compentry_func_wrap.initialized, NULL); + + if ( !_rl_compentry_func_wrap.values + || !_rl_compentry_func_wrap.values[_rl_compentry_func_wrap.idx]) { + g_strfreev (_rl_compentry_func_wrap.values); + _rl_compentry_func_wrap.values = NULL; + _rl_compentry_func_wrap.initialized = FALSE; + return NULL; + } + + return g_strdup (_rl_compentry_func_wrap.values[_rl_compentry_func_wrap.idx++]); +} + +NmcCompEntryFunc +nmc_rl_compentry_func_wrap (const char *const*values) +{ + g_strfreev (_rl_compentry_func_wrap.values); + _rl_compentry_func_wrap.values = g_strdupv ((char **) values); + _rl_compentry_func_wrap.idx = 0; + _rl_compentry_func_wrap.initialized = TRUE; + return _rl_compentry_func_wrap_fcn; +} + char * nmc_rl_gen_func_ifnames (const char *text, int state) { @@ -1170,8 +1243,6 @@ nmc_parse_lldp_capabilities (guint value) return g_string_free (str, FALSE); } -extern GMainLoop *loop; - static void command_done (GObject *object, GAsyncResult *res, gpointer user_data) { diff --git a/clients/cli/common.h b/clients/cli/common.h index 2534c4f73f..b7057e462f 100644 --- a/clients/cli/common.h +++ b/clients/cli/common.h @@ -25,7 +25,7 @@ #include "nmcli.h" #include "nm-secret-agent-simple.h" -gboolean print_ip4_config (NMIPConfig *cfg4, const NmcConfig *nmc_config, const char *group_prefix, const char *one_field); +gboolean print_ip4_config (NMIPConfig *cfg4, const NmcConfig *nmc_config, const char *one_field); gboolean print_ip6_config (NMIPConfig *cfg6, const NmcConfig *nmc_config, const char *group_prefix, const char *one_field); gboolean print_dhcp4_config (NMDhcpConfig *dhcp4, const NmcConfig *nmc_config, const char *group_prefix, const char *one_field); gboolean print_dhcp6_config (NMDhcpConfig *dhcp6, const NmcConfig *nmc_config, const char *group_prefix, const char *one_field); @@ -53,6 +53,7 @@ char *nmc_unique_connection_name (const GPtrArray *connections, void nmc_cleanup_readline (void); char *nmc_readline (const char *prompt_fmt, ...) G_GNUC_PRINTF (1, 2); char *nmc_readline_echo (gboolean echo_on, const char *prompt_fmt, ...) G_GNUC_PRINTF (2, 3); +NmcCompEntryFunc nmc_rl_compentry_func_wrap (const char *const*values); char *nmc_rl_gen_func_basic (const char *text, int state, const char *const*words); char *nmc_rl_gen_func_ifnames (const char *text, int state); gboolean nmc_get_in_readline (void); @@ -80,7 +81,7 @@ void nmc_complete_bool (const char *prefix); const char *nmc_error_get_simple_message (GError *error); -extern const NmcMetaGenericInfo *const nmc_fields_ip4_config[]; +extern const NmcMetaGenericInfo *const metagen_ip4_config[]; extern const NmcMetaGenericInfo *const nmc_fields_dhcp4_config[]; extern const NmcMetaGenericInfo *const nmc_fields_ip6_config[]; extern const NmcMetaGenericInfo *const nmc_fields_dhcp6_config[]; diff --git a/clients/cli/connections.c b/clients/cli/connections.c index c981faecd5..cdc20578aa 100644 --- a/clients/cli/connections.c +++ b/clients/cli/connections.c @@ -42,24 +42,22 @@ #include "devices.h" #include "polkit-agent.h" +typedef enum { + PROPERTY_INF_FLAG_NONE = 0x0, + PROPERTY_INF_FLAG_DISABLED = 0x1, /* Don't ask due to runtime decision. */ + PROPERTY_INF_FLAG_ENABLED = 0x2, /* Override NM_META_PROPERTY_INF_FLAG_DONT_ASK due to runtime decision. */ + PROPERTY_INF_FLAG_ALL = 0x3, +} PropertyInfFlags; + +typedef char *(*CompEntryFunc) (const char *, int); + typedef struct _OptionInfo OptionInfo; struct _OptionInfo { - const char *setting_name; + const NMMetaSettingInfoEditor *setting_info; const char *property; const char *option; - enum { - OPTION_NONE = 0x00, - OPTION_REQD = 0x01, /* Don't ask to ask. */ - OPTION_DONT_ASK = 0x02, /* Don't ask interactively by default */ - OPTION_MULTI = 0x04, /* Ask multiple times, do an append instead of set. */ - - OPTION_DISABLED = 0x10, /* Don't ask due to runtime decision. */ - OPTION_ENABLED = 0x20, /* Override OPTION_DONT_ASK due to runtime decision. */ - } flags; - const char *prompt; - const char *def_hint; - gboolean (*check_and_set)(NmCli *nmc, NMConnection *connection, OptionInfo *option, const char *value, GError **error); - rl_compentry_func_t *generator_func; + gboolean (*check_and_set)(NmCli *nmc, NMConnection *connection, const OptionInfo *option, const char *value, GError **error); + CompEntryFunc generator_func; }; /* define some prompts for connection editor */ @@ -68,59 +66,6 @@ struct _OptionInfo { #define EDITOR_PROMPT_CON_TYPE _("Enter connection type: ") /* define some other prompts */ -#define PROMPT_CON_TYPE N_("Connection type") -#define PROMPT_IFNAME N_("Interface name [*]") -#define PROMPT_VPN_TYPE N_("VPN type") -#define PROMPT_MASTER N_("Master") - -#define PROMPT_IB_MODE N_("Transport mode") -#define WORD_DATAGRAM "datagram" -#define WORD_CONNECTED "connected" -#define PROMPT_IB_MODE_CHOICES "(" WORD_DATAGRAM "/" WORD_CONNECTED ") [" WORD_DATAGRAM "]" - -#define PROMPT_BT_TYPE N_("Bluetooth type") -#define WORD_PANU "panu" -#define WORD_DUN_GSM "dun-gsm" -#define WORD_DUN_CDMA "dun-cdma" -#define PROMPT_BT_TYPE_CHOICES "(" WORD_PANU "/" WORD_DUN_GSM "/" WORD_DUN_CDMA ") [" WORD_PANU "]" - -#define PROMPT_BOND_MODE N_("Bonding mode") - -#define PROMPT_BOND_MON_MODE N_("Bonding monitoring mode") -#define WORD_MIIMON "miimon" -#define WORD_ARP "arp" -#define PROMPT_BOND_MON_MODE_CHOICES "(" WORD_MIIMON "/" WORD_ARP ") [" WORD_MIIMON "]" - -#define PROMPT_ADSL_PROTO N_("Protocol") -#define PROMPT_ADSL_PROTO_CHOICES "(" NM_SETTING_ADSL_PROTOCOL_PPPOA "/" NM_SETTING_ADSL_PROTOCOL_PPPOE "/" NM_SETTING_ADSL_PROTOCOL_IPOATM ")" - -#define PROMPT_WIFI_MODE N_("Wi-Fi mode") -#define WORD_INFRA "infrastructure" -#define WORD_AP "ap" -#define WORD_ADHOC "adhoc" -#define PROMPT_WIFI_MODE_CHOICES "(" WORD_INFRA "/" WORD_AP "/" WORD_ADHOC ") [" WORD_INFRA "]" - -#define PROMPT_ADSL_ENCAP N_("ADSL encapsulation") -#define PROMPT_ADSL_ENCAP_CHOICES "(" NM_SETTING_ADSL_ENCAPSULATION_VCMUX "/" NM_SETTING_ADSL_ENCAPSULATION_LLC ") [none]" - -#define PROMPT_TUN_MODE N_("Tun mode") -#define WORD_TUN "tun" -#define WORD_TAP "tap" -#define PROMPT_TUN_MODE_CHOICES "(" WORD_TUN "/" WORD_TAP ") [" WORD_TUN "]" - -#define PROMPT_IP_TUNNEL_MODE N_("IP Tunnel mode") - -#define PROMPT_MACVLAN_MODE N_("MACVLAN mode") - -#define PROMPT_MACSEC_MODE N_("MACsec mode") -#define WORD_PSK "psk" -#define WORD_EAP "eap" -#define PROMPT_MACSEC_MODE_CHOICES "(" WORD_PSK "/" WORD_EAP ")" - -#define PROMPT_PROXY_METHOD N_("Proxy method") -#define WORD_NONE "none" -#define WORD_AUTO "auto" -#define PROMPT_PROXY_METHOD_CHOICES "(" WORD_NONE "/" WORD_AUTO ") [" WORD_NONE "]" #define PROMPT_CONNECTION _("Connection (name, UUID, or path)") #define PROMPT_VPN_CONNECTION _("VPN connection (name, UUID, or path)") @@ -213,7 +158,7 @@ const NmcMetaGenericInfo *const nmc_fields_con_active_details_vpn[] = { const NmcMetaGenericInfo *const nmc_fields_con_active_details_groups[] = { NMC_META_GENERIC_WITH_NESTED ("GENERAL", nmc_fields_con_active_details_general + 1), /* 0 */ - NMC_META_GENERIC_WITH_NESTED ("IP4", nmc_fields_ip4_config + 1), /* 1 */ + NMC_META_GENERIC_WITH_NESTED ("IP4", metagen_ip4_config), /* 1 */ NMC_META_GENERIC_WITH_NESTED ("DHCP4", nmc_fields_dhcp4_config + 1), /* 2 */ NMC_META_GENERIC_WITH_NESTED ("IP6", nmc_fields_ip6_config + 1), /* 3 */ NMC_META_GENERIC_WITH_NESTED ("DHCP6", nmc_fields_dhcp6_config + 1), /* 4 */ @@ -227,9 +172,6 @@ const NmcMetaGenericInfo *const nmc_fields_con_active_details_groups[] = { #define CON_SHOW_DETAIL_GROUP_PROFILE "profile" #define CON_SHOW_DETAIL_GROUP_ACTIVE "active" -/* glib main loop variable - defined in nmcli.c */ -extern GMainLoop *loop; - static guint progress_id = 0; /* ID of event source for displaying progress */ /* for readline TAB completion in editor */ @@ -242,8 +184,6 @@ typedef struct { } TabCompletionInfo; static TabCompletionInfo nmc_tab_completion = {NULL, NULL, NULL, NULL}; -static char *gen_connection_types (const char *text, int state); - static void usage (void) { @@ -555,23 +495,6 @@ usage_connection_export (void) "The data are directed to standard output or to a file if a name is given.\n\n")); } -static NMSetting * -nmc_setting_new_for_name (const char *name) -{ - GType stype; - NMSetting *setting = NULL; - - if (name) { - stype = nm_setting_lookup_type (name); - if (stype != G_TYPE_INVALID) { - setting = g_object_new (stype, NULL); - g_warn_if_fail (NM_IS_SETTING (setting)); - } - } - return setting; -} - -/* quit main loop */ static void quit (void) { @@ -581,7 +504,7 @@ quit (void) nmc_terminal_erase_line (); } - g_main_loop_quit (loop); /* quit main loop */ + g_main_loop_quit (loop); } static char * @@ -709,7 +632,7 @@ update_secrets_in_connection (NMRemoteConnection *remote, NMConnection *local) } static gboolean -nmc_connection_profile_details (NMConnection *connection, NmCli *nmc, gboolean secrets) +nmc_connection_profile_details (NMConnection *connection, NmCli *nmc) { GError *error = NULL; GArray *print_settings_array; @@ -771,7 +694,7 @@ nmc_connection_profile_details (NMConnection *connection, NmCli *nmc, gboolean s setting = nm_connection_get_setting_by_name (connection, nm_meta_setting_infos_editor[section_idx].general->setting_name); if (setting) { - setting_details (&nmc->nmc_config, setting, prop_name, secrets); + setting_details (&nmc->nmc_config, setting, prop_name); was_output = TRUE; } } @@ -1219,7 +1142,7 @@ nmc_active_connection_details (NMActiveConnection *acon, NmCli *nmc) gboolean b1 = FALSE; NMIPConfig *cfg4 = nm_active_connection_get_ip4_config (acon); - b1 = print_ip4_config (cfg4, &nmc->nmc_config, "IP4", group_fld); + b1 = print_ip4_config (cfg4, &nmc->nmc_config, group_fld); was_output = was_output || b1; } @@ -1391,8 +1314,8 @@ split_required_fields_for_con_show (const char *input, else if (!strcasecmp (*iter, CON_SHOW_DETAIL_GROUP_ACTIVE)) group_active = TRUE; else { - char *allowed1 = nmc_get_allowed_fields ((const NMMetaAbstractInfo *const*) nm_meta_setting_infos_editor_p ()); - char *allowed2 = nmc_get_allowed_fields ((const NMMetaAbstractInfo *const*) nmc_fields_con_active_details_groups); + char *allowed1 = nmc_get_allowed_fields ((const NMMetaAbstractInfo *const*) nm_meta_setting_infos_editor_p (), NULL); + char *allowed2 = nmc_get_allowed_fields ((const NMMetaAbstractInfo *const*) nmc_fields_con_active_details_groups, NULL); g_set_error (error, NMCLI_ERROR, 0, _("invalid field '%s'; allowed fields: %s and %s, or %s,%s"), *iter, allowed1, allowed2, CON_SHOW_DETAIL_GROUP_PROFILE, CON_SHOW_DETAIL_GROUP_ACTIVE); g_free (allowed1); @@ -1839,7 +1762,7 @@ do_connections_show (NmCli *nmc, int argc, char **argv) if (acon) con = NM_CONNECTION (nm_active_connection_get_connection (acon)); } - + if (!con && !acon) { g_string_printf (nmc->return_text, _("Error: %s - no such connection profile."), *argv); nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; @@ -1873,9 +1796,9 @@ do_connections_show (NmCli *nmc, int argc, char **argv) if (without_fields || profile_flds) { if (con) { nmc->required_fields = profile_flds; - if (nmc->show_secrets) + if (nmc->nmc_config.show_secrets) update_secrets_in_connection (NM_REMOTE_CONNECTION (con), con); - res = nmc_connection_profile_details (con, nmc, nmc->show_secrets); + res = nmc_connection_profile_details (con, nmc); nmc->required_fields = NULL; if (!res) goto finish; @@ -1893,7 +1816,7 @@ do_connections_show (NmCli *nmc, int argc, char **argv) } } new_line = TRUE; - + /* Take next argument. * But for pos != NULL we have more connections of the same name, * so process the same argument again. @@ -2830,253 +2753,29 @@ finish: return nmc->return_value; } -/*----------------------------------------------------------------------------*/ - -typedef struct NameItem { - const char *name; - const char *alias; - const struct NameItem *settings; - gboolean mandatory; -} NameItem; - -static const NameItem nmc_generic_settings [] = { - { NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL, TRUE }, - { NULL, NULL, NULL, FALSE } -}; - -static const NameItem nmc_ethernet_settings [] = { - { NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL, TRUE }, - { NM_SETTING_WIRED_SETTING_NAME, "ethernet", NULL, TRUE }, - { NM_SETTING_802_1X_SETTING_NAME, NULL, NULL, FALSE }, - { NM_SETTING_DCB_SETTING_NAME, NULL, NULL, FALSE }, - { NULL, NULL, NULL, FALSE } -}; - -static const NameItem nmc_infiniband_settings [] = { - { NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL, TRUE }, - { NM_SETTING_INFINIBAND_SETTING_NAME, NULL, NULL, TRUE }, - { NULL, NULL, NULL, FALSE } -}; - -static const NameItem nmc_wifi_settings [] = { - { NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL, TRUE }, - { NM_SETTING_WIRELESS_SETTING_NAME, "wifi", NULL, TRUE }, - { NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, "wifi-sec", NULL, FALSE }, - { NM_SETTING_802_1X_SETTING_NAME, NULL, NULL, FALSE }, - { NULL, NULL, NULL, FALSE } -}; - -static const NameItem nmc_wimax_settings [] = { - { NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL, TRUE }, - { NM_SETTING_WIMAX_SETTING_NAME, NULL, NULL, TRUE }, - { NULL, NULL, NULL, FALSE } -}; - -static const NameItem nmc_gsm_settings [] = { - { NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL, TRUE }, - { NM_SETTING_GSM_SETTING_NAME, NULL, NULL, TRUE }, - { NM_SETTING_SERIAL_SETTING_NAME, NULL, NULL, FALSE }, - { NM_SETTING_PPP_SETTING_NAME, NULL, NULL, FALSE }, - { NULL, NULL, NULL, FALSE } -}; - -static const NameItem nmc_cdma_settings [] = { - { NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL, TRUE }, - { NM_SETTING_CDMA_SETTING_NAME, NULL, NULL, TRUE }, - { NM_SETTING_SERIAL_SETTING_NAME, NULL, NULL, FALSE }, - { NM_SETTING_PPP_SETTING_NAME, NULL, NULL, FALSE }, - { NULL, NULL, NULL, FALSE } -}; - -static const NameItem nmc_bluetooth_settings [] = { - { NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL, TRUE }, - { NM_SETTING_BLUETOOTH_SETTING_NAME, NULL, NULL, TRUE }, - { NULL, NULL, NULL, FALSE } -}; - -static const NameItem nmc_adsl_settings [] = { - { NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL, TRUE }, - { NM_SETTING_ADSL_SETTING_NAME, NULL, NULL, TRUE }, - { NULL, NULL, NULL, FALSE } -}; - -/* PPPoE is a base connection type from historical reasons. - * See libnm-core/nm-setting.c:_nm_setting_is_base_type() - */ -static const NameItem nmc_pppoe_settings [] = { - { NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL, TRUE }, - { NM_SETTING_WIRED_SETTING_NAME, "ethernet", NULL, TRUE }, - { NM_SETTING_PPPOE_SETTING_NAME, NULL, NULL, TRUE }, - { NM_SETTING_PPP_SETTING_NAME, NULL, NULL, FALSE }, - { NM_SETTING_802_1X_SETTING_NAME, NULL, NULL, FALSE }, - { NULL, NULL, NULL, FALSE } -}; - -static const NameItem nmc_olpc_mesh_settings [] = { - { NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL, TRUE }, - { NM_SETTING_OLPC_MESH_SETTING_NAME, "olpc-mesh", NULL, TRUE }, - { NULL, NULL, NULL, FALSE } -}; - -static const NameItem nmc_vpn_settings [] = { - { NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL, TRUE }, - { NM_SETTING_VPN_SETTING_NAME, NULL, NULL, TRUE }, - { NULL, NULL, NULL, FALSE } -}; - -static const NameItem nmc_vlan_settings [] = { - { NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL, TRUE }, - { NM_SETTING_WIRED_SETTING_NAME, "ethernet", NULL, FALSE }, - { NM_SETTING_VLAN_SETTING_NAME, NULL, NULL, TRUE }, - { NULL, NULL, NULL, FALSE } -}; - -static const NameItem nmc_bond_settings [] = { - { NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL, TRUE }, - { NM_SETTING_BOND_SETTING_NAME, NULL, NULL, TRUE }, - { NM_SETTING_WIRED_SETTING_NAME, "ethernet", NULL, FALSE }, - { NULL, NULL, NULL, FALSE } -}; - -static const NameItem nmc_team_settings [] = { - { NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL, TRUE }, - { NM_SETTING_TEAM_SETTING_NAME, NULL, NULL, TRUE }, - { NM_SETTING_WIRED_SETTING_NAME, "ethernet", NULL, FALSE }, - { NULL, NULL, NULL, FALSE } -}; - -static const NameItem nmc_bridge_settings [] = { - { NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL, TRUE }, - { NM_SETTING_BRIDGE_SETTING_NAME, NULL, NULL, TRUE }, - { NM_SETTING_WIRED_SETTING_NAME, "ethernet", NULL, FALSE }, - { NULL, NULL, NULL, FALSE } -}; - -static const NameItem nmc_bond_slave_settings [] = { - { NULL, NULL, NULL, FALSE } -}; - -static const NameItem nmc_team_slave_settings [] = { - { NM_SETTING_TEAM_PORT_SETTING_NAME, NULL, NULL, TRUE }, - { NULL, NULL, NULL, FALSE } -}; - -static const NameItem nmc_bridge_slave_settings [] = { - { NM_SETTING_BRIDGE_PORT_SETTING_NAME, NULL, NULL, TRUE }, - { NULL, NULL, NULL, FALSE } -}; - -static const NameItem nmc_no_slave_settings [] = { - { NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL, NULL, FALSE }, - { NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL, NULL, FALSE }, - { NM_SETTING_PROXY_SETTING_NAME, NULL, NULL, FALSE }, - { NULL, NULL, NULL, FALSE } -}; - -static const NameItem nmc_tun_settings [] = { - { NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL, TRUE }, - { NM_SETTING_TUN_SETTING_NAME, NULL, NULL, TRUE }, - { NM_SETTING_WIRED_SETTING_NAME, "ethernet", NULL, FALSE }, - { NULL, NULL, NULL, FALSE } -}; - -static const NameItem nmc_ip_tunnel_settings [] = { - { NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL, TRUE }, - { NM_SETTING_IP_TUNNEL_SETTING_NAME, NULL, NULL, TRUE }, - { NULL, NULL, NULL, FALSE } -}; - -static const NameItem nmc_macsec_settings [] = { - { NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL, TRUE }, - { NM_SETTING_WIRED_SETTING_NAME, "ethernet", NULL, FALSE }, - { NM_SETTING_802_1X_SETTING_NAME, NULL, NULL, FALSE }, - { NM_SETTING_MACSEC_SETTING_NAME, NULL, NULL, TRUE }, - { NULL, NULL, NULL, FALSE } -}; - -static const NameItem nmc_macvlan_settings [] = { - { NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL, TRUE }, - { NM_SETTING_WIRED_SETTING_NAME, "ethernet", NULL, FALSE }, - { NM_SETTING_MACVLAN_SETTING_NAME, NULL, NULL, TRUE }, - { NULL, NULL, NULL, FALSE } -}; - -static const NameItem nmc_vxlan_settings [] = { - { NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL, TRUE }, - { NM_SETTING_VXLAN_SETTING_NAME, NULL, NULL, TRUE }, - { NM_SETTING_WIRED_SETTING_NAME, "ethernet", NULL, FALSE }, - { NULL, NULL, NULL, FALSE } -}; - -static const NameItem nmc_dummy_settings [] = { - { NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL, TRUE }, - { NM_SETTING_DUMMY_SETTING_NAME, NULL, NULL, TRUE }, - { NM_SETTING_WIRED_SETTING_NAME, "ethernet", NULL, FALSE }, - { NULL, NULL, NULL, FALSE } -}; - -static const NameItem nmc_valid_connection_types[] = { - { NM_SETTING_GENERIC_SETTING_NAME, NULL, nmc_generic_settings }, /* Needs to be first. */ - { NM_SETTING_WIRED_SETTING_NAME, "ethernet", nmc_ethernet_settings }, - { NM_SETTING_PPPOE_SETTING_NAME, NULL, nmc_pppoe_settings }, - { NM_SETTING_WIRELESS_SETTING_NAME, "wifi", nmc_wifi_settings }, - { NM_SETTING_WIMAX_SETTING_NAME, NULL, nmc_wimax_settings }, - { NM_SETTING_GSM_SETTING_NAME, NULL, nmc_gsm_settings }, - { NM_SETTING_CDMA_SETTING_NAME, NULL, nmc_cdma_settings }, - { NM_SETTING_INFINIBAND_SETTING_NAME, NULL, nmc_infiniband_settings }, - { NM_SETTING_ADSL_SETTING_NAME, NULL, nmc_adsl_settings }, - { NM_SETTING_BLUETOOTH_SETTING_NAME, NULL, nmc_bluetooth_settings }, - { NM_SETTING_VPN_SETTING_NAME, NULL, nmc_vpn_settings }, - { NM_SETTING_OLPC_MESH_SETTING_NAME, "olpc-mesh", nmc_olpc_mesh_settings }, - { NM_SETTING_VLAN_SETTING_NAME, NULL, nmc_vlan_settings }, - { NM_SETTING_BOND_SETTING_NAME, NULL, nmc_bond_settings }, - { NM_SETTING_TEAM_SETTING_NAME, NULL, nmc_team_settings }, - { NM_SETTING_BRIDGE_SETTING_NAME, NULL, nmc_bridge_settings }, - { "bond-slave", NULL, nmc_bond_slave_settings }, - { "team-slave", NULL, nmc_team_slave_settings }, - { "bridge-slave", NULL, nmc_bridge_slave_settings }, - { "no-slave", NULL, nmc_no_slave_settings }, - { NM_SETTING_TUN_SETTING_NAME, NULL, nmc_tun_settings }, - { NM_SETTING_IP_TUNNEL_SETTING_NAME, NULL, nmc_ip_tunnel_settings }, - { NM_SETTING_MACSEC_SETTING_NAME, NULL, nmc_macsec_settings }, - { NM_SETTING_MACVLAN_SETTING_NAME, NULL, nmc_macvlan_settings }, - { NM_SETTING_VXLAN_SETTING_NAME, NULL, nmc_vxlan_settings }, - { NM_SETTING_DUMMY_SETTING_NAME, NULL, nmc_dummy_settings }, - { NULL, NULL, NULL } -}; +/*****************************************************************************/ /* * Return the most appropriate name for the connection of a type 'name' possibly with given 'slave_type' * if exists, else return the 'name'. The returned string must not be freed. */ static const char * -get_name_alias (const char *name, const char *slave_type, const NameItem array[]) +get_name_alias_toplevel (const char *name, const char *slave_type) { - const NameItem *iter = &array[0]; + const NMMetaSettingInfoEditor *setting_info; if (slave_type) { - while (iter && iter->name) { - if ( g_str_has_prefix (iter->name, slave_type) - && g_str_has_suffix (iter->name, "-slave")) - break; - iter++; - } - } else if (name) { - while (iter && iter->name) { - if (!strcmp (name, iter->name)) - break; - iter++; - } - } else - return NULL; + const char *slave_name; - if (iter) { - if (iter->alias) - return iter->alias; - else - return iter->name; + if (nm_meta_setting_info_valid_parts_for_slave_type (slave_type, &slave_name)) + return slave_name ?: name; + return name; } + setting_info = nm_meta_setting_info_editor_find_by_name (name, FALSE); + if (setting_info) + return setting_info->alias ?: setting_info->general->setting_name; + return name; } @@ -3087,44 +2786,62 @@ get_name_alias (const char *name, const char *slave_type, const NameItem array[] * Returns: string; the caller is responsible for freeing it. */ static char * -get_valid_options_string (const NameItem *array, const NameItem *array_slv) +Get_valid_options_string (const NMMetaSettingValidPartItem *const*array, const NMMetaSettingValidPartItem *const*array_slv) { - const NameItem *iter = array; + const NMMetaSettingValidPartItem *const*iter = array; GString *str; int i; str = g_string_sized_new (150); for (i = 0; i < 2; i++, iter = array_slv) { - while (iter && iter->name) { + for (; iter && *iter; iter++) { + const NMMetaSettingInfoEditor *setting_info = (*iter)->setting_info; + if (str->len) g_string_append (str, ", "); - if (iter->alias) - g_string_append_printf (str, "%s (%s)", iter->name, iter->alias); + if (setting_info->alias) + g_string_append_printf (str, "%s (%s)", setting_info->general->setting_name, setting_info->alias); else - g_string_append (str, iter->name); - iter++; + g_string_append (str, setting_info->general->setting_name); } } return g_string_free (str, FALSE); } -static const NameItem * +static char * +get_valid_options_string_toplevel (void) +{ + GString *str; + int i; + + str = g_string_sized_new (150); + for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++) { + const NMMetaSettingInfoEditor *setting_info = &nm_meta_setting_infos_editor[i]; + + if (str->len) + g_string_append (str, ", "); + if (setting_info->alias) + g_string_append_printf (str, "%s (%s)", setting_info->general->setting_name, setting_info->alias); + else + g_string_append (str, setting_info->general->setting_name); + } + return g_string_free (str, FALSE); +} + +static const NMMetaSettingValidPartItem *const* get_valid_settings_array (const char *con_type) { - guint i, num; + const NMMetaSettingInfoEditor *setting_info; /* No connection type yet? Return settings for a generic connection * (just the "connection" setting), which always makes sense. */ if (!con_type) - return nmc_valid_connection_types[0].settings; - - num = G_N_ELEMENTS (nmc_valid_connection_types); - for (i = 0; i < num; i++) { - if (nm_streq0 (con_type, nmc_valid_connection_types[i].name)) - return nmc_valid_connection_types[i].settings; - } + return nm_meta_setting_info_valid_parts_default; + setting_info = nm_meta_setting_info_editor_find_by_name (con_type, FALSE); + if (setting_info) + return setting_info->valid_parts ?: NM_PTRARRAY_EMPTY (const NMMetaSettingValidPartItem *); return NULL; } @@ -3143,14 +2860,13 @@ get_valid_settings_array (const char *con_type) * Returns: list of property.arg elements */ static char * -get_valid_properties_string (const NameItem *array, - const NameItem *array_slv, +get_valid_properties_string (const NMMetaSettingValidPartItem *const*array, + const NMMetaSettingValidPartItem *const*array_slv, char modifier, const char *prefix, const char *postfix) { - const NameItem *iter = array; - const NMMetaSettingInfoEditor *setting_info; + const NMMetaSettingValidPartItem *const*iter = array; const char *prop_name = NULL; GString *str; int i, j; @@ -3161,56 +2877,51 @@ get_valid_properties_string (const NameItem *array, str = g_string_sized_new (1024); for (i = 0; i < 2; i++, iter = array_slv) { - while (!full_match && iter && iter->name) { - if ( !(g_str_has_prefix (iter->name, prefix)) - && (!(iter->alias) || !g_str_has_prefix (iter->alias, prefix))) { - iter++; + for(; !full_match && iter && *iter; iter++) { + const NMMetaSettingInfoEditor *setting_info = (*iter)->setting_info; + + if ( !(g_str_has_prefix (setting_info->general->setting_name, prefix)) + && ( !setting_info->alias + || !g_str_has_prefix (setting_info->alias, prefix))) { continue; } + /* If postix (so prefix is terminated by a dot), check * that prefix is not ambiguous */ if (postfix) { /* If we have a perfect match, no need to look for others * prefix and no check on ambiguity should be performed. * Moreover, erase previous matches from output string */ - if ( nm_streq (prefix, iter->name) - || nm_streq0 (prefix, iter->alias)) { + if ( nm_streq (prefix, setting_info->general->setting_name) + || nm_streq0 (prefix, setting_info->alias)) { g_string_erase (str, 0, -1); full_match = TRUE; - } else if (prop_name) { + } else if (prop_name) return g_string_free (str, TRUE); - } prop_name = prefix; - } else { - prop_name = iter->name; - } + } else + prop_name = setting_info->general->setting_name; /* Search the array with the arguments of the current property */ - setting_info = nm_meta_setting_info_editor_find_by_name (iter->name); - j = 0; - while (TRUE) { + for (j = 0; j < setting_info->properties_num; j++) { gchar *new; const char *arg_name; - if (j + 1 >= setting_info->properties_num) - break; - arg_name = setting_info->properties[j + 1].property_name; + arg_name = setting_info->properties[j].property_name; /* If required, expand the alias too */ - if (!postfix && iter->alias) { + if (!postfix && setting_info->alias) { if (modifier) g_string_append_c (str, modifier); new = g_strdup_printf ("%s.%s\n", - iter->alias, + setting_info->alias, arg_name); g_string_append (str, new); g_free (new); } - if (postfix && !g_str_has_prefix (arg_name, postfix)) { - j++; + if (postfix && !g_str_has_prefix (arg_name, postfix)) continue; - } if (modifier) g_string_append_c (str, modifier); @@ -3219,9 +2930,7 @@ get_valid_properties_string (const NameItem *array, arg_name); g_string_append (str, new); g_free (new); - j++; } - iter++; } } return g_string_free (str, FALSE); @@ -3237,9 +2946,9 @@ get_valid_properties_string (const NameItem *array, * The returned string must not be freed. */ static const char * -check_valid_name (const char *val, const NameItem *array, const NameItem *array_slv, GError **error) +check_valid_name (const char *val, const NMMetaSettingValidPartItem *const*array, const NMMetaSettingValidPartItem *const*array_slv, GError **error) { - const NameItem *iter; + const NMMetaSettingValidPartItem *const*iter; gs_unref_ptrarray GPtrArray *tmp_arr = NULL; const char *str; GError *tmp_err = NULL; @@ -3251,11 +2960,12 @@ check_valid_name (const char *val, const NameItem *array, const NameItem *array_ tmp_arr = g_ptr_array_sized_new (32); iter = array; for (i = 0; i < 2; i++, iter = array_slv) { - while (iter && iter->name) { - g_ptr_array_add (tmp_arr, (gpointer) iter->name); - if (iter->alias) - g_ptr_array_add (tmp_arr, (gpointer) iter->alias); - iter++; + for (; iter && *iter; iter++) { + const NMMetaSettingInfoEditor *setting_info = (*iter)->setting_info; + + g_ptr_array_add (tmp_arr, (gpointer) setting_info->general->setting_name); + if (setting_info->alias) + g_ptr_array_add (tmp_arr, (gpointer) setting_info->alias); } } g_ptr_array_add (tmp_arr, (gpointer) NULL); @@ -3267,10 +2977,10 @@ check_valid_name (const char *val, const NameItem *array, const NameItem *array_ g_propagate_error (error, tmp_err); else { /* We want to handle aliases, so construct own error message */ - char *err_str = get_valid_options_string (array, array_slv); + gs_free char *err_str = NULL; + err_str = Get_valid_options_string (array, array_slv); g_set_error (error, 1, 0, _("'%s' not among [%s]"), val, err_str); - g_free (err_str); g_clear_error (&tmp_err); } return NULL; @@ -3279,12 +2989,13 @@ check_valid_name (const char *val, const NameItem *array, const NameItem *array_ /* Return a pointer to the found string in passed 'array' */ iter = array; for (i = 0; i < 2; i++, iter = array_slv) { - while (iter && iter->name) { - if ( nm_streq (iter->name, str) - || nm_streq0 (iter->alias, str)) { - return iter->name; + for (; iter && *iter; iter++) { + const NMMetaSettingInfoEditor *setting_info = (*iter)->setting_info; + + if ( nm_streq (setting_info->general->setting_name, str) + || nm_streq0 (setting_info->alias, str)) { + return setting_info->general->setting_name; } - iter++; } } @@ -3293,44 +3004,82 @@ check_valid_name (const char *val, const NameItem *array, const NameItem *array_ return NULL; } +static const char * +check_valid_name_toplevel (const char *val, GError **error) +{ + gs_unref_ptrarray GPtrArray *tmp_arr = NULL; + const char *str; + GError *tmp_err = NULL; + int i; + const NMMetaSettingInfoEditor *setting_info; + + /* Create a temporary array that can be used in nmc_string_is_valid() */ + tmp_arr = g_ptr_array_sized_new (32); + for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++) { + setting_info = &nm_meta_setting_infos_editor[i]; + g_ptr_array_add (tmp_arr, (gpointer) setting_info->general->setting_name); + if (setting_info->alias) + g_ptr_array_add (tmp_arr, (gpointer) setting_info->alias); + } + g_ptr_array_add (tmp_arr, (gpointer) NULL); + + /* Check string validity */ + str = nmc_string_is_valid (val, (const char **) tmp_arr->pdata, &tmp_err); + if (!str) { + if (tmp_err->code == 1) + g_propagate_error (error, tmp_err); + else { + /* We want to handle aliases, so construct own error message */ + char *err_str = get_valid_options_string_toplevel (); + + g_set_error (error, 1, 0, _("'%s' not among [%s]"), val, err_str); + g_free (err_str); + g_clear_error (&tmp_err); + } + return NULL; + } + + setting_info = nm_meta_setting_info_editor_find_by_name (str, TRUE); + if (setting_info) + return setting_info->general->setting_name; + + /* We should not really come here */ + g_set_error (error, 1, 0, _("Unknown error")); + return NULL; +} + static gboolean is_setting_mandatory (NMConnection *connection, NMSetting *setting) { NMSettingConnection *s_con; const char *c_type; - const NameItem *item; + const NMMetaSettingValidPartItem *const*item; const char *name; const char *s_type; - char *slv_type; + guint i; s_con = nm_connection_get_setting_connection (connection); g_assert (s_con); c_type = nm_setting_connection_get_connection_type (s_con); + s_type = nm_setting_connection_get_slave_type (s_con); name = nm_setting_get_name (setting); - item = get_valid_settings_array (c_type); - while (item && item->name) { - if (!strcmp (name, item->name)) - return item->mandatory; - item++; - } - - /* Let's give a try to parameters related to slave type */ - s_type = nm_setting_connection_get_slave_type (s_con); - slv_type = g_strdup_printf ("%s-slave", s_type ? s_type : "no"); - item = get_valid_settings_array (slv_type); - g_free (slv_type); - while (item && item->name) { - if (!strcmp (name, item->name)) - return item->mandatory; - item++; + for (i = 0; i < 2; i++) { + if (i == 0) + item = get_valid_settings_array (c_type); + else + item = nm_meta_setting_info_valid_parts_for_slave_type (s_type, NULL); + for (; item && *item; item++) { + if (!strcmp (name, (*item)->setting_info->general->setting_name)) + return (*item)->mandatory; + } } return FALSE; } -/*----------------------------------------------------------------------------*/ +/*****************************************************************************/ static const char * _strip_master_prefix (const char *master, const char *(**func)(NMConnection *)) @@ -3440,8 +3189,6 @@ normalized_master_for_slave (const GPtrArray *connections, #define WORD_YES "yes" #define WORD_NO "no" -#define WORD_LOC_YES _("yes") -#define WORD_LOC_NO _("no") static const char * prompt_yes_no (gboolean default_yes, char *delim) { @@ -3451,14 +3198,14 @@ prompt_yes_no (gboolean default_yes, char *delim) delim = ""; snprintf (prompt, sizeof (prompt), "(%s/%s) [%s]%s ", - WORD_LOC_YES, WORD_LOC_NO, - default_yes ? WORD_LOC_YES : WORD_LOC_NO, delim); + WORD_YES, WORD_NO, + default_yes ? WORD_YES : WORD_NO, delim); return prompt; } static NMSetting * -is_setting_valid (NMConnection *connection, const NameItem *valid_settings_main, const NameItem *valid_settings_slave, char *setting) +is_setting_valid (NMConnection *connection, const NMMetaSettingValidPartItem *const*valid_settings_main, const NMMetaSettingValidPartItem *const*valid_settings_slave, char *setting) { const char *setting_name; @@ -3531,9 +3278,106 @@ set_default_interface_name (NmCli *nmc, NMSettingConnection *s_con) g_free (ifname); } -/*----------------------------------------------------------------------------*/ +/*****************************************************************************/ -static OptionInfo option_info[]; +static PropertyInfFlags +_dynamic_options_set (const NMMetaAbstractInfo *abstract_info, + PropertyInfFlags mask, PropertyInfFlags set) +{ + static GHashTable *cache = NULL; + gpointer p; + PropertyInfFlags v, v2; + + if (G_UNLIKELY (!cache)) + cache = g_hash_table_new (NULL, NULL); + + if (g_hash_table_lookup_extended (cache, (gpointer) abstract_info, NULL, &p)) + v = GPOINTER_TO_UINT (p); + else + v = 0; + + v2 = (v & ~mask) | (mask & set); + if (v != v2) + g_hash_table_insert (cache, (gpointer) abstract_info, GUINT_TO_POINTER (v2)); + + return v2; +} + +static PropertyInfFlags +_dynamic_options_get (const NMMetaAbstractInfo *abstract_info) +{ + return _dynamic_options_set (abstract_info, 0, 0); +} + +/*****************************************************************************/ + +static gboolean +_meta_property_needs_bond_hack (const NMMetaPropertyInfo *property_info) +{ + /* hack: the bond property data is handled special and not generically. + * Eventually, get rid of explicitly checking whether we handle a bond. */ + if (!property_info) + g_return_val_if_reached (FALSE); + return property_info->property_typ_data + && property_info->property_typ_data->subtype.nested.data == &nm_meta_property_typ_data_bond; + +} + +static char ** +_meta_abstract_complete (const NMMetaAbstractInfo *abstract_info, const char *text) +{ + const char *const*values; + char **values_to_free = NULL; + const NMMetaOperationContext ctx = { + .connection = nmc_tab_completion.connection, + }; + + values = nm_meta_abstract_info_complete (abstract_info, + nmc_meta_environment, + nmc_meta_environment_arg, + &ctx, + text, + &values_to_free); + if (values) + return values_to_free ?: g_strdupv ((char **) values); + return NULL; +} + +static void +_meta_abstract_get (const NMMetaAbstractInfo *abstract_info, + const NMMetaSettingInfoEditor **out_setting_info, + const char **out_setting_name, + const char **out_property_name, + const char **out_option, + NMMetaPropertyInfFlags *out_inf_flags, + const char **out_prompt, + const char **out_def_hint) +{ + /* _meta_property_needs_bond_hack () */ + if (abstract_info->meta_type == &nm_meta_type_nested_property_info) { + const NMMetaNestedPropertyTypeInfo *info = (const NMMetaNestedPropertyTypeInfo *) abstract_info; + + NM_SET_OUT (out_setting_info, info->parent_info->setting_info); + NM_SET_OUT (out_setting_name, info->parent_info->setting_info->general->setting_name); + NM_SET_OUT (out_property_name, info->parent_info->property_name); + NM_SET_OUT (out_option, info->field_name); + NM_SET_OUT (out_inf_flags, info->inf_flags); + NM_SET_OUT (out_prompt, info->prompt); + NM_SET_OUT (out_def_hint, info->def_hint); + } else { + const NMMetaPropertyInfo *info = (const NMMetaPropertyInfo *) abstract_info; + + NM_SET_OUT (out_setting_info, info->setting_info); + NM_SET_OUT (out_setting_name, info->setting_info->general->setting_name); + NM_SET_OUT (out_property_name, info->property_name); + NM_SET_OUT (out_option, info->property_alias); + NM_SET_OUT (out_inf_flags, info->inf_flags); + NM_SET_OUT (out_prompt, info->prompt); + NM_SET_OUT (out_def_hint, info->def_hint); + } +} + +static const OptionInfo *_meta_abstract_get_option_info (const NMMetaAbstractInfo *abstract_info); /* * Mark options in option_info as relevant. @@ -3542,17 +3386,34 @@ static OptionInfo option_info[]; static void enable_options (const gchar *setting_name, const gchar *property, const gchar * const *opts) { - OptionInfo *candidate; + const NMMetaPropertyInfo *property_info; - for (candidate = option_info; candidate->setting_name; candidate++) { - if ( strcmp (candidate->setting_name, setting_name) == 0 - && strcmp (candidate->property, property) == 0 - && (candidate->flags & OPTION_DONT_ASK) - && candidate->option - && g_strv_contains (opts, candidate->option)) { - candidate->flags |= OPTION_ENABLED; + property_info = nm_meta_property_info_find_by_name (setting_name, property); + + if (!property_info) + g_return_if_reached (); + + if (_meta_property_needs_bond_hack (property_info)) { + guint i; + + for (i = 0; i < nm_meta_property_typ_data_bond.nested_len; i++) { + const NMMetaNestedPropertyTypeInfo *bi = &nm_meta_property_typ_data_bond.nested[i]; + + if ( bi->inf_flags & NM_META_PROPERTY_INF_FLAG_DONT_ASK + && bi->field_name + && g_strv_contains (opts, bi->field_name)) + _dynamic_options_set ((const NMMetaAbstractInfo *) bi, PROPERTY_INF_FLAG_ENABLED, PROPERTY_INF_FLAG_ENABLED); } + return; } + + if (!property_info->is_cli_option) + g_return_if_reached (); + + if ( property_info->inf_flags & NM_META_PROPERTY_INF_FLAG_DONT_ASK + && property_info->property_alias + && g_strv_contains (opts, property_info->property_alias)) + _dynamic_options_set ((const NMMetaAbstractInfo *) property_info, PROPERTY_INF_FLAG_ENABLED, PROPERTY_INF_FLAG_ENABLED); } /* @@ -3563,12 +3424,47 @@ enable_options (const gchar *setting_name, const gchar *property, const gchar * static void disable_options (const gchar *setting_name, const gchar *property) { - OptionInfo *candidate; + const NMMetaPropertyInfo *property_infos_local[2]; + const NMMetaPropertyInfo *const*property_infos; + guint p; - for (candidate = option_info; candidate->setting_name; candidate++) { - if ( strcmp (candidate->setting_name, setting_name) == 0 - && (!property || strcmp (candidate->property, property) == 0)) - candidate->flags |= OPTION_DISABLED; + if (property) { + const NMMetaPropertyInfo *pi; + + pi = nm_meta_property_info_find_by_name (setting_name, property); + if (!pi) + g_return_if_reached (); + if ( !_meta_property_needs_bond_hack (pi) + && !pi->is_cli_option) + return; + property_infos_local[0] = pi; + property_infos_local[1] = NULL; + property_infos = property_infos_local; + } else { + const NMMetaSettingInfoEditor *setting_info; + + setting_info = nm_meta_setting_info_editor_find_by_name (setting_name, FALSE); + if (!setting_info) + g_return_if_reached (); + property_infos = nm_property_infos_for_setting_type (setting_info->general->meta_type); + } + + for (p = 0; property_infos[p]; p++) { + const NMMetaPropertyInfo *property_info = property_infos[p]; + + if (_meta_property_needs_bond_hack (property_info)) { + guint i; + + for (i = 0; i < nm_meta_property_typ_data_bond.nested_len; i++) { + const NMMetaNestedPropertyTypeInfo *bi = &nm_meta_property_typ_data_bond.nested[i]; + + _dynamic_options_set ((const NMMetaAbstractInfo *) bi, PROPERTY_INF_FLAG_DISABLED, PROPERTY_INF_FLAG_DISABLED); + } + nm_assert (p == 0 && !property_infos[1]); + } else { + if (property_info->is_cli_option) + _dynamic_options_set ((const NMMetaAbstractInfo *) property_info, PROPERTY_INF_FLAG_DISABLED, PROPERTY_INF_FLAG_DISABLED); + } } } @@ -3580,11 +3476,29 @@ disable_options (const gchar *setting_name, const gchar *property) static void reset_options (void) { - OptionInfo *candidate; + NMMetaSettingType s; - for (candidate = option_info; candidate->setting_name; candidate++) { - candidate->flags &= ~OPTION_DISABLED; - candidate->flags &= ~OPTION_ENABLED; + for (s = 0; s < _NM_META_SETTING_TYPE_NUM; s++) { + const NMMetaPropertyInfo *const*property_infos; + guint p; + + property_infos = nm_property_infos_for_setting_type (s); + for (p = 0; property_infos[p]; p++) { + const NMMetaPropertyInfo *property_info = property_infos[p]; + + if (_meta_property_needs_bond_hack (property_info)) { + guint i; + + for (i = 0; i < nm_meta_property_typ_data_bond.nested_len; i++) { + const NMMetaNestedPropertyTypeInfo *bi = &nm_meta_property_typ_data_bond.nested[i]; + + _dynamic_options_set ((const NMMetaAbstractInfo *) bi, PROPERTY_INF_FLAG_ALL, 0); + } + } else { + if (property_info->is_cli_option) + _dynamic_options_set ((const NMMetaAbstractInfo *) property_info, PROPERTY_INF_FLAG_ALL, 0); + } + } } } @@ -3597,17 +3511,12 @@ set_property (NMConnection *connection, NMSetting *setting; GError *local = NULL; + g_assert (setting_name && setting_name[0]); + setting = nm_connection_get_setting_by_name (connection, setting_name); if (!setting) { - setting = nmc_setting_new_for_name (setting_name); - if (!setting) { - /* This should really not happen */ - g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_UNKNOWN, - _("Error: don't know how to create '%s' setting."), - setting_name); - return FALSE; - } - nmc_setting_custom_init (setting); + setting = nm_meta_setting_info_editor_new_setting (nm_meta_setting_info_editor_find_by_name (setting_name, FALSE), + NM_META_ACCESSOR_SETTING_INIT_TYPE_CLI); nm_connection_add_setting (connection, setting); } @@ -3666,17 +3575,25 @@ set_property (NMConnection *connection, } static gboolean -set_option (NmCli *nmc, NMConnection *connection, OptionInfo *option, const gchar *value, GError **error) +set_option (NmCli *nmc, NMConnection *connection, const NMMetaAbstractInfo *abstract_info, const gchar *value, GError **error) { - option->flags |= OPTION_DISABLED; - if (option->check_and_set) { + const char *setting_name, *property_name, *option_name; + NMMetaPropertyInfFlags inf_flags; + const OptionInfo *option; + + option = _meta_abstract_get_option_info (abstract_info); + + _dynamic_options_set (abstract_info, PROPERTY_INF_FLAG_DISABLED, PROPERTY_INF_FLAG_DISABLED); + + _meta_abstract_get (abstract_info, NULL, &setting_name, &property_name, &option_name, &inf_flags, NULL, NULL); + if (option && option->check_and_set) { return option->check_and_set (nmc, connection, option, value, error); } else if (value) { - return set_property (connection, option->setting_name, option->property, - value, option->flags & OPTION_MULTI ? '+' : '\0', error); - } else if (option->flags & OPTION_REQD) { + return set_property (connection, setting_name, property_name, + value, inf_flags & NM_META_PROPERTY_INF_FLAG_MULTI ? '+' : '\0', error); + } else if (inf_flags & NM_META_PROPERTY_INF_FLAG_REQD) { g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, - _("Error: '%s' is mandatory."), option->option); + _("Error: '%s' is mandatory."), option_name); return FALSE; } @@ -3688,10 +3605,9 @@ set_option (NmCli *nmc, NMConnection *connection, OptionInfo *option, const gcha * and slave type. */ static gboolean -con_settings (NMConnection *connection, const NameItem **type_settings, const NameItem **slv_settings, GError **error) +con_settings (NMConnection *connection, const NMMetaSettingValidPartItem *const**type_settings, const NMMetaSettingValidPartItem *const**slv_settings, GError **error) { const char *con_type; - gs_free char *slv_type = NULL; NMSettingConnection *s_con; g_return_val_if_fail (type_settings, FALSE); @@ -3701,18 +3617,11 @@ con_settings (NMConnection *connection, const NameItem **type_settings, const Na g_assert (s_con); con_type = nm_setting_connection_get_slave_type (s_con); - if (!con_type) - con_type = "no"; - slv_type = g_strdup_printf ("%s-slave", con_type); - if (slv_type) { - *slv_settings = get_valid_settings_array (slv_type); - if (!*slv_settings) { - g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, - _("Error: invalid slave type; %s."), slv_type); - return FALSE; - } - } else { - *slv_settings = NULL; + *slv_settings = nm_meta_setting_info_valid_parts_for_slave_type (con_type, NULL); + if (!*slv_settings) { + g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, + _("Error: invalid slave type; %s."), con_type); + return FALSE; } con_type = nm_setting_connection_get_connection_type (s_con); @@ -3733,60 +3642,27 @@ con_settings (NMConnection *connection, const NameItem **type_settings, const Na * it's possible that a type is aready set). */ static void -ensure_settings (NMConnection *connection, const NameItem *item) +ensure_settings (NMConnection *connection, const NMMetaSettingValidPartItem *const*item) { - const NameItem *setting_item; NMSetting *setting; - for (setting_item = item; setting_item->name; setting_item++) { - if (!setting_item->mandatory) + for (; item && *item; item++) { + if (!(*item)->mandatory) continue; - if (nm_connection_get_setting_by_name (connection, setting_item->name)) + if (nm_connection_get_setting_by_name (connection, (*item)->setting_info->general->setting_name)) continue; - setting = nmc_setting_new_for_name (setting_item->name); - if (setting) { - nmc_setting_custom_init (setting); - nm_connection_add_setting (connection, setting); - } + setting = nm_meta_setting_info_editor_new_setting ((*item)->setting_info, + NM_META_ACCESSOR_SETTING_INIT_TYPE_CLI); + nm_connection_add_setting (connection, setting); } } -/*----------------------------------------------------------------------------*/ - -static char * -gen_func_slave_type (const char *text, int state) -{ - const char *words[] = { "bond", "team", "bridge", NULL }; - return nmc_rl_gen_func_basic (text, state, words); -} - -static char * -gen_func_vpn_types (const char *text, int state) -{ - gs_strfreev char **plugin_names = NULL; - - plugin_names = nm_vpn_plugin_info_list_get_service_types (nm_vpn_get_plugin_infos (), FALSE, TRUE); - return nmc_rl_gen_func_basic (text, state, (const char **) plugin_names); -} +/*****************************************************************************/ static char * gen_func_bool_values_l10n (const char *text, int state) { - const char *words[] = { WORD_LOC_YES, WORD_LOC_NO, NULL }; - return nmc_rl_gen_func_basic (text, state, words); -} - -static char * -gen_func_wifi_mode (const char *text, int state) -{ - const char *words[] = { "infrastructure", "ap", "adhoc", NULL }; - return nmc_rl_gen_func_basic (text, state, words); -} - -static char * -gen_func_ib_type (const char *text, int state) -{ - const char *words[] = { "datagram", "connected", NULL }; + const char *words[] = { WORD_YES, WORD_NO, NULL }; return nmc_rl_gen_func_basic (text, state, words); } @@ -3817,117 +3693,17 @@ gen_func_bond_lacp_rate (const char *text, int state) return nmc_rl_gen_func_basic (text, state, words); } -static char * -gen_func_adsl_proto (const char *text, int state) -{ - const char *words[] = { "pppoe", "pppoa", "ipoatm", NULL }; - return nmc_rl_gen_func_basic (text, state, words); -} - -static char * -gen_func_adsl_encap (const char *text, int state) -{ - const char *words[] = { "vcmux", "llc", NULL }; - return nmc_rl_gen_func_basic (text, state, words); -} - -static char * -gen_func_tun_mode (const char *text, int state) -{ - const char *words[] = { "tun", "tap", NULL }; - return nmc_rl_gen_func_basic (text, state, words); -} - -static char * -gen_func_ip_tunnel_mode (const char *text, int state) -{ - gs_free const char **words = NULL; - - words = nm_utils_enum_get_values (nm_ip_tunnel_mode_get_type (), - NM_IP_TUNNEL_MODE_UNKNOWN + 1, - G_MAXINT); - return nmc_rl_gen_func_basic (text, state, words); -} - -static char * -gen_func_macsec_mode (const char *text, int state) -{ - gs_free const char **words = NULL; - - words = nm_utils_enum_get_values (nm_setting_macsec_mode_get_type (), - G_MININT, - G_MAXINT); - return nmc_rl_gen_func_basic (text, state, words); -} - -static char * -gen_func_macvlan_mode (const char *text, int state) -{ - gs_free const char **words = NULL; - - words = nm_utils_enum_get_values (nm_setting_macvlan_mode_get_type(), - NM_SETTING_MACVLAN_MODE_UNKNOWN + 1, - G_MAXINT); - return nmc_rl_gen_func_basic (text, state, words); -} - -static char * -gen_func_proxy_method (const char *text, int state) -{ - gs_free const char **words = NULL; - - words = nm_utils_enum_get_values (nm_setting_proxy_method_get_type (), - G_MININT, - G_MAXINT); - return nmc_rl_gen_func_basic (text, state, words); -} - -static char * -gen_func_master_ifnames (const char *text, int state) -{ - int i; - GPtrArray *ifnames; - char *ret; - NMConnection *con; - NMSettingConnection *s_con; - const char *con_type, *ifname; - const GPtrArray *connections; - - connections = nm_client_get_connections (nm_cli.client); - - /* Disable appending space after completion */ - rl_completion_append_character = '\0'; - - ifnames = g_ptr_array_sized_new (20); - for (i = 0; i < connections->len; i++) { - con = NM_CONNECTION (connections->pdata[i]); - s_con = nm_connection_get_setting_connection (con); - g_assert (s_con); - con_type = nm_setting_connection_get_connection_type (s_con); - if (g_strcmp0 (con_type, nmc_tab_completion.con_type) != 0) - continue; - ifname = nm_connection_get_interface_name (con); - g_ptr_array_add (ifnames, (gpointer) ifname); - } - g_ptr_array_add (ifnames, (gpointer) NULL); - - ret = nmc_rl_gen_func_basic (text, state, (const char **) ifnames->pdata); - - g_ptr_array_free (ifnames, TRUE); - return ret; -} - - -/*----------------------------------------------------------------------------*/ +/*****************************************************************************/ static gboolean -set_connection_type (NmCli *nmc, NMConnection *con, OptionInfo *option, const char *value, GError **error) +set_connection_type (NmCli *nmc, NMConnection *con, const OptionInfo *option, const char *value, GError **error) { - const NameItem *type_settings, *slv_settings; + const NMMetaSettingValidPartItem *const*type_settings; + const NMMetaSettingValidPartItem *const*slv_settings; GError *local = NULL; const gchar *master[] = { "master", NULL }; - value = check_valid_name (value, nmc_valid_connection_types, NULL, &local); + value = check_valid_name_toplevel (value, &local); if (!value) { g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, _("Error: bad connection type: %s."), local->message); @@ -3970,7 +3746,7 @@ set_connection_type (NmCli *nmc, NMConnection *con, OptionInfo *option, const ch NM_SETTING_CONNECTION_INTERFACE_NAME); } - if (!set_property (con, option->setting_name, option->property, value, '\0', error)) + if (!set_property (con, option->setting_info->general->setting_name, option->property, value, '\0', error)) return FALSE; if (!con_settings (con, &type_settings, &slv_settings, error)) @@ -3983,7 +3759,7 @@ set_connection_type (NmCli *nmc, NMConnection *con, OptionInfo *option, const ch } static gboolean -set_connection_iface (NmCli *nmc, NMConnection *con, OptionInfo *option, const char *value, GError **error) +set_connection_iface (NmCli *nmc, NMConnection *con, const OptionInfo *option, const char *value, GError **error) { GError *tmp_error = NULL; @@ -3999,11 +3775,11 @@ set_connection_iface (NmCli *nmc, NMConnection *con, OptionInfo *option, const c } } - return set_property (con, option->setting_name, option->property, value, '\0', error); + return set_property (con, option->setting_info->general->setting_name, option->property, value, '\0', error); } static gboolean -set_connection_master (NmCli *nmc, NMConnection *con, OptionInfo *option, const char *value, GError **error) +set_connection_master (NmCli *nmc, NMConnection *con, const OptionInfo *option, const char *value, GError **error) { const GPtrArray *connections; NMSettingConnection *s_con; @@ -4028,11 +3804,11 @@ set_connection_master (NmCli *nmc, NMConnection *con, OptionInfo *option, const return FALSE; } - return set_property (con, option->setting_name, option->property, value, '\0', error); + return set_property (con, option->setting_info->general->setting_name, option->property, value, '\0', error); } static gboolean -set_bond_option (NmCli *nmc, NMConnection *con, OptionInfo *option, const char *value, GError **error) +set_bond_option (NmCli *nmc, NMConnection *con, const OptionInfo *option, const char *value, GError **error) { NMSettingBond *s_bond; gboolean success; @@ -4081,7 +3857,7 @@ set_bond_option (NmCli *nmc, NMConnection *con, OptionInfo *option, const char * } static gboolean -set_bond_monitoring_mode (NmCli *nmc, NMConnection *con, OptionInfo *option, const char *value, GError **error) +set_bond_monitoring_mode (NmCli *nmc, NMConnection *con, const OptionInfo *option, const char *value, GError **error) { NMSettingBond *s_bond; gs_free gchar *monitor_mode = NULL; @@ -4095,17 +3871,17 @@ set_bond_monitoring_mode (NmCli *nmc, NMConnection *con, OptionInfo *option, con monitor_mode = g_strdup (value); g_strstrip (monitor_mode); } else { - monitor_mode = g_strdup (WORD_MIIMON); + monitor_mode = g_strdup (NM_META_TEXT_WORD_MIIMON); } - if (matches (monitor_mode, WORD_MIIMON)) + if (matches (monitor_mode, NM_META_TEXT_WORD_MIIMON)) enable_options (NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS, miimon_opts); - else if (matches (monitor_mode, WORD_ARP)) + else if (matches (monitor_mode, NM_META_TEXT_WORD_ARP)) enable_options (NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS, arp_opts); else { g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, _("Error: '%s' is not a valid monitoring mode; use '%s' or '%s'.\n"), - monitor_mode, WORD_MIIMON, WORD_ARP); + monitor_mode, NM_META_TEXT_WORD_MIIMON, NM_META_TEXT_WORD_ARP); return FALSE; } @@ -4113,7 +3889,7 @@ set_bond_monitoring_mode (NmCli *nmc, NMConnection *con, OptionInfo *option, con } static gboolean -set_bluetooth_type (NmCli *nmc, NMConnection *con, OptionInfo *option, const char *value, GError **error) +set_bluetooth_type (NmCli *nmc, NMConnection *con, const OptionInfo *option, const char *value, GError **error) { NMSetting *setting; @@ -4124,8 +3900,8 @@ set_bluetooth_type (NmCli *nmc, NMConnection *con, OptionInfo *option, const cha if ( !strcmp (value, NM_SETTING_BLUETOOTH_TYPE_DUN) || !strcmp (value, NM_SETTING_BLUETOOTH_TYPE_DUN"-gsm")) { value = NM_SETTING_BLUETOOTH_TYPE_DUN; - setting = nm_setting_gsm_new (); - nmc_setting_custom_init (setting); + setting = nm_meta_setting_info_editor_new_setting (&nm_meta_setting_infos_editor[NM_META_SETTING_TYPE_GSM], + NM_META_ACCESSOR_SETTING_INIT_TYPE_CLI); nm_connection_add_setting (con, setting); } else if (!strcmp (value, NM_SETTING_BLUETOOTH_TYPE_DUN"-cdma")) { value = NM_SETTING_BLUETOOTH_TYPE_DUN; @@ -4141,22 +3917,11 @@ set_bluetooth_type (NmCli *nmc, NMConnection *con, OptionInfo *option, const cha return FALSE; } - return set_property (con, option->setting_name, option->property, value, '\0', error); + return set_property (con, option->setting_info->general->setting_name, option->property, value, '\0', error); } static gboolean -set_yes_no (NmCli *nmc, NMConnection *con, OptionInfo *option, const char *value, GError **error) -{ - if (g_strcmp0 (value, _(WORD_LOC_YES))) - value = WORD_YES; - if (g_strcmp0 (value, _(WORD_LOC_NO))) - value = WORD_NO; - - return set_property (con, option->setting_name, option->property, value, '\0', error); -} - -static gboolean -set_ip4_address (NmCli *nmc, NMConnection *con, OptionInfo *option, const char *value, GError **error) +set_ip4_address (NmCli *nmc, NMConnection *con, const OptionInfo *option, const char *value, GError **error) { NMSettingIPConfig *s_ip4; @@ -4171,12 +3936,12 @@ set_ip4_address (NmCli *nmc, NMConnection *con, OptionInfo *option, const char * NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL, NULL); } - return set_property (con, option->setting_name, option->property, value, - option->flags & OPTION_MULTI ? '+' : '\0', error); + return set_property (con, option->setting_info->general->setting_name, option->property, value, + '+', error); } static gboolean -set_ip6_address (NmCli *nmc, NMConnection *con, OptionInfo *option, const char *value, GError **error) +set_ip6_address (NmCli *nmc, NMConnection *con, const OptionInfo *option, const char *value, GError **error) { NMSettingIPConfig *s_ip6; @@ -4191,187 +3956,97 @@ set_ip6_address (NmCli *nmc, NMConnection *con, OptionInfo *option, const char * NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_MANUAL, NULL); } - return set_property (con, option->setting_name, option->property, value, - option->flags & OPTION_MULTI ? '+' : '\0', error); + return set_property (con, option->setting_info->general->setting_name, option->property, value, + '+', error); } +/*****************************************************************************/ -/*----------------------------------------------------------------------------*/ +static const OptionInfo * +_meta_abstract_get_option_info (const NMMetaAbstractInfo *abstract_info) +{ + static const OptionInfo option_info[] = { +#define OPTION_INFO(name, property_name_, property_alias_, check_and_set_, generator_func_) \ + { \ + .setting_info = &nm_meta_setting_infos_editor[NM_META_SETTING_TYPE_##name], \ + .property = property_name_, \ + .option = property_alias_, \ + .check_and_set = check_and_set_, \ + .generator_func = generator_func_, \ + } + OPTION_INFO (CONNECTION, NM_SETTING_CONNECTION_TYPE, "type", set_connection_type, NULL), + OPTION_INFO (CONNECTION, NM_SETTING_CONNECTION_INTERFACE_NAME, "ifname", set_connection_iface, NULL), + OPTION_INFO (CONNECTION, NM_SETTING_CONNECTION_MASTER, "master", set_connection_master, NULL), + OPTION_INFO (BLUETOOTH, NM_SETTING_BLUETOOTH_TYPE, "bt-type", set_bluetooth_type, gen_func_bt_type), + OPTION_INFO (BOND, NM_SETTING_BOND_OPTIONS, "mode", set_bond_option, gen_func_bond_mode), + OPTION_INFO (BOND, NM_SETTING_BOND_OPTIONS, "primary", set_bond_option, nmc_rl_gen_func_ifnames), + OPTION_INFO (BOND, NM_SETTING_BOND_OPTIONS, NULL, set_bond_monitoring_mode, gen_func_bond_mon_mode), + OPTION_INFO (BOND, NM_SETTING_BOND_OPTIONS, "miimon", set_bond_option, NULL), + OPTION_INFO (BOND, NM_SETTING_BOND_OPTIONS, "downdelay", set_bond_option, NULL), + OPTION_INFO (BOND, NM_SETTING_BOND_OPTIONS, "updelay", set_bond_option, NULL), + OPTION_INFO (BOND, NM_SETTING_BOND_OPTIONS, "arp-interval", set_bond_option, NULL), + OPTION_INFO (BOND, NM_SETTING_BOND_OPTIONS, "arp-ip-target", set_bond_option, NULL), + OPTION_INFO (BOND, NM_SETTING_BOND_OPTIONS, "lacp-rate", set_bond_option, gen_func_bond_lacp_rate), + OPTION_INFO (IP4_CONFIG, NM_SETTING_IP_CONFIG_ADDRESSES, "ip4", set_ip4_address, NULL), + OPTION_INFO (IP6_CONFIG, NM_SETTING_IP_CONFIG_ADDRESSES, "ip6", set_ip6_address, NULL), + { 0 }, + }; + const char *property_name, *option; + const NMMetaSettingInfoEditor *setting_info; + const OptionInfo *candidate; -static OptionInfo option_info[] = { - { NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_TYPE, "type", OPTION_REQD, PROMPT_CON_TYPE, NULL, - set_connection_type, gen_connection_types }, - { NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_ID, "con-name", OPTION_DONT_ASK, NULL, NULL, NULL, NULL }, - { NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_AUTOCONNECT, "autoconnect", OPTION_DONT_ASK, NULL, NULL, NULL, - gen_func_bool_values_l10n }, - { NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_INTERFACE_NAME, "ifname", OPTION_REQD, PROMPT_IFNAME, NULL, - set_connection_iface, nmc_rl_gen_func_ifnames }, - { NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_MASTER, "master", OPTION_DONT_ASK, PROMPT_MASTER, NULL, - set_connection_master, gen_func_master_ifnames }, - { NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_SLAVE_TYPE, "slave-type", OPTION_DONT_ASK, NULL, NULL, NULL, - gen_func_slave_type }, - { NM_SETTING_PPPOE_SETTING_NAME, NM_SETTING_PPPOE_USERNAME, "username", OPTION_REQD, N_("PPPoE username"), NULL, NULL, NULL }, - { NM_SETTING_PPPOE_SETTING_NAME, NM_SETTING_PPPOE_PASSWORD, "password", OPTION_NONE, N_("Password [none]"), NULL, NULL, NULL }, - { NM_SETTING_PPPOE_SETTING_NAME, NM_SETTING_PPPOE_SERVICE, "service", OPTION_NONE, N_("Service [none]"), NULL, NULL, NULL }, - { NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_MTU, "mtu", OPTION_NONE, N_("MTU [auto]"), NULL, NULL, NULL }, - { NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_MAC_ADDRESS, "mac", OPTION_NONE, N_("MAC [none]"), NULL, NULL, NULL }, - { NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_CLONED_MAC_ADDRESS, "cloned-mac", OPTION_NONE, N_("Cloned MAC [none]"), NULL, NULL, NULL }, - { NM_SETTING_INFINIBAND_SETTING_NAME, NM_SETTING_INFINIBAND_MTU, "mtu", OPTION_NONE, N_("MTU [auto]"), NULL, NULL, NULL }, - { NM_SETTING_INFINIBAND_SETTING_NAME, NM_SETTING_INFINIBAND_MAC_ADDRESS, "mac", OPTION_NONE, N_("MAC [none]"), NULL, NULL, NULL }, - { NM_SETTING_INFINIBAND_SETTING_NAME, NM_SETTING_INFINIBAND_TRANSPORT_MODE, "transport-mode", OPTION_NONE, PROMPT_IB_MODE, PROMPT_IB_MODE_CHOICES, - NULL, gen_func_ib_type }, - { NM_SETTING_INFINIBAND_SETTING_NAME, NM_SETTING_INFINIBAND_PARENT, "parent", OPTION_NONE, N_("Parent interface [none]"), NULL, NULL, NULL }, - { NM_SETTING_INFINIBAND_SETTING_NAME, NM_SETTING_INFINIBAND_P_KEY, "p-key", OPTION_NONE, N_("P_KEY [none]"), NULL, NULL, NULL }, - { NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_WIRELESS_SSID, "ssid", OPTION_REQD, N_("SSID"), NULL, NULL, NULL }, - { NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_WIRELESS_MODE, "mode", OPTION_NONE, PROMPT_WIFI_MODE, PROMPT_WIFI_MODE_CHOICES, - NULL, gen_func_wifi_mode }, - { NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_WIRELESS_MTU, "mtu", OPTION_NONE, N_("MTU [auto]"), NULL, NULL, NULL }, - { NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_WIRELESS_MAC_ADDRESS, "mac", OPTION_NONE, N_("MAC [none]"), NULL, NULL, NULL }, - { NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, "cloned-mac", OPTION_NONE, N_("Cloned MAC [none]"), NULL, NULL, NULL }, - { NM_SETTING_WIMAX_SETTING_NAME, NM_SETTING_WIMAX_NETWORK_NAME, "nsp", OPTION_REQD, N_("WiMAX NSP name"), NULL, NULL, NULL }, - { NM_SETTING_WIMAX_SETTING_NAME, NM_SETTING_WIMAX_MAC_ADDRESS, "mac", OPTION_NONE, N_("MAC [none]"), NULL, NULL, NULL }, - { NM_SETTING_GSM_SETTING_NAME, NM_SETTING_GSM_APN, "apn", OPTION_REQD, N_("APN"), NULL, NULL, NULL }, - { NM_SETTING_GSM_SETTING_NAME, NM_SETTING_GSM_USERNAME, "user", OPTION_NONE, N_("Username [none]"), NULL, NULL, NULL }, - { NM_SETTING_GSM_SETTING_NAME, NM_SETTING_GSM_PASSWORD, "password", OPTION_NONE, N_("Password [none]"), NULL, NULL, NULL }, - { NM_SETTING_CDMA_SETTING_NAME, NM_SETTING_CDMA_USERNAME, "user", OPTION_NONE, N_("Username [none]"), NULL, NULL, NULL }, - { NM_SETTING_CDMA_SETTING_NAME, NM_SETTING_CDMA_PASSWORD, "password", OPTION_NONE, N_("Password [none]"), NULL, NULL, NULL }, - { NM_SETTING_BLUETOOTH_SETTING_NAME, NM_SETTING_BLUETOOTH_BDADDR, "addr", OPTION_REQD, N_("Bluetooth device address"), NULL, NULL, NULL }, - { NM_SETTING_BLUETOOTH_SETTING_NAME, NM_SETTING_BLUETOOTH_TYPE, "bt-type", OPTION_NONE, PROMPT_BT_TYPE, PROMPT_BT_TYPE_CHOICES, - set_bluetooth_type, gen_func_bt_type }, - { NM_SETTING_VLAN_SETTING_NAME, NM_SETTING_VLAN_PARENT, "dev", OPTION_REQD, N_("VLAN parent device or connection UUID"), NULL, - NULL, nmc_rl_gen_func_ifnames }, - { NM_SETTING_VLAN_SETTING_NAME, NM_SETTING_VLAN_ID, "id", OPTION_REQD, N_("VLAN ID (<0-4094>)"), NULL, NULL, NULL }, - { NM_SETTING_VLAN_SETTING_NAME, NM_SETTING_VLAN_FLAGS, "flags", OPTION_NONE, N_("VLAN flags (<0-7>) [none]"), NULL, NULL, NULL }, - { NM_SETTING_VLAN_SETTING_NAME, NM_SETTING_VLAN_INGRESS_PRIORITY_MAP, "ingress", OPTION_NONE, N_("Ingress priority maps [none]"), NULL, NULL, NULL }, - { NM_SETTING_VLAN_SETTING_NAME, NM_SETTING_VLAN_EGRESS_PRIORITY_MAP, "egress", OPTION_NONE, N_("Egress priority maps [none]"), NULL, NULL, NULL }, - { NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS, "mode", OPTION_NONE, PROMPT_BOND_MODE, "[balance-rr]", - set_bond_option, gen_func_bond_mode }, - { NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS, "primary", OPTION_DONT_ASK, N_("Bonding primary interface [none]"), - NULL, set_bond_option, nmc_rl_gen_func_ifnames }, - { NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS, NULL, OPTION_NONE, N_("Bonding monitoring mode"), PROMPT_BOND_MON_MODE_CHOICES, - set_bond_monitoring_mode, gen_func_bond_mon_mode }, - { NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS, "miimon", OPTION_DONT_ASK, N_("Bonding miimon [100]"), NULL, set_bond_option, NULL }, - { NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS, "downdelay", OPTION_DONT_ASK, N_("Bonding downdelay [0]"), NULL, set_bond_option, NULL }, - { NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS, "updelay", OPTION_DONT_ASK, N_("Bonding updelay [0]"), NULL, set_bond_option, NULL }, - { NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS, "arp-interval", OPTION_DONT_ASK, N_("Bonding arp-interval [0]"), NULL, - set_bond_option, NULL }, - { NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS, "arp-ip-target", OPTION_DONT_ASK, N_("Bonding arp-ip-target [none]"), - NULL, set_bond_option, NULL }, - { NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS, "lacp-rate", OPTION_DONT_ASK, N_("LACP rate ('slow' or 'fast') [slow]"), NULL, - set_bond_option, gen_func_bond_lacp_rate }, - { NM_SETTING_TEAM_SETTING_NAME, NM_SETTING_TEAM_CONFIG, "config", OPTION_NONE, N_("Team JSON configuration [none]"), NULL, NULL, NULL }, - { NM_SETTING_TEAM_PORT_SETTING_NAME, NM_SETTING_TEAM_PORT_CONFIG, "config", OPTION_NONE, N_("Team JSON configuration [none]"), NULL, NULL, NULL }, - { NM_SETTING_BRIDGE_SETTING_NAME, NM_SETTING_BRIDGE_STP, "stp", OPTION_NONE, N_("Enable STP [no]"), NULL, - set_yes_no, gen_func_bool_values_l10n }, - { NM_SETTING_BRIDGE_SETTING_NAME, NM_SETTING_BRIDGE_PRIORITY, "priority", OPTION_NONE, N_("STP priority [32768]"), NULL, NULL, NULL }, - { NM_SETTING_BRIDGE_SETTING_NAME, NM_SETTING_BRIDGE_FORWARD_DELAY, "forward-delay", OPTION_NONE, N_("Forward delay [15]"), NULL, NULL, NULL }, - { NM_SETTING_BRIDGE_SETTING_NAME, NM_SETTING_BRIDGE_HELLO_TIME, "hello-time", OPTION_NONE, N_("Hello time [2]"), NULL, NULL, NULL }, - { NM_SETTING_BRIDGE_SETTING_NAME, NM_SETTING_BRIDGE_MAX_AGE, "max-age", OPTION_NONE, N_("Max age [20]"), NULL, NULL, NULL }, - { NM_SETTING_BRIDGE_SETTING_NAME, NM_SETTING_BRIDGE_AGEING_TIME, "ageing-time", OPTION_NONE, N_("MAC address ageing time [300]"), NULL, NULL, NULL }, - { NM_SETTING_BRIDGE_SETTING_NAME, NM_SETTING_BRIDGE_MULTICAST_SNOOPING, "multicast-snooping", OPTION_NONE, N_("Enable IGMP snooping [no]"), NULL, - set_yes_no, gen_func_bool_values_l10n }, - { NM_SETTING_BRIDGE_SETTING_NAME, NM_SETTING_BRIDGE_MAC_ADDRESS, "mac", OPTION_NONE, N_("MAC [none]"), NULL, NULL, NULL }, - { NM_SETTING_BRIDGE_PORT_SETTING_NAME, NM_SETTING_BRIDGE_PORT_PRIORITY, "priority", OPTION_NONE, N_("Bridge port priority [32]"), NULL, NULL, NULL }, - { NM_SETTING_BRIDGE_PORT_SETTING_NAME, NM_SETTING_BRIDGE_PORT_PATH_COST, "path-cost", OPTION_NONE, N_("Bridge port STP path cost [100]"), NULL, NULL, NULL }, - { NM_SETTING_BRIDGE_PORT_SETTING_NAME, NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, "hairpin", OPTION_NONE, N_("Hairpin [no]"), NULL, - set_yes_no, gen_func_bool_values_l10n }, - { NM_SETTING_VPN_SETTING_NAME, NM_SETTING_VPN_SERVICE_TYPE, "vpn-type", OPTION_REQD, PROMPT_VPN_TYPE, NULL, NULL, gen_func_vpn_types }, - { NM_SETTING_VPN_SETTING_NAME, NM_SETTING_VPN_USER_NAME, "user", OPTION_NONE, N_("Username [none]"), NULL, NULL, NULL }, - { NM_SETTING_OLPC_MESH_SETTING_NAME, NM_SETTING_OLPC_MESH_SSID, "ssid", OPTION_REQD, N_("SSID"), NULL, NULL, NULL }, - { NM_SETTING_OLPC_MESH_SETTING_NAME, NM_SETTING_OLPC_MESH_CHANNEL, "channel", OPTION_NONE, N_("OLPC Mesh channel [1]"), NULL, NULL, NULL }, - { NM_SETTING_OLPC_MESH_SETTING_NAME, NM_SETTING_OLPC_MESH_DHCP_ANYCAST_ADDRESS, "dhcp-anycast", OPTION_NONE, N_("DHCP anycast MAC address [none]"), NULL, NULL, NULL }, - { NM_SETTING_ADSL_SETTING_NAME, NM_SETTING_ADSL_USERNAME, "username", OPTION_REQD, N_("Username"), NULL, NULL, NULL }, - { NM_SETTING_ADSL_SETTING_NAME, NM_SETTING_ADSL_PROTOCOL, "protocol", OPTION_REQD, PROMPT_ADSL_PROTO, PROMPT_ADSL_PROTO_CHOICES, - NULL, gen_func_adsl_proto }, - { NM_SETTING_ADSL_SETTING_NAME, NM_SETTING_ADSL_PASSWORD, "password", OPTION_NONE, N_("Password [none]"), NULL, NULL, NULL }, - { NM_SETTING_ADSL_SETTING_NAME, NM_SETTING_ADSL_ENCAPSULATION, "encapsulation", OPTION_NONE, PROMPT_ADSL_ENCAP, PROMPT_ADSL_ENCAP_CHOICES, - NULL, gen_func_adsl_encap }, - { NM_SETTING_MACSEC_SETTING_NAME, NM_SETTING_MACSEC_PARENT, "dev", OPTION_REQD, N_("MACsec parent device or connection UUID"), NULL, NULL, NULL }, - { NM_SETTING_MACSEC_SETTING_NAME, NM_SETTING_MACSEC_MODE, "mode", OPTION_REQD, PROMPT_MACSEC_MODE, PROMPT_MACSEC_MODE_CHOICES, NULL, gen_func_macsec_mode }, - { NM_SETTING_MACSEC_SETTING_NAME, NM_SETTING_MACSEC_ENCRYPT, "encrypt", OPTION_NONE, N_("Enable encryption [yes]"), NULL, set_yes_no, gen_func_bool_values_l10n }, - { NM_SETTING_MACSEC_SETTING_NAME, NM_SETTING_MACSEC_MKA_CAK, "cak", OPTION_NONE, N_("MKA CAK"), NULL, NULL, NULL }, - { NM_SETTING_MACSEC_SETTING_NAME, NM_SETTING_MACSEC_MKA_CKN, "ckn", OPTION_NONE, N_("MKA_CKN"), NULL, NULL, NULL }, - { NM_SETTING_MACSEC_SETTING_NAME, NM_SETTING_MACSEC_PORT, "port", OPTION_NONE, N_("SCI port [1]"), NULL, NULL, NULL }, + _meta_abstract_get (abstract_info, &setting_info, NULL, &property_name, &option, NULL, NULL, NULL); - { NM_SETTING_MACVLAN_SETTING_NAME, NM_SETTING_MACVLAN_PARENT, "dev", OPTION_REQD, N_("MACVLAN parent device or connection UUID"), NULL, - NULL, nmc_rl_gen_func_ifnames }, - { NM_SETTING_MACVLAN_SETTING_NAME, NM_SETTING_MACVLAN_MODE, "mode", OPTION_REQD, PROMPT_MACVLAN_MODE, NULL, - NULL, gen_func_macvlan_mode }, - { NM_SETTING_MACVLAN_SETTING_NAME, NM_SETTING_MACVLAN_TAP, "tap", OPTION_NONE, N_("Tap [no]"), NULL, - set_yes_no, gen_func_bool_values_l10n }, - { NM_SETTING_VXLAN_SETTING_NAME, NM_SETTING_VXLAN_ID, "id", OPTION_REQD, N_("VXLAN ID"), NULL, NULL, NULL }, - { NM_SETTING_VXLAN_SETTING_NAME, NM_SETTING_VXLAN_REMOTE, "remote", OPTION_REQD, N_("Remote"), NULL, NULL, NULL }, - { NM_SETTING_VXLAN_SETTING_NAME, NM_SETTING_VXLAN_PARENT, "dev", OPTION_NONE, N_("Parent device [none]"), NULL, - NULL, nmc_rl_gen_func_ifnames }, - { NM_SETTING_VXLAN_SETTING_NAME, NM_SETTING_VXLAN_LOCAL, "local", OPTION_NONE, N_("Local address [none]"), NULL, NULL, NULL }, - { NM_SETTING_VXLAN_SETTING_NAME, NM_SETTING_VXLAN_SOURCE_PORT_MIN, "source-port-min", OPTION_NONE, N_("Minimum source port [0]"), NULL, NULL, NULL }, - { NM_SETTING_VXLAN_SETTING_NAME, NM_SETTING_VXLAN_SOURCE_PORT_MAX, "source-port-max", OPTION_NONE, N_("Maximum source port [0]"), NULL, NULL, NULL }, - { NM_SETTING_VXLAN_SETTING_NAME, NM_SETTING_VXLAN_DESTINATION_PORT, "destination-port", OPTION_NONE, N_("Destination port [8472]"), NULL, NULL, NULL }, - { NM_SETTING_TUN_SETTING_NAME, NM_SETTING_TUN_MODE, "mode", OPTION_NONE, PROMPT_TUN_MODE, PROMPT_TUN_MODE_CHOICES, - NULL, gen_func_tun_mode }, - { NM_SETTING_TUN_SETTING_NAME, NM_SETTING_TUN_OWNER, "owner", OPTION_NONE, N_("User ID [none]"), NULL, NULL, NULL }, - { NM_SETTING_TUN_SETTING_NAME, NM_SETTING_TUN_GROUP, "group", OPTION_NONE, N_("Group ID [none]"), NULL, NULL, NULL }, - { NM_SETTING_TUN_SETTING_NAME, NM_SETTING_TUN_PI, "pi", OPTION_NONE, N_("Enable PI [no]"), NULL, - set_yes_no, gen_func_bool_values_l10n }, - { NM_SETTING_TUN_SETTING_NAME, NM_SETTING_TUN_VNET_HDR, "vnet-hdr", OPTION_NONE, N_("Enable VNET header [no]"), NULL, - set_yes_no, gen_func_bool_values_l10n }, - { NM_SETTING_TUN_SETTING_NAME, NM_SETTING_TUN_MULTI_QUEUE, "multi-queue", OPTION_NONE, N_("Enable multi queue [no]"), NULL, - set_yes_no, gen_func_bool_values_l10n }, - { NM_SETTING_IP_TUNNEL_SETTING_NAME, NM_SETTING_IP_TUNNEL_MODE, "mode", OPTION_REQD, PROMPT_IP_TUNNEL_MODE, NULL, NULL, gen_func_ip_tunnel_mode }, - { NM_SETTING_IP_TUNNEL_SETTING_NAME, NM_SETTING_IP_TUNNEL_LOCAL, "local", OPTION_NONE, N_("Local endpoint [none]"), NULL, NULL, NULL }, - { NM_SETTING_IP_TUNNEL_SETTING_NAME, NM_SETTING_IP_TUNNEL_REMOTE, "remote", OPTION_REQD, N_("Remote"), NULL, NULL, NULL }, - { NM_SETTING_IP_TUNNEL_SETTING_NAME, NM_SETTING_IP_TUNNEL_PARENT, "dev", OPTION_NONE, N_("Parent device [none]"), NULL, - NULL, nmc_rl_gen_func_ifnames }, - { NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_SETTING_IP_CONFIG_ADDRESSES, "ip4", OPTION_MULTI, N_("IPv4 address (IP[/plen]) [none]"), NULL, - set_ip4_address, NULL }, - { NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_SETTING_IP_CONFIG_GATEWAY, "gw4", OPTION_NONE, N_("IPv4 gateway [none]"), NULL, NULL, NULL }, - { NM_SETTING_IP6_CONFIG_SETTING_NAME, NM_SETTING_IP_CONFIG_ADDRESSES, "ip6", OPTION_MULTI, N_("IPv6 address (IP[/plen]) [none]"), NULL, - set_ip6_address, NULL }, - { NM_SETTING_IP6_CONFIG_SETTING_NAME, NM_SETTING_IP_CONFIG_GATEWAY, "gw6", OPTION_NONE, N_("IPv6 gateway [none]"), NULL, NULL, NULL }, - { NM_SETTING_PROXY_SETTING_NAME, NM_SETTING_PROXY_METHOD, "method", OPTION_NONE, PROMPT_PROXY_METHOD, PROMPT_PROXY_METHOD_CHOICES, NULL, gen_func_proxy_method }, - { NM_SETTING_PROXY_SETTING_NAME, NM_SETTING_PROXY_BROWSER_ONLY, "browser-only", OPTION_NONE, N_("Browser only [no]"), NULL, - set_yes_no, gen_func_bool_values_l10n }, - { NM_SETTING_PROXY_SETTING_NAME, NM_SETTING_PROXY_PAC_URL, "pac-url", OPTION_NONE, N_("PAC URL"), NULL, NULL, NULL }, - { NM_SETTING_PROXY_SETTING_NAME, NM_SETTING_PROXY_PAC_SCRIPT, "pac-script", OPTION_NONE, N_("PAC script"), NULL, NULL, NULL }, - { NULL, NULL, NULL, OPTION_NONE, NULL, NULL, NULL, NULL }, -}; + for (candidate = option_info; candidate->setting_info; candidate++) { + if ( candidate->setting_info == setting_info + && nm_streq0 (candidate->property, property_name) + && nm_streq0 (candidate->option, option)) { + return candidate; + } + } + return NULL; +} static gboolean -option_relevant (NMConnection *connection, OptionInfo *option) +option_relevant (NMConnection *connection, const NMMetaAbstractInfo *abstract_info) { - if (option->flags & OPTION_DONT_ASK && !(option->flags & OPTION_ENABLED)) + const char *setting_name; + NMMetaPropertyInfFlags inf_flags; + + _meta_abstract_get (abstract_info, NULL, &setting_name, NULL, NULL, &inf_flags, NULL, NULL); + + if ( (inf_flags & NM_META_PROPERTY_INF_FLAG_DONT_ASK) + && !(_dynamic_options_get (abstract_info) & PROPERTY_INF_FLAG_ENABLED)) return FALSE; - if (option->flags & OPTION_DISABLED) + if (_dynamic_options_get (abstract_info) & PROPERTY_INF_FLAG_DISABLED) return FALSE; - if (!nm_connection_get_setting_by_name (connection, option->setting_name)) + if (!nm_connection_get_setting_by_name (connection, setting_name)) return FALSE; return TRUE; } -/*----------------------------------------------------------------------------*/ +/*****************************************************************************/ static void complete_property_name (NmCli *nmc, NMConnection *connection, - char modifier, - const gchar *prefix, - const gchar *postfix) + char modifier, + const gchar *prefix, + const gchar *postfix) { NMSettingConnection *s_con; - const NameItem *valid_settings_main = NULL; - const NameItem *valid_settings_slave = NULL; + const NMMetaSettingValidPartItem *const*valid_settings_main; + const NMMetaSettingValidPartItem *const*valid_settings_slave; const char *connection_type = NULL; const char *slave_type = NULL; - gs_free char *slv_type = NULL; gs_free char *word_list = NULL; - OptionInfo *candidate; + NMMetaSettingType s; connection_type = nm_connection_get_connection_type (connection); s_con = nm_connection_get_setting_connection (connection); if (s_con) slave_type = nm_setting_connection_get_slave_type (s_con); - slv_type = g_strdup_printf ("%s-slave", slave_type ? slave_type : "no"); valid_settings_main = get_valid_settings_array (connection_type); - valid_settings_slave = get_valid_settings_array (slv_type); + valid_settings_slave = nm_meta_setting_info_valid_parts_for_slave_type (slave_type, NULL); word_list = get_valid_properties_string (valid_settings_main, valid_settings_slave, modifier, prefix, postfix); if (word_list) @@ -4380,14 +4055,37 @@ complete_property_name (NmCli *nmc, NMConnection *connection, if (modifier != '\0') return; - for (candidate = option_info; candidate->setting_name; candidate++) { - if (!nm_connection_get_setting_by_name (connection, candidate->setting_name)) + for (s = 0; s < _NM_META_SETTING_TYPE_NUM; s++) { + const NMMetaPropertyInfo *const*property_infos; + guint p; + + if (!nm_connection_get_setting_by_name (connection, nm_meta_setting_infos_editor[s].general->setting_name)) continue; - if (!candidate->option) - continue; - if (!g_str_has_prefix (candidate->option, prefix)) - continue; - g_print ("%s\n", candidate->option); + + property_infos = nm_property_infos_for_setting_type (s); + for (p = 0; property_infos[p]; p++) { + const NMMetaPropertyInfo *property_info = property_infos[p]; + + if (_meta_property_needs_bond_hack (property_info)) { + guint i; + + for (i = 0; i < nm_meta_property_typ_data_bond.nested_len; i++) { + const NMMetaNestedPropertyTypeInfo *bi = &nm_meta_property_typ_data_bond.nested[i]; + + if ( !bi->field_name + || !g_str_has_prefix (bi->field_name, prefix)) + continue; + g_print ("%s\n", bi->field_name); + } + } else { + if (!property_info->is_cli_option) + continue; + if ( !property_info->property_alias + || !g_str_has_prefix (property_info->property_alias, prefix)) + continue; + g_print ("%s\n", property_info->property_alias); + } + } } } @@ -4405,62 +4103,54 @@ run_rl_generator (rl_compentry_func_t *generator_func, const char *prefix) } } -static void -complete_option (OptionInfo *option, const gchar *prefix) +static gboolean +complete_option (const NMMetaAbstractInfo *abstract_info, const gchar *prefix, NMConnection *context_connection) { - if (option->generator_func) - run_rl_generator (option->generator_func, prefix); + const OptionInfo *candidate; + const char *const*values; + gs_strfreev char **values_to_free = NULL; + const NMMetaOperationContext ctx = { + .connection = context_connection, + }; + + values = nm_meta_abstract_info_complete (abstract_info, + nmc_meta_environment, + nmc_meta_environment_arg, + &ctx, + prefix, + &values_to_free); + if (values) { + for (; values[0]; values++) + g_print ("%s\n", values[0]); + return TRUE; + } + + candidate = _meta_abstract_get_option_info (abstract_info); + if (candidate && candidate->generator_func) { + run_rl_generator (candidate->generator_func, prefix); + return TRUE; + } + + return FALSE; } static void -complete_property (const gchar *setting_name, const gchar *property, const gchar *prefix) +complete_property (const gchar *setting_name, const gchar *property, const gchar *prefix, NMConnection *connection) { - if (strcmp (setting_name, NM_SETTING_CONNECTION_SETTING_NAME) == 0) { - if (strcmp (property, NM_SETTING_CONNECTION_TYPE) == 0) - run_rl_generator (gen_connection_types, prefix); - else if (strcmp (property, NM_SETTING_CONNECTION_MASTER) == 0) - run_rl_generator (gen_func_master_ifnames, prefix); - else if (strcmp (property, NM_SETTING_CONNECTION_INTERFACE_NAME) == 0) - run_rl_generator (nmc_rl_gen_func_ifnames, prefix); - } else if ( strcmp (setting_name, NM_SETTING_VPN_SETTING_NAME) == 0 - && strcmp (property, NM_SETTING_VPN_SERVICE_TYPE) == 0) - run_rl_generator (gen_func_vpn_types, prefix); - else if ( strcmp (setting_name, NM_SETTING_WIRELESS_SETTING_NAME) == 0 - && strcmp (property, NM_SETTING_WIRELESS_MODE) == 0) - run_rl_generator (gen_func_wifi_mode, prefix); - else if ( strcmp (setting_name, NM_SETTING_INFINIBAND_SETTING_NAME) == 0 - && strcmp (property, NM_SETTING_INFINIBAND_TRANSPORT_MODE) == 0) - run_rl_generator (gen_func_ib_type, prefix); - else if ( strcmp (setting_name, NM_SETTING_BLUETOOTH_SETTING_NAME) == 0 + const NMMetaPropertyInfo *property_info; + + property_info = nm_meta_property_info_find_by_name (setting_name, property); + if (property_info) { + if (complete_option ((const NMMetaAbstractInfo *) property_info, prefix, connection)) + return; + } + + if ( strcmp (setting_name, NM_SETTING_BLUETOOTH_SETTING_NAME) == 0 && strcmp (property, NM_SETTING_BLUETOOTH_TYPE) == 0) run_rl_generator (gen_func_bt_type, prefix); - else if (strcmp (setting_name, NM_SETTING_ADSL_SETTING_NAME) == 0) { - if (strcmp (property, NM_SETTING_ADSL_PROTOCOL) == 0) - run_rl_generator (gen_func_adsl_proto, prefix); - else if (strcmp (property, NM_SETTING_ADSL_ENCAPSULATION) == 0) - run_rl_generator (gen_func_adsl_encap, prefix); - } else if ( strcmp (setting_name, NM_SETTING_TUN_SETTING_NAME) == 0 - && strcmp (property, NM_SETTING_TUN_MODE) == 0) - run_rl_generator (gen_func_tun_mode, prefix); - else if (strcmp (setting_name, NM_SETTING_IP_TUNNEL_SETTING_NAME) == 0) { - if (strcmp (property, NM_SETTING_IP_TUNNEL_MODE) == 0) - run_rl_generator (gen_func_ip_tunnel_mode, prefix); - else if (strcmp (property, NM_SETTING_IP_TUNNEL_PARENT) == 0) - run_rl_generator (nmc_rl_gen_func_ifnames, prefix); - } else if (strcmp (setting_name, NM_SETTING_MACVLAN_SETTING_NAME) == 0) { - if (strcmp (property, NM_SETTING_MACVLAN_MODE) == 0) - run_rl_generator (gen_func_macvlan_mode, prefix); - else if (strcmp (property, NM_SETTING_MACVLAN_PARENT) == 0) - run_rl_generator (nmc_rl_gen_func_ifnames, prefix); - else if (strcmp (property, NM_SETTING_MACVLAN_TAP) == 0) - run_rl_generator (gen_func_bool_values_l10n, prefix); - } else if ( strcmp (setting_name, NM_SETTING_VXLAN_SETTING_NAME) == 0 - && strcmp (property, NM_SETTING_VXLAN_PARENT) == 0) - run_rl_generator (nmc_rl_gen_func_ifnames, prefix); - } -/*----------------------------------------------------------------------------*/ +/*****************************************************************************/ static gboolean get_value (const char **value, int *argc, char ***argv, const char *option, GError **error) @@ -4498,10 +4188,10 @@ nmc_read_connection_properties (NmCli *nmc, */ /* Go through arguments and set properties */ do { - OptionInfo *candidate; - OptionInfo *chosen = NULL; + const NMMetaAbstractInfo *chosen = NULL; gs_strfreev gchar **strv = NULL; - const NameItem *type_settings, *slv_settings; + const NMMetaSettingValidPartItem *const*type_settings; + const NMMetaSettingValidPartItem *const*slv_settings; char modifier = '\0'; if (!con_settings (connection, &type_settings, &slv_settings, error)) @@ -4548,25 +4238,64 @@ nmc_read_connection_properties (NmCli *nmc, return FALSE; if (!*argc && nmc->complete) - complete_property (setting, strv[1], value ? value : ""); + complete_property (setting, strv[1], value ? value : "", connection); if (!set_property (connection, setting_name, strv[1], value, modifier, error)) return FALSE; } else { + NMMetaSettingType s; + const char *chosen_setting_name = NULL; + const char *chosen_option = NULL; + /* Let's see if this is an property alias (such as "id", "mode", "type" or "con-name")*/ - for (candidate = option_info; candidate->setting_name; candidate++) { - if (g_strcmp0 (candidate->option, option)) + for (s = 0; s < _NM_META_SETTING_TYPE_NUM; s++) { + const NMMetaPropertyInfo *const*property_infos; + guint p; + + if (!check_valid_name (nm_meta_setting_infos[s].setting_name, + type_settings, slv_settings, NULL)) continue; - if (!check_valid_name (candidate->setting_name, type_settings, slv_settings, NULL)) - continue; - if (chosen) { - g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, - _("Error: '%s' is ambiguous (%s.%s or %s.%s)."), option, - chosen->setting_name, chosen->property, - candidate->setting_name, candidate->property); - return FALSE; + + property_infos = nm_property_infos_for_setting_type (s); + for (p = 0; property_infos[p]; p++) { + const NMMetaPropertyInfo *property_info = property_infos[p]; + + if (_meta_property_needs_bond_hack (property_info)) { + guint i; + + for (i = 0; i < nm_meta_property_typ_data_bond.nested_len; i++) { + const NMMetaNestedPropertyTypeInfo *bi = &nm_meta_property_typ_data_bond.nested[i]; + + if (!nm_streq0 (bi->field_name, option)) + continue; + if (chosen) { + g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, + _("Error: '%s' is ambiguous (%s.%s or %s.%s)."), option, + chosen_setting_name, chosen_option, + nm_meta_setting_infos[s].setting_name, option); + return FALSE; + } + chosen_setting_name = nm_meta_setting_infos[s].setting_name; + chosen_option = option; + chosen = (const NMMetaAbstractInfo *) bi; + } + } else { + if (!property_info->is_cli_option) + continue; + if (!nm_streq0 (property_info->property_alias, option)) + continue; + if (chosen) { + g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, + _("Error: '%s' is ambiguous (%s.%s or %s.%s)."), option, + chosen_setting_name, chosen_option, + nm_meta_setting_infos[s].setting_name, option); + return FALSE; + } + chosen_setting_name = nm_meta_setting_infos[s].setting_name; + chosen_option = option; + chosen = (const NMMetaAbstractInfo *) property_info; + } } - chosen = candidate; } if (!chosen) { @@ -4575,7 +4304,7 @@ nmc_read_connection_properties (NmCli *nmc, if (*argc == 1 && nmc->complete) complete_property_name (nmc, connection, modifier, option, NULL); g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, - _("Error: invalid . '%s'."), option); + _("Error: invalid . '%s'."), option); return FALSE; } @@ -4588,7 +4317,7 @@ nmc_read_connection_properties (NmCli *nmc, return FALSE; if (!*argc && nmc->complete) - complete_option (chosen, value ? value : ""); + complete_option (chosen, value ? value : "", connection); if (!set_option (nmc, connection, chosen, value, error)) return FALSE; @@ -4672,6 +4401,7 @@ is_single_word (const char* line) static char ** nmcli_con_add_tab_completion (const char *text, int start, int end) { + NMMetaSettingType s; char **match_array = NULL; rl_compentry_func_t *generator_func = NULL; gs_free char *no = g_strdup_printf ("[%s]: ", gettext ("no")); @@ -4686,38 +4416,46 @@ nmcli_con_add_tab_completion (const char *text, int start, int end) if (!is_single_word (rl_line_buffer)) return NULL; - if (g_str_has_prefix (rl_prompt, PROMPT_CON_TYPE)) - generator_func = gen_connection_types; - else if (g_str_has_prefix (rl_prompt, PROMPT_IFNAME)) - generator_func = nmc_rl_gen_func_ifnames; - else if (g_str_has_prefix (rl_prompt, PROMPT_VPN_TYPE)) - generator_func = gen_func_vpn_types; - else if (g_str_has_prefix (rl_prompt, PROMPT_MASTER)) - generator_func = gen_func_master_ifnames; - else if (g_str_has_prefix (rl_prompt, PROMPT_WIFI_MODE)) - generator_func = gen_func_wifi_mode; - else if (g_str_has_prefix (rl_prompt, PROMPT_IB_MODE)) - generator_func = gen_func_ib_type; - else if (g_str_has_prefix (rl_prompt, PROMPT_BT_TYPE)) + for (s = 0; s < _NM_META_SETTING_TYPE_NUM; s++) { + const NMMetaPropertyInfo *const*property_infos; + guint p; + + property_infos = nm_property_infos_for_setting_type (s); + for (p = 0; property_infos[p]; p++) { + const NMMetaPropertyInfo *property_info = property_infos[p]; + + if (_meta_property_needs_bond_hack (property_info)) { + guint i; + + for (i = 0; i < nm_meta_property_typ_data_bond.nested_len; i++) { + const NMMetaNestedPropertyTypeInfo *bi = &nm_meta_property_typ_data_bond.nested[i]; + + if ( bi->prompt + && g_str_has_prefix (rl_prompt, bi->prompt)) { + goto next; + } + } + } else { + if ( property_info->prompt + && g_str_has_prefix (rl_prompt, property_info->prompt)) { + char **values; + + values = _meta_abstract_complete ((const NMMetaAbstractInfo *) property_info, text); + if (values) + return values; + goto next; + } + } + } + } + +next: + if (g_str_has_prefix (rl_prompt, NM_META_TEXT_PROMPT_BT_TYPE)) generator_func = gen_func_bt_type; - else if (g_str_has_prefix (rl_prompt, PROMPT_BOND_MODE)) + else if (g_str_has_prefix (rl_prompt, NM_META_TEXT_PROMPT_BOND_MODE)) generator_func = gen_func_bond_mode; - else if (g_str_has_prefix (rl_prompt, PROMPT_BOND_MON_MODE)) + else if (g_str_has_prefix (rl_prompt, NM_META_TEXT_PROMPT_BOND_MON_MODE)) generator_func = gen_func_bond_mon_mode; - else if (g_str_has_prefix (rl_prompt, PROMPT_ADSL_PROTO)) - generator_func = gen_func_adsl_proto; - else if (g_str_has_prefix (rl_prompt, PROMPT_ADSL_ENCAP)) - generator_func = gen_func_adsl_encap; - else if (g_str_has_prefix (rl_prompt, PROMPT_TUN_MODE)) - generator_func = gen_func_tun_mode; - else if (g_str_has_prefix (rl_prompt, PROMPT_IP_TUNNEL_MODE)) - generator_func = gen_func_ip_tunnel_mode; - else if (g_str_has_prefix (rl_prompt, PROMPT_MACVLAN_MODE)) - generator_func = gen_func_macvlan_mode; - else if (g_str_has_prefix (rl_prompt, PROMPT_MACSEC_MODE)) - generator_func = gen_func_macsec_mode; - else if (g_str_has_prefix (rl_prompt, PROMPT_PROXY_METHOD)) - generator_func = gen_func_proxy_method; else if ( g_str_has_suffix (rl_prompt, yes) || g_str_has_suffix (rl_prompt, no)) generator_func = gen_func_bool_values_l10n; @@ -4729,20 +4467,25 @@ nmcli_con_add_tab_completion (const char *text, int start, int end) } static void -ask_option (NmCli *nmc, NMConnection *connection, OptionInfo *option) +ask_option (NmCli *nmc, NMConnection *connection, const NMMetaAbstractInfo *abstract_info) { gchar *value; GError *error = NULL; gs_free gchar *prompt = NULL; - gboolean multi = option->flags & OPTION_MULTI; + gboolean multi; + const char *opt_prompt, *opt_def_hint; + NMMetaPropertyInfFlags inf_flags; + _meta_abstract_get (abstract_info, NULL, NULL, NULL, NULL, &inf_flags, &opt_prompt, &opt_def_hint); prompt = g_strjoin ("", - gettext (option->prompt), - option->def_hint ? " " : "", - option->def_hint ? option->def_hint : "", + gettext (opt_prompt), + opt_def_hint ? " " : "", + opt_def_hint ?: "", ": ", NULL); + multi = NM_FLAGS_HAS (inf_flags, NM_META_PROPERTY_INF_FLAG_MULTI); + if (multi) g_print (_("You can specify this option more than once. Press when you're done.\n")); @@ -4751,7 +4494,7 @@ again: if (multi && !value) return; - if (!set_option (nmc, connection, option, value, &error)) { + if (!set_option (nmc, connection, abstract_info, value, &error)) { g_printerr ("%s\n", error->message); g_clear_error (&error); goto again; @@ -4764,14 +4507,39 @@ again: static void questionnaire_mandatory (NmCli *nmc, NMConnection *connection) { - OptionInfo *candidate; + NMMetaSettingType s; - /* Mandatory settings. */ - for (candidate = option_info; candidate->setting_name; candidate++) { - if (!option_relevant (connection, candidate)) - continue; - if (candidate->flags & OPTION_REQD || candidate->flags & OPTION_ENABLED) - ask_option (nmc, connection, candidate); + for (s = 0; s < _NM_META_SETTING_TYPE_NUM; s++) { + const NMMetaPropertyInfo *const*property_infos; + guint p; + + property_infos = nm_property_infos_for_setting_type (s); + for (p = 0; property_infos[p]; p++) { + const NMMetaPropertyInfo *property_info = property_infos[p]; + + if (_meta_property_needs_bond_hack (property_info)) { + guint i; + + for (i = 0; i < nm_meta_property_typ_data_bond.nested_len; i++) { + const NMMetaNestedPropertyTypeInfo *bi = &nm_meta_property_typ_data_bond.nested[i]; + + if (!option_relevant (connection, (const NMMetaAbstractInfo *) bi)) + continue; + if ( (bi->inf_flags & NM_META_PROPERTY_INF_FLAG_REQD) + || (_dynamic_options_get ((const NMMetaAbstractInfo *) bi) & PROPERTY_INF_FLAG_ENABLED)) + ask_option (nmc, connection, (const NMMetaAbstractInfo *) bi); + } + } else { + if (!property_info->is_cli_option) + continue; + + if (!option_relevant (connection, (const NMMetaAbstractInfo *) property_info)) + continue; + if ( (property_info->inf_flags & NM_META_PROPERTY_INF_FLAG_REQD) + || (_dynamic_options_get ((const NMMetaAbstractInfo *) property_info) & PROPERTY_INF_FLAG_ENABLED)) + ask_option (nmc, connection, (const NMMetaAbstractInfo *) property_info); + } + } } } @@ -4789,104 +4557,80 @@ want_provide_opt_args (const char *type, int num) "Do you want to provide them? %s", num), prompt_yes_no (TRUE, NULL)); answer = answer ? g_strstrip (answer) : NULL; - if (answer && !matches (answer, WORD_LOC_YES)) + if (answer && !matches (answer, WORD_YES)) ret = FALSE; g_free (answer); return ret; } -static const char * -setting_name_to_name (const char *name) -{ - if (strcmp (name, NM_SETTING_WIRED_SETTING_NAME) == 0) - return _("Wired Ethernet"); - if (strcmp (name, NM_SETTING_INFINIBAND_SETTING_NAME) == 0) - return _("InfiniBand connection"); - if (strcmp (name, NM_SETTING_WIRELESS_SETTING_NAME) == 0) - return _("Wi-Fi connection"); - if (strcmp (name, NM_SETTING_WIMAX_SETTING_NAME) == 0) - return _("WiMAX connection"); - if (strcmp (name, NM_SETTING_PPPOE_SETTING_NAME) == 0) - return _("PPPoE"); - if (strcmp (name, NM_SETTING_CDMA_SETTING_NAME) == 0) - return _("CDMA mobile broadband connection"); - if (strcmp (name, NM_SETTING_GSM_SETTING_NAME) == 0) - return _("GSM mobile broadband connection"); - if (strcmp (name, NM_SETTING_BLUETOOTH_SETTING_NAME) == 0) - return _("bluetooth connection"); - if (strcmp (name, NM_SETTING_VLAN_SETTING_NAME) == 0) - return _("VLAN connection"); - if (strcmp (name, NM_SETTING_BOND_SETTING_NAME) == 0) - return _("Bond device"); - if (strcmp (name, NM_SETTING_TEAM_SETTING_NAME) == 0) - return _("Team device"); - if (strcmp (name, NM_SETTING_TEAM_PORT_SETTING_NAME) == 0) - return _("Team port"); - if (strcmp (name, NM_SETTING_BRIDGE_SETTING_NAME) == 0) - return _("Bridge device"); - if (strcmp (name, NM_SETTING_BRIDGE_PORT_SETTING_NAME) == 0) - return _("Bridge port"); - if (strcmp (name, NM_SETTING_VPN_SETTING_NAME) == 0) - return _("VPN connection"); - if (strcmp (name, NM_SETTING_OLPC_MESH_SETTING_NAME) == 0) - return _("OLPC Mesh connection"); - if (strcmp (name, NM_SETTING_ADSL_SETTING_NAME) == 0) - return _("ADSL connection"); - if (strcmp (name, NM_SETTING_MACSEC_SETTING_NAME) == 0) - return _("MACsec connection"); - if (strcmp (name, NM_SETTING_MACVLAN_SETTING_NAME) == 0) - return _("macvlan connection"); - if (strcmp (name, NM_SETTING_VXLAN_SETTING_NAME) == 0) - return _("VXLAN connection"); - if (strcmp (name, NM_SETTING_TUN_SETTING_NAME) == 0) - return _("Tun device"); - if (strcmp (name, NM_SETTING_IP4_CONFIG_SETTING_NAME) == 0) - return _("IPv4 protocol"); - if (strcmp (name, NM_SETTING_IP6_CONFIG_SETTING_NAME) == 0) - return _("IPv6 protocol"); - if (strcmp (name, NM_SETTING_PROXY_SETTING_NAME) == 0) - return _("Proxy"); - - /* Should not happen; but let's still try to be somewhat sensible. */ - return name; -} - static gboolean questionnaire_one_optional (NmCli *nmc, NMConnection *connection) { - OptionInfo *candidate; + NMMetaSettingType s; + gs_unref_ptrarray GPtrArray *infos = NULL; + guint i; + gboolean already_confirmed = FALSE; + NMMetaSettingType s_asking = NM_META_SETTING_TYPE_UNKNOWN; - /* Optional settings. */ - const gchar *setting_name = NULL; - int count = 0; + infos = g_ptr_array_new (); /* Find first setting with relevant options and count them. */ - for (candidate = option_info; candidate->setting_name; candidate++) { - if (!option_relevant (connection, candidate)) - continue; - if (!setting_name) - setting_name = candidate->setting_name; - else if (strcmp (setting_name, candidate->setting_name)) - break; - count++; - } - if (!setting_name) - return FALSE; +again: + for (s = 0; s < _NM_META_SETTING_TYPE_NUM; s++) { + const NMMetaPropertyInfo *const*property_infos; + guint p; - /* Now ask for the settings. */ - if (want_provide_opt_args (setting_name_to_name (setting_name), count)) { - for (candidate = option_info; candidate->setting_name; candidate++) { - if (!option_relevant (connection, candidate)) - continue; - if (strcmp (setting_name, candidate->setting_name)) - continue; - ask_option (nmc, connection, candidate); + if ( s_asking != NM_META_SETTING_TYPE_UNKNOWN + && s != s_asking) + continue; + + property_infos = nm_property_infos_for_setting_type (s); + for (p = 0; property_infos[p]; p++) { + const NMMetaPropertyInfo *property_info = property_infos[p]; + + if (_meta_property_needs_bond_hack (property_info)) { + for (i = 0; i < nm_meta_property_typ_data_bond.nested_len; i++) { + const NMMetaNestedPropertyTypeInfo *bi = &nm_meta_property_typ_data_bond.nested[i]; + + if (!option_relevant (connection, (const NMMetaAbstractInfo *) bi)) + continue; + g_ptr_array_add (infos, (gpointer) bi); + } + } else { + if (!property_info->is_cli_option) + continue; + if (!option_relevant (connection, (const NMMetaAbstractInfo *) property_info)) + continue; + g_ptr_array_add (infos, (gpointer) property_info); + } + } + if (infos->len) { + s_asking = s; + break; } } - /* Make sure we won't ask again. */ - disable_options (setting_name, NULL); + if (infos->len) { + const NMMetaSettingInfoEditor *setting_info = NULL; + _meta_abstract_get (infos->pdata[0], &setting_info, NULL, NULL, NULL, NULL, NULL, NULL); + + /* Now ask for the settings. */ + if ( already_confirmed + || want_provide_opt_args (_(setting_info->pretty_name), infos->len)) { + ask_option (nmc, connection, infos->pdata[0]); + already_confirmed = TRUE; + /* asking for an option may enable other options. Create the list again. */ + g_ptr_array_set_size (infos, 0); + goto again; + } + } + + if (s_asking == NM_META_SETTING_TYPE_UNKNOWN) + return FALSE; + + /* Make sure we won't ask again. */ + disable_options (nm_meta_setting_infos[s_asking].setting_name, NULL); return TRUE; } @@ -4898,8 +4642,8 @@ do_connection_add (NmCli *nmc, int argc, char **argv) GError *error = NULL; AddConnectionInfo *info = NULL; gboolean save_bool = TRUE; - OptionInfo *candidate; gboolean seen_dash_dash = FALSE; + NMMetaSettingType s; next_arg (nmc, &argc, &argv, NULL); @@ -4983,8 +4727,9 @@ read_properties: const GPtrArray *connections; connections = nm_client_get_connections (nmc->client); - try_name = ifname ? g_strdup_printf ("%s-%s", get_name_alias (type, slave_type, nmc_valid_connection_types), ifname) - : g_strdup (get_name_alias (type, slave_type, nmc_valid_connection_types)); + try_name = ifname + ? g_strdup_printf ("%s-%s", get_name_alias_toplevel (type, slave_type), ifname) + : g_strdup (get_name_alias_toplevel (type, slave_type)); default_name = nmc_unique_connection_name (connections, try_name); g_free (try_name); g_object_set (s_con, NM_SETTING_CONNECTION_ID, default_name, NULL); @@ -5006,13 +4751,39 @@ read_properties: * from doing something that's not likely to make sense (such as missing ifname * on a bond/bridge/team, etc.). Added just to preserve traditional behavior, it * perhaps is a good idea to just remove this. */ - for (candidate = option_info; candidate->setting_name; candidate++) { - if (!option_relevant (connection, candidate)) - continue; - if (candidate->flags & OPTION_REQD) { - g_string_printf (nmc->return_text, _("Error: '%s' argument is required."), candidate->option); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto finish; + for (s = 0; s < _NM_META_SETTING_TYPE_NUM; s++) { + const NMMetaPropertyInfo *const*property_infos; + guint p; + + property_infos = nm_property_infos_for_setting_type (s); + for (p = 0; property_infos[p]; p++) { + const NMMetaPropertyInfo *property_info = property_infos[p]; + + if (_meta_property_needs_bond_hack (property_info)) { + guint i; + + for (i = 0; i < nm_meta_property_typ_data_bond.nested_len; i++) { + const NMMetaNestedPropertyTypeInfo *bi = &nm_meta_property_typ_data_bond.nested[i]; + + if (!option_relevant (connection, (const NMMetaAbstractInfo *) bi)) + continue; + if (bi->inf_flags & NM_META_PROPERTY_INF_FLAG_REQD) { + g_string_printf (nmc->return_text, _("Error: '%s' argument is required."), bi->field_name); + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + goto finish; + } + } + } else { + if (!property_info->is_cli_option) + continue; + if (!option_relevant (connection, (const NMMetaAbstractInfo *) property_info)) + continue; + if (property_info->inf_flags & NM_META_PROPERTY_INF_FLAG_REQD) { + g_string_printf (nmc->return_text, _("Error: '%s' argument is required."), property_info->property_alias); + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + goto finish; + } + } } } @@ -5037,7 +4808,7 @@ finish: return nmc->return_value; } -/*----------------------------------------------------------------------------*/ +/*****************************************************************************/ /* Functions for readline TAB completion in editor */ static void @@ -5157,28 +4928,14 @@ gen_cmd_save (const char *text, int state) return nmc_rl_gen_func_basic (text, state, words); } -static char * -gen_connection_types (const char *text, int state) +static rl_compentry_func_t * +gen_connection_types (const char *text) { - static int list_idx, len; - const char *c_type, *a_type; + gs_strfreev char **values = NULL; - if (!state) { - list_idx = 0; - len = strlen (text); - } - - while (nmc_valid_connection_types[list_idx].name) { - a_type = nmc_valid_connection_types[list_idx].alias; - c_type = nmc_valid_connection_types[list_idx].name; - list_idx++; - if (a_type && !strncmp (text, a_type, len)) - return g_strdup (a_type); - if (c_type && !strncmp (text, c_type, len)) - return g_strdup (c_type); - } - - return NULL; + values = _meta_abstract_complete ((const NMMetaAbstractInfo *) nm_meta_property_info_connection_type, + text); + return nmc_rl_compentry_func_wrap ((const char *const*) values); } static char * @@ -5186,10 +4943,9 @@ gen_setting_names (const char *text, int state) { static int list_idx, len, is_slv; const char *s_name, *a_name; - const NameItem *valid_settings_arr; + const NMMetaSettingValidPartItem *const*valid_settings_arr; NMSettingConnection *s_con; const char *s_type = NULL; - char *slv_type; if (!state) { list_idx = 0; @@ -5199,11 +4955,13 @@ gen_setting_names (const char *text, int state) if (!is_slv) { valid_settings_arr = get_valid_settings_array (nmc_tab_completion.con_type); - if (!valid_settings_arr) + if (list_idx >= NM_PTRARRAY_LEN (valid_settings_arr)) return NULL; - while (valid_settings_arr[list_idx].name) { - a_name = valid_settings_arr[list_idx].alias; - s_name = valid_settings_arr[list_idx].name; + for (; valid_settings_arr[list_idx];) { + const NMMetaSettingInfoEditor *setting_info = valid_settings_arr[list_idx]->setting_info; + + a_name = setting_info->alias; + s_name = setting_info->general->setting_name; list_idx++; if (len == 0 && a_name) return g_strdup_printf ("%s (%s)", s_name, a_name); @@ -5222,20 +4980,22 @@ gen_setting_names (const char *text, int state) s_con = nm_connection_get_setting_connection (nmc_tab_completion.connection); if (s_con) s_type = nm_setting_connection_get_slave_type (s_con); - slv_type = g_strdup_printf ("%s-slave", s_type ? s_type : "no"); - valid_settings_arr = get_valid_settings_array (slv_type); - g_free (slv_type); + valid_settings_arr = nm_meta_setting_info_valid_parts_for_slave_type (s_type, NULL); - while (valid_settings_arr[list_idx].name) { - a_name = valid_settings_arr[list_idx].alias; - s_name = valid_settings_arr[list_idx].name; - list_idx++; - if (len == 0 && a_name) - return g_strdup_printf ("%s (%s)", s_name, a_name); - if (a_name && !strncmp (text, a_name, len)) - return g_strdup (a_name); - if (s_name && !strncmp (text, s_name, len)) - return g_strdup (s_name); + if (list_idx < NM_PTRARRAY_LEN (valid_settings_arr)) { + while (valid_settings_arr[list_idx]) { + const NMMetaSettingInfoEditor *setting_info = valid_settings_arr[list_idx]->setting_info; + + a_name = setting_info->alias; + s_name = setting_info->general->setting_name; + list_idx++; + if (len == 0 && a_name) + return g_strdup_printf ("%s (%s)", s_name, a_name); + if (a_name && !strncmp (text, a_name, len)) + return g_strdup (a_name); + if (s_name && !strncmp (text, s_name, len)) + return g_strdup (s_name); + } } return NULL; @@ -5250,8 +5010,8 @@ gen_property_names (const char *text, int state) const char *line = rl_line_buffer; const char *setting_name; char **strv = NULL; - const NameItem *valid_settings_main; - const NameItem *valid_settings_slave; + const NMMetaSettingValidPartItem *const*valid_settings_main; + const NMMetaSettingValidPartItem *const*valid_settings_slave; const char *p1; const char *slv_type; @@ -5261,7 +5021,7 @@ gen_property_names (const char *text, int state) while (p1 > line && !g_ascii_isspace (*p1)) p1--; - strv = g_strsplit (p1+1, ".", 2); + strv = g_strsplit (p1 + 1, ".", 2); valid_settings_main = get_valid_settings_array (nmc_tab_completion.con_type); @@ -5269,18 +5029,19 @@ gen_property_names (const char *text, int state) * guessing the slave type from the setting name already * typed (or autocompleted) */ if (nm_streq0 (strv[0], NM_SETTING_TEAM_PORT_SETTING_NAME)) - slv_type = "team-slave"; + slv_type = NM_SETTING_TEAM_SETTING_NAME; else if (nm_streq0 (strv[0], NM_SETTING_BRIDGE_PORT_SETTING_NAME)) - slv_type = "bridge-slave"; + slv_type = NM_SETTING_BRIDGE_SETTING_NAME; else - slv_type = "no-slave"; - valid_settings_slave = get_valid_settings_array (slv_type); + slv_type = NULL; + valid_settings_slave = nm_meta_setting_info_valid_parts_for_slave_type (slv_type, NULL); setting_name = check_valid_name (strv[0], valid_settings_main, valid_settings_slave, NULL); - setting = nmc_setting_new_for_name (setting_name); + setting = nm_meta_setting_info_editor_new_setting (nm_meta_setting_info_editor_find_by_name (setting_name, FALSE), + NM_META_ACCESSOR_SETTING_INIT_TYPE_DEFAULT); } else { /* Else take the current setting, if any */ setting = nmc_tab_completion.setting ? g_object_ref (nmc_tab_completion.setting) : NULL; @@ -5559,15 +5320,14 @@ static void get_setting_and_property (const char *prompt, const char *line, NMSetting **setting_out, char**property_out) { - const NameItem *valid_settings_main; - const NameItem *valid_settings_slave; + const NMMetaSettingValidPartItem *const*valid_settings_main; + const NMMetaSettingValidPartItem *const*valid_settings_slave; const char *setting_name; NMSetting *setting = NULL; char *property = NULL; char *sett = NULL, *prop = NULL; NMSettingConnection *s_con; const char *s_type = NULL; - char *slv_type; extract_setting_and_property (prompt, line, &sett, &prop); if (sett) { @@ -5575,15 +5335,14 @@ get_setting_and_property (const char *prompt, const char *line, s_con = nm_connection_get_setting_connection (nmc_tab_completion.connection); if (s_con) s_type = nm_setting_connection_get_slave_type (s_con); - slv_type = g_strdup_printf ("%s-slave", s_type ? s_type : "no"); valid_settings_main = get_valid_settings_array (nmc_tab_completion.con_type); - valid_settings_slave = get_valid_settings_array (slv_type); - g_free (slv_type); + valid_settings_slave = nm_meta_setting_info_valid_parts_for_slave_type (s_type, NULL); setting_name = check_valid_name (sett, valid_settings_main, valid_settings_slave, NULL); - setting = nmc_setting_new_for_name (setting_name); + setting = nm_meta_setting_info_editor_new_setting (nm_meta_setting_info_editor_find_by_name (setting_name, FALSE), + NM_META_ACCESSOR_SETTING_INIT_TYPE_DEFAULT); } else setting = nmc_tab_completion.setting ? g_object_ref (nmc_tab_completion.setting) : NULL; @@ -5774,7 +5533,7 @@ nmcli_editor_tab_completion (const char *text, int start, int end) /* Choose the right generator function */ if (strcmp (prompt_tmp, EDITOR_PROMPT_CON_TYPE) == 0) - generator_func = gen_connection_types; + generator_func = gen_connection_types (text); else if (strcmp (prompt_tmp, EDITOR_PROMPT_SETTING) == 0) generator_func = gen_setting_names; else if (strcmp (prompt_tmp, EDITOR_PROMPT_PROPERTY) == 0) @@ -5960,7 +5719,7 @@ save_history_cmds (const char *uuid) } } -/*----------------------------------------------------------------------------*/ +/*****************************************************************************/ static void editor_show_connection (NMConnection *connection, NmCli *nmc) @@ -5969,7 +5728,7 @@ editor_show_connection (NMConnection *connection, NmCli *nmc) nmc->nmc_config_mutable.multiline_output = TRUE; nmc->nmc_config_mutable.escape_values = 0; - nmc_connection_profile_details (connection, nmc, nmc->editor_show_secrets); + nmc_connection_profile_details (connection, nmc); } static void @@ -5982,7 +5741,7 @@ editor_show_setting (NMSetting *setting, NmCli *nmc) nmc->nmc_config_mutable.multiline_output = TRUE; nmc->nmc_config_mutable.escape_values = 0; - setting_details (&nmc->nmc_config, setting, NULL, nmc->editor_show_secrets); + setting_details (&nmc->nmc_config, setting, NULL); } typedef enum { @@ -6313,7 +6072,7 @@ editor_sub_usage (const char *command) } } -/*----------------------------------------------------------------------------*/ +/*****************************************************************************/ typedef struct { NMDevice *device; @@ -6438,7 +6197,7 @@ activate_connection_editor_cb (GObject *client, g_clear_error (&error); } -/*----------------------------------------------------------------------------*/ +/*****************************************************************************/ static void print_property_description (NMSetting *setting, const char *prop_name) @@ -6536,7 +6295,7 @@ confirm_quit (void) "Do you really want to quit? %s"), prompt_yes_no (FALSE, NULL)); answer = answer ? g_strstrip (answer) : NULL; - if (answer && matches (answer, WORD_LOC_YES)) + if (answer && matches (answer, WORD_YES)) want_quit = TRUE; g_free (answer); @@ -6778,7 +6537,7 @@ split_editor_main_cmd_args (const char *str, char **setting, char **property, ch } static NMSetting * -create_setting_by_name (const char *name, const NameItem *valid_settings_main, const NameItem *valid_settings_slave) +create_setting_by_name (const char *name, const NMMetaSettingValidPartItem *const*valid_settings_main, const NMMetaSettingValidPartItem *const*valid_settings_slave) { const char *setting_name; NMSetting *setting = NULL; @@ -6787,18 +6546,16 @@ create_setting_by_name (const char *name, const NameItem *valid_settings_main, c setting_name = check_valid_name (name, valid_settings_main, valid_settings_slave, NULL); if (setting_name) { - setting = nmc_setting_new_for_name (setting_name); - if (!setting) - return NULL; /* This should really not happen */ - nmc_setting_custom_init (setting); + setting = nm_meta_setting_info_editor_new_setting (nm_meta_setting_info_editor_find_by_name (setting_name, FALSE), + NM_META_ACCESSOR_SETTING_INIT_TYPE_CLI); } return setting; } static const char * ask_check_setting (const char *arg, - const NameItem *valid_settings_main, - const NameItem *valid_settings_slave, + const NMMetaSettingValidPartItem *const*valid_settings_main, + const NMMetaSettingValidPartItem *const*valid_settings_slave, const char *valid_settings_str) { char *setting_name_user; @@ -6888,7 +6645,7 @@ confirm_connection_saving (NMConnection *local, NMConnection *remote) "That might result in an immediate activation of the connection.\n" "Do you still want to save? %s"), prompt_yes_no (TRUE, NULL)); answer = answer ? g_strstrip (answer) : NULL; - if (!answer || matches (answer, WORD_LOC_YES)) + if (!answer || matches (answer, WORD_YES)) confirmed = TRUE; else confirmed = FALSE; @@ -6952,11 +6709,10 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t gboolean cmd_loop = TRUE; char *cmd_arg = NULL; char *cmd_arg_s, *cmd_arg_p, *cmd_arg_v; - const NameItem *valid_settings_main = NULL; - const NameItem *valid_settings_slave = NULL; + const NMMetaSettingValidPartItem *const*valid_settings_main; + const NMMetaSettingValidPartItem *const*valid_settings_slave; char *valid_settings_str = NULL; const char *s_type = NULL; - char *slv_type; AddConnectionInfo *info = NULL; gboolean dirty; gboolean temp_changes; @@ -6966,13 +6722,11 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t s_con = nm_connection_get_setting_connection (connection); if (s_con) s_type = nm_setting_connection_get_slave_type (s_con); - slv_type = g_strdup_printf ("%s-slave", s_type ? s_type : "no"); valid_settings_main = get_valid_settings_array (connection_type); - valid_settings_slave = get_valid_settings_array (slv_type); - g_free (slv_type); + valid_settings_slave = nm_meta_setting_info_valid_parts_for_slave_type (s_type, NULL); - valid_settings_str = get_valid_options_string (valid_settings_main, valid_settings_slave); + valid_settings_str = Get_valid_options_string (valid_settings_main, valid_settings_slave); g_print (_("You may edit the following settings: %s\n"), valid_settings_str); menu_ctx.level = 0; @@ -7124,20 +6878,24 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t const char *user_arg = cmd_arg_s ? cmd_arg_s : cmd_arg_p; setting_name = ask_check_setting (user_arg, - valid_settings_main, - valid_settings_slave, - valid_settings_str); + valid_settings_main, + valid_settings_slave, + valid_settings_str); if (!setting_name) break; setting = nm_connection_get_setting_by_name (connection, setting_name); if (!setting) { - setting = nmc_setting_new_for_name (setting_name); - if (!setting) { + const NMMetaSettingInfoEditor *setting_info; + + setting_info = nm_meta_setting_info_editor_find_by_name (setting_name, FALSE); + if (!setting_info) { g_print (_("Error: unknown setting '%s'\n"), setting_name); break; } - nmc_setting_custom_init (setting); + + setting = nm_meta_setting_info_editor_new_setting (setting_info, + NM_META_ACCESSOR_SETTING_INIT_TYPE_CLI); if (NM_IS_SETTING_WIRELESS (setting)) nmc_setting_wireless_connect_handlers (NM_SETTING_WIRELESS (setting)); @@ -7212,19 +6970,20 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t user_s = descr_all ? cmd_arg_p : cmd_arg_s ? cmd_arg_s : NULL; if (user_s) { ss = is_setting_valid (connection, - valid_settings_main, - valid_settings_slave, - user_s); + valid_settings_main, + valid_settings_slave, + user_s); if (!ss) { if (check_valid_name (user_s, valid_settings_main, valid_settings_slave, - NULL)) + NULL)) { g_print (_("Setting '%s' is not present in the connection.\n"), - user_s); - else + user_s); + } else { g_print (_("Error: invalid setting argument '%s'; valid are [%s]\n"), user_s, valid_settings_str); + } break; } } else @@ -7252,9 +7011,9 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t /* If the string is not a property, try it as a setting */ NMSetting *s_tmp; s_tmp = is_setting_valid (connection, - valid_settings_main, - valid_settings_slave, - cmd_arg_p); + valid_settings_main, + valid_settings_slave, + cmd_arg_p); if (s_tmp) { /* Remove setting from the connection */ connection_remove_setting (connection, s_tmp); @@ -7303,13 +7062,13 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t user_s = descr_all ? cmd_arg_p : cmd_arg_s ? cmd_arg_s : NULL; if (user_s) { ss = is_setting_valid (connection, - valid_settings_main, - valid_settings_slave, - user_s); + valid_settings_main, + valid_settings_slave, + user_s); if (!ss) { ss = create_setting_by_name (user_s, - valid_settings_main, - valid_settings_slave); + valid_settings_main, + valid_settings_slave); if (!ss) { g_print (_("Error: invalid setting argument '%s'; valid are [%s]\n"), user_s, valid_settings_str); @@ -7333,9 +7092,9 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t /* If the string is not a property, try it as a setting */ NMSetting *s_tmp; s_tmp = is_setting_valid (connection, - valid_settings_main, - valid_settings_slave, - cmd_arg_p); + valid_settings_main, + valid_settings_slave, + cmd_arg_p); if (s_tmp) print_setting_description (s_tmp); else @@ -7366,6 +7125,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t user_s = whole_setting ? cmd_arg_p : cmd_arg_s ? cmd_arg_s : NULL; if (user_s) { const char *s_name; + s_name = check_valid_name (user_s, valid_settings_main, valid_settings_slave, @@ -7397,9 +7157,9 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t /* If the string is not a property, try it as a setting */ NMSetting *s_tmp; s_tmp = is_setting_valid (connection, - valid_settings_main, - valid_settings_slave, - cmd_arg_p); + valid_settings_main, + valid_settings_slave, + cmd_arg_p); if (s_tmp) { /* Print the whole setting */ editor_show_setting (s_tmp, nmc); @@ -7646,7 +7406,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t g_print (_("Error: show-secrets: %s\n"), tmp_err->message); g_clear_error (&tmp_err); } else - nmc->editor_show_secrets = bb; + nmc->nmc_config_mutable.show_secrets = bb; } else if (cmd_arg_p && matches (cmd_arg_p, "prompt-color")) { GError *tmp_err = NULL; NMMetaTermColor color; @@ -7673,7 +7433,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t "prompt-color: %d\n", nmc->editor_status_line ? "yes" : "no", nmc->editor_save_confirmation ? "yes" : "no", - nmc->editor_show_secrets ? "yes" : "no", + nmc->nmc_config.show_secrets ? "yes" : "no", nmc->editor_prompt_color); } else g_print (_("Invalid configuration option '%s'; allowed [%s]\n"), @@ -7766,11 +7526,14 @@ editor_init_new_connection (NmCli *nmc, NMConnection *connection) NM_SETTING_CONNECTION_SLAVE_TYPE, slave_type, NULL); } else { + const NMMetaSettingInfoEditor *setting_info; + /* Add a "base" setting to the connection by default */ - base_setting = nmc_setting_new_for_name (con_type); - if (!base_setting) + setting_info = nm_meta_setting_info_editor_find_by_name (con_type, FALSE); + if (!setting_info) return; - nmc_setting_custom_init (base_setting); + base_setting = nm_meta_setting_info_editor_new_setting (setting_info, + NM_META_ACCESSOR_SETTING_INIT_TYPE_CLI); nm_connection_add_setting (connection, base_setting); set_default_interface_name (nmc, s_con); @@ -7785,18 +7548,16 @@ editor_init_new_connection (NmCli *nmc, NMConnection *connection) } - /* Always add IPv4 and IPv6 settings for non-slave connections */ - setting = nm_setting_ip4_config_new (); - nmc_setting_custom_init (setting); + setting = nm_meta_setting_info_editor_new_setting (&nm_meta_setting_infos_editor[NM_META_SETTING_TYPE_IP4_CONFIG], + NM_META_ACCESSOR_SETTING_INIT_TYPE_CLI); nm_connection_add_setting (connection, setting); - setting = nm_setting_ip6_config_new (); - nmc_setting_custom_init (setting); + setting = nm_meta_setting_info_editor_new_setting (&nm_meta_setting_infos_editor[NM_META_SETTING_TYPE_IP6_CONFIG], + NM_META_ACCESSOR_SETTING_INIT_TYPE_CLI); nm_connection_add_setting (connection, setting); - /* Also Proxy Setting */ - setting = nm_setting_proxy_new (); - nmc_setting_custom_init (setting); + setting = nm_meta_setting_info_editor_new_setting (&nm_meta_setting_infos_editor[NM_META_SETTING_TYPE_PROXY], + NM_META_ACCESSOR_SETTING_INIT_TYPE_CLI); nm_connection_add_setting (connection, setting); } } @@ -7828,14 +7589,18 @@ editor_init_existing_connection (NMConnection *connection) } static void -nmc_complete_connection_type (const char *prefix, const NameItem *types) +nmc_complete_connection_type (const char *prefix) { - while (types->name) { - if (!*prefix || matches (prefix, types->name)) - g_print ("%s\n", types->name); - if (types->alias && (!*prefix || matches (prefix, types->alias))) - g_print ("%s\n", types->alias); - types++; + guint i; + + for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++) { + const NMMetaSettingInfoEditor *setting_info = &nm_meta_setting_infos_editor[i]; + + if (!*prefix || matches (prefix, setting_info->general->setting_name)) + g_print ("%s\n", setting_info->general->setting_name); + if ( setting_info->alias + && (!*prefix || matches (prefix, setting_info->alias))) + g_print ("%s\n", setting_info->alias); } } @@ -7952,12 +7717,12 @@ do_connection_edit (NmCli *nmc, int argc, char **argv) /* New connection */ if (nmc->complete) { if (type && argc == 0) - nmc_complete_connection_type (type, nmc_valid_connection_types); + nmc_complete_connection_type (type); goto error; } - connection_type = check_valid_name (type, nmc_valid_connection_types, NULL, &err1); - tmp_str = get_valid_options_string (nmc_valid_connection_types, NULL); + connection_type = check_valid_name_toplevel (type, &err1); + tmp_str = get_valid_options_string_toplevel (); while (!connection_type) { if (!type) @@ -7968,7 +7733,7 @@ do_connection_edit (NmCli *nmc, int argc, char **argv) type_ask = nmc_readline (EDITOR_PROMPT_CON_TYPE); type = type_ask = type_ask ? g_strstrip (type_ask) : NULL; - connection_type = check_valid_name (type_ask, nmc_valid_connection_types, NULL, &err1); + connection_type = check_valid_name_toplevel (type_ask, &err1); g_free (type_ask); } g_free (tmp_str); @@ -7981,9 +7746,10 @@ do_connection_edit (NmCli *nmc, int argc, char **argv) uuid = nm_utils_uuid_generate (); if (con_name) default_name = g_strdup (con_name); - else + else { default_name = nmc_unique_connection_name (connections, - get_name_alias (connection_type, NULL, nmc_valid_connection_types)); + get_name_alias_toplevel (connection_type, NULL)); + } g_object_set (s_con, NM_SETTING_CONNECTION_ID, default_name, @@ -8523,26 +8289,8 @@ do_connection_load (NmCli *nmc, int argc, char **argv) return nmc->return_value; } -// FIXME: change the text when non-VPN connection types are supported -#define PROMPT_IMPORT_TYPE PROMPT_VPN_TYPE #define PROMPT_IMPORT_FILE N_("File to import: ") -static void -nmc_complete_vpn_service (const char *prefix) -{ - char **services; - char **candidate; - - services = nm_vpn_plugin_info_list_get_service_types (NULL, FALSE, TRUE); - for (candidate = services; *candidate; candidate++) { - if (!*prefix && g_str_has_prefix (*candidate, NM_DBUS_INTERFACE)) - continue; - if (!*prefix || matches (prefix, *candidate)) - g_print ("%s\n", *candidate); - } - g_strfreev (services); -} - static NMCResultCode do_connection_import (NmCli *nmc, int argc, char **argv) { @@ -8567,7 +8315,7 @@ do_connection_import (NmCli *nmc, int argc, char **argv) g_assert (!nmc->complete); if (nmc->ask) { - type_ask = nmc_readline (gettext (PROMPT_IMPORT_TYPE)); + type_ask = nmc_readline (gettext (NM_META_TEXT_PROMPT_VPN_TYPE)); filename_ask = nmc_readline (gettext (PROMPT_IMPORT_FILE)); type = type_ask = type_ask ? g_strstrip (type_ask) : NULL; filename = filename_ask = filename_ask ? g_strstrip (filename_ask) : NULL; @@ -8592,7 +8340,7 @@ do_connection_import (NmCli *nmc, int argc, char **argv) } if (argc == 1 && nmc->complete) - nmc_complete_vpn_service (*argv); + complete_option ((const NMMetaAbstractInfo *) nm_meta_property_info_vpn_service_type, *argv, NULL); if (!type) type = *argv; @@ -8867,8 +8615,8 @@ nmcli_con_tab_completion (const char *text, int start, int end) generator_func = gen_func_connection_names; } else if (g_strcmp0 (rl_prompt, PROMPT_ACTIVE_CONNECTIONS) == 0) { generator_func = gen_func_active_connection_names; - } else if (g_strcmp0 (rl_prompt, PROMPT_IMPORT_TYPE) == 0) { - generator_func = gen_func_vpn_types; + } else if (g_strcmp0 (rl_prompt, NM_META_TEXT_PROMPT_VPN_TYPE) == 0) { + return _meta_abstract_complete ((const NMMetaAbstractInfo *) nm_meta_property_info_vpn_service_type, text); } else if (g_strcmp0 (rl_prompt, PROMPT_IMPORT_FILE) == 0) { rl_attempted_completion_over = 0; rl_complete_with_tilde_expansion = 1; diff --git a/clients/cli/devices.c b/clients/cli/devices.c index 64a75a07d1..da5650f45e 100644 --- a/clients/cli/devices.c +++ b/clients/cli/devices.c @@ -208,7 +208,7 @@ const NmcMetaGenericInfo *const nmc_fields_dev_show_sections[] = { NMC_META_GENERIC_WITH_NESTED ("WIRED-PROPERTIES", nmc_fields_dev_show_wired_prop + 1), /* 4 */ NMC_META_GENERIC_WITH_NESTED ("WIMAX-PROPERTIES", nmc_fields_dev_show_wimax_prop + 1), /* 5 */ NMC_META_GENERIC_WITH_NESTED ("NSP", nmc_fields_dev_wimax_list + 1), /* 6 */ - NMC_META_GENERIC_WITH_NESTED ("IP4", nmc_fields_ip4_config + 1), /* 7 */ + NMC_META_GENERIC_WITH_NESTED ("IP4", metagen_ip4_config), /* 7 */ NMC_META_GENERIC_WITH_NESTED ("DHCP4", nmc_fields_dhcp4_config + 1), /* 8 */ NMC_META_GENERIC_WITH_NESTED ("IP6", nmc_fields_ip6_config + 1), /* 9 */ NMC_META_GENERIC_WITH_NESTED ("DHCP6", nmc_fields_dhcp6_config + 1), /* 10 */ @@ -245,9 +245,6 @@ const NmcMetaGenericInfo *const nmc_fields_dev_lldp_list[] = { #define NMC_FIELDS_DEV_LLDP_LIST_COMMON "DEVICE,CHASSIS-ID,PORT-ID,PORT-DESCRIPTION,SYSTEM-NAME,SYSTEM-DESCRIPTION," \ "SYSTEM-CAPABILITIES" -/* glib main loop variable - defined in nmcli.c */ -extern GMainLoop *loop; - static guint progress_id = 0; /* ID of event source for displaying progress */ static void @@ -450,7 +447,6 @@ usage_device_lldp (void) "used to list neighbors for a particular interface.\n\n")); } -/* quit main loop */ static void quit (void) { @@ -459,7 +455,7 @@ quit (void) nmc_terminal_erase_line (); } - g_main_loop_quit (loop); /* quit main loop */ + g_main_loop_quit (loop); } static int @@ -1273,7 +1269,7 @@ show_device_info (NMDevice *device, NmCli *nmc) /* IP4 */ if (cfg4 && !strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[7]->name)) - was_output = print_ip4_config (cfg4, &nmc->nmc_config, nmc_fields_dev_show_sections[7]->name, section_fld); + was_output = print_ip4_config (cfg4, &nmc->nmc_config, section_fld); /* DHCP4 */ if (dhcp4 && !strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[8]->name)) @@ -3110,7 +3106,7 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv) if (ap_flags & NM_802_11_AP_FLAGS_PRIVACY) { /* Ask for missing password when one is expected and '--ask' is used */ if (!password && nmc->ask) - password = passwd_ask = nmc_readline_echo (nmc->show_secrets, _("Password: ")); + password = passwd_ask = nmc_readline_echo (nmc->nmc_config.show_secrets, _("Password: ")); if (password) { if (!connection) @@ -3408,7 +3404,7 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv) next_arg (nmc, &argc, &argv, NULL); } - show_password = nmc->show_secrets || show_password; + show_password = nmc->nmc_config.show_secrets || show_password; if (nmc->complete) return nmc->return_value; diff --git a/clients/cli/general.c b/clients/cli/general.c index fe29e9947e..84c853aef0 100644 --- a/clients/cli/general.c +++ b/clients/cli/general.c @@ -35,20 +35,230 @@ #include "devices.h" #include "connections.h" -static const NmcMetaGenericInfo *const nmc_fields_nm_status[] = { - NMC_META_GENERIC ("RUNNING"), /* 0 */ - NMC_META_GENERIC ("VERSION"), /* 1 */ - NMC_META_GENERIC ("STATE"), /* 2 */ - NMC_META_GENERIC ("STARTUP"), /* 3 */ - NMC_META_GENERIC ("CONNECTIVITY"), /* 4 */ - NMC_META_GENERIC ("NETWORKING"), /* 5 */ - NMC_META_GENERIC ("WIFI-HW"), /* 6 */ - NMC_META_GENERIC ("WIFI"), /* 7 */ - NMC_META_GENERIC ("WWAN-HW"), /* 8 */ - NMC_META_GENERIC ("WWAN"), /* 9 */ - NMC_META_GENERIC ("WIMAX-HW"), /* 10 */ - NMC_META_GENERIC ("WIMAX"), /* 11 */ - NULL, +/*****************************************************************************/ + +NM_UTILS_LOOKUP_STR_DEFINE_STATIC (nm_state_to_string_no_l10n, NMState, + NM_UTILS_LOOKUP_DEFAULT (N_("unknown")), + NM_UTILS_LOOKUP_ITEM (NM_STATE_ASLEEP, N_("asleep")), + NM_UTILS_LOOKUP_ITEM (NM_STATE_CONNECTING, N_("connecting")), + NM_UTILS_LOOKUP_ITEM (NM_STATE_CONNECTED_LOCAL, N_("connected (local only)")), + NM_UTILS_LOOKUP_ITEM (NM_STATE_CONNECTED_SITE, N_("connected (site only)")), + NM_UTILS_LOOKUP_ITEM (NM_STATE_CONNECTED_GLOBAL, N_("connected")), + NM_UTILS_LOOKUP_ITEM (NM_STATE_DISCONNECTING, N_("disconnecting")), + NM_UTILS_LOOKUP_ITEM (NM_STATE_DISCONNECTED, N_("disconnected")), + NM_UTILS_LOOKUP_ITEM_IGNORE (NM_STATE_UNKNOWN), +); + +static const char * +nm_state_to_string (NMState state) +{ + return _(nm_state_to_string_no_l10n (state)); +} + +static NMMetaTermColor +state_to_color (NMState state) +{ + switch (state) { + case NM_STATE_CONNECTING: + return NM_META_TERM_COLOR_YELLOW; + case NM_STATE_CONNECTED_LOCAL: + case NM_STATE_CONNECTED_SITE: + case NM_STATE_CONNECTED_GLOBAL: + return NM_META_TERM_COLOR_GREEN; + case NM_STATE_DISCONNECTING: + return NM_META_TERM_COLOR_YELLOW; + case NM_STATE_ASLEEP: + case NM_STATE_DISCONNECTED: + return NM_META_TERM_COLOR_RED; + default: + return NM_META_TERM_COLOR_NORMAL; + } +} + +NM_UTILS_LOOKUP_STR_DEFINE_STATIC (nm_connectivity_to_string_no_l10n, NMConnectivityState, + NM_UTILS_LOOKUP_DEFAULT (N_("unknown")), + NM_UTILS_LOOKUP_ITEM (NM_CONNECTIVITY_NONE, N_("none")), + NM_UTILS_LOOKUP_ITEM (NM_CONNECTIVITY_PORTAL, N_("portal")), + NM_UTILS_LOOKUP_ITEM (NM_CONNECTIVITY_LIMITED, N_("limited")), + NM_UTILS_LOOKUP_ITEM (NM_CONNECTIVITY_FULL, N_("full")), + NM_UTILS_LOOKUP_ITEM_IGNORE (NM_CONNECTIVITY_UNKNOWN), +); + +static const char * +nm_connectivity_to_string (NMConnectivityState connectivity) +{ + return _(nm_connectivity_to_string_no_l10n (connectivity)); +} + +static NMMetaTermColor +connectivity_to_color (NMConnectivityState connectivity) +{ + switch (connectivity) { + case NM_CONNECTIVITY_NONE: + return NM_META_TERM_COLOR_RED; + case NM_CONNECTIVITY_PORTAL: + case NM_CONNECTIVITY_LIMITED: + return NM_META_TERM_COLOR_YELLOW; + case NM_CONNECTIVITY_FULL: + return NM_META_TERM_COLOR_GREEN; + default: + return NM_META_TERM_COLOR_NORMAL; + } +} + +static const char * +permission_to_string (NMClientPermission perm) +{ + switch (perm) { + case NM_CLIENT_PERMISSION_ENABLE_DISABLE_NETWORK: + return NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK; + case NM_CLIENT_PERMISSION_ENABLE_DISABLE_WIFI: + return NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI; + case NM_CLIENT_PERMISSION_ENABLE_DISABLE_WWAN: + return NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN; + case NM_CLIENT_PERMISSION_ENABLE_DISABLE_WIMAX: + return NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX; + case NM_CLIENT_PERMISSION_SLEEP_WAKE: + return NM_AUTH_PERMISSION_SLEEP_WAKE; + case NM_CLIENT_PERMISSION_NETWORK_CONTROL: + return NM_AUTH_PERMISSION_NETWORK_CONTROL; + case NM_CLIENT_PERMISSION_WIFI_SHARE_PROTECTED: + return NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED; + case NM_CLIENT_PERMISSION_WIFI_SHARE_OPEN: + return NM_AUTH_PERMISSION_WIFI_SHARE_OPEN; + case NM_CLIENT_PERMISSION_SETTINGS_MODIFY_SYSTEM: + return NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM; + case NM_CLIENT_PERMISSION_SETTINGS_MODIFY_OWN: + return NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN; + case NM_CLIENT_PERMISSION_SETTINGS_MODIFY_HOSTNAME: + return NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME; + case NM_CLIENT_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS: + return NM_AUTH_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS; + case NM_CLIENT_PERMISSION_RELOAD: + return NM_AUTH_PERMISSION_RELOAD; + case NM_CLIENT_PERMISSION_CHECKPOINT_ROLLBACK: + return NM_AUTH_PERMISSION_CHECKPOINT_ROLLBACK; + case NM_CLIENT_PERMISSION_ENABLE_DISABLE_STATISTICS: + return NM_AUTH_PERMISSION_ENABLE_DISABLE_STATISTICS; + default: + return _("unknown"); + } +} + +NM_UTILS_LOOKUP_STR_DEFINE_STATIC (permission_result_to_string_no_l10n, NMClientPermissionResult, + NM_UTILS_LOOKUP_DEFAULT (N_("unknown")), + NM_UTILS_LOOKUP_ITEM (NM_CLIENT_PERMISSION_RESULT_YES, N_("yes")), + NM_UTILS_LOOKUP_ITEM (NM_CLIENT_PERMISSION_RESULT_NO, N_("no")), + NM_UTILS_LOOKUP_ITEM (NM_CLIENT_PERMISSION_RESULT_AUTH, N_("auth")), + NM_UTILS_LOOKUP_ITEM_IGNORE (NM_CLIENT_PERMISSION_RESULT_UNKNOWN), +); + +_NM_UTILS_LOOKUP_DEFINE (static, permission_result_to_color, NMClientPermissionResult, NMMetaTermColor, + NM_UTILS_LOOKUP_DEFAULT (NM_META_TERM_COLOR_NORMAL), + NM_UTILS_LOOKUP_ITEM (NM_CLIENT_PERMISSION_RESULT_YES, NM_META_TERM_COLOR_GREEN), + NM_UTILS_LOOKUP_ITEM (NM_CLIENT_PERMISSION_RESULT_NO, NM_META_TERM_COLOR_RED), + NM_UTILS_LOOKUP_ITEM (NM_CLIENT_PERMISSION_RESULT_AUTH, NM_META_TERM_COLOR_YELLOW), + NM_UTILS_LOOKUP_ITEM_IGNORE (NM_CLIENT_PERMISSION_RESULT_UNKNOWN), +); + +/*****************************************************************************/ + +static const NmcMetaGenericInfo *const metagen_general_status[]; + +static gconstpointer +_metagen_general_status_get_fcn (const NMMetaEnvironment *environment, + gpointer environment_user_data, + const NmcMetaGenericInfo *info, + gpointer target, + NMMetaAccessorGetType get_type, + NMMetaAccessorGetFlags get_flags, + NMMetaAccessorGetOutFlags *out_flags, + gpointer *out_to_free) +{ + NmCli *nmc = target; + const char *value; + gboolean v_bool; + NMState state; + NMConnectivityState connectivity; + + switch (info->info_type) { + case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_RUNNING: + NMC_HANDLE_TERMFORMAT (NM_META_TERM_COLOR_NORMAL); + value = N_("running"); + goto translate_and_out; + case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_VERSION: + NMC_HANDLE_TERMFORMAT (NM_META_TERM_COLOR_NORMAL); + value = nm_client_get_version (nmc->client); + goto clone_and_out; + case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_STATE: + state = nm_client_get_state (nmc->client); + NMC_HANDLE_TERMFORMAT (state_to_color (state)); + value = nm_state_to_string_no_l10n (state); + goto translate_and_out; + case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_STARTUP: + v_bool = nm_client_get_startup (nmc->client); + NMC_HANDLE_TERMFORMAT (v_bool ? NM_META_TERM_COLOR_YELLOW : NM_META_TERM_COLOR_GREEN); + value = v_bool ? N_("starting") : N_("started"); + goto translate_and_out; + case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_CONNECTIVITY: + connectivity = nm_client_get_connectivity (nmc->client); + NMC_HANDLE_TERMFORMAT (connectivity_to_color (connectivity)); + value = nm_connectivity_to_string_no_l10n (connectivity); + goto translate_and_out; + case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_NETWORKING: + v_bool = nm_client_networking_get_enabled (nmc->client); + goto enabled_out; + case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WIFI_HW: + v_bool = nm_client_wireless_hardware_get_enabled (nmc->client); + goto enabled_out; + case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WIFI: + v_bool = nm_client_wireless_get_enabled (nmc->client); + goto enabled_out; + case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WWAN_HW: + v_bool = nm_client_wwan_hardware_get_enabled (nmc->client); + goto enabled_out; + case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WWAN: + v_bool = nm_client_wwan_get_enabled (nmc->client); + goto enabled_out; + case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WIMAX_HW: + case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WIMAX: + /* deprected fields. Don't return anything. */ + return NULL; + default: + break; + } + + g_return_val_if_reached (NULL); + +enabled_out: + NMC_HANDLE_TERMFORMAT (v_bool ? NM_META_TERM_COLOR_GREEN : NM_META_TERM_COLOR_RED); + value = v_bool ? N_("enabled") : N_("disabled"); + goto translate_and_out; + +clone_and_out: + return (*out_to_free = g_strdup (value)); + +translate_and_out: + if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY) + return _(value); + return value; +} + +static const NmcMetaGenericInfo *const metagen_general_status[_NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_NUM + 1] = { +#define _METAGEN_GENERAL_STATUS(type, name) \ + [type] = NMC_META_GENERIC(name, .info_type = type, .get_fcn = _metagen_general_status_get_fcn) + _METAGEN_GENERAL_STATUS (NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_RUNNING, "RUNNING"), + _METAGEN_GENERAL_STATUS (NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_VERSION, "VERSION"), + _METAGEN_GENERAL_STATUS (NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_STATE, "STATE"), + _METAGEN_GENERAL_STATUS (NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_STARTUP, "STARTUP"), + _METAGEN_GENERAL_STATUS (NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_CONNECTIVITY, "CONNECTIVITY"), + _METAGEN_GENERAL_STATUS (NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_NETWORKING, "NETWORKING"), + _METAGEN_GENERAL_STATUS (NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WIFI_HW, "WIFI-HW"), + _METAGEN_GENERAL_STATUS (NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WIFI, "WIFI"), + _METAGEN_GENERAL_STATUS (NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WWAN_HW, "WWAN-HW"), + _METAGEN_GENERAL_STATUS (NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WWAN, "WWAN"), + _METAGEN_GENERAL_STATUS (NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WIMAX_HW, "WIMAX-HW"), + _METAGEN_GENERAL_STATUS (NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WIMAX, "WIMAX"), }; #define NMC_FIELDS_NM_STATUS_ALL "RUNNING,VERSION,STATE,STARTUP,CONNECTIVITY,NETWORKING,WIFI-HW,WIFI,WWAN-HW,WWAN" #define NMC_FIELDS_NM_STATUS_SWITCH "NETWORKING,WIFI-HW,WIFI,WWAN-HW,WWAN" @@ -60,29 +270,96 @@ static const NmcMetaGenericInfo *const nmc_fields_nm_status[] = { #define NMC_FIELDS_NM_WIMAX "WIMAX" #define NMC_FIELDS_NM_CONNECTIVITY "CONNECTIVITY" +/*****************************************************************************/ -/* Available fields for 'general permissions' */ -static const NmcMetaGenericInfo *const nmc_fields_nm_permissions[] = { - NMC_META_GENERIC ("PERMISSION"), /* 0 */ - NMC_META_GENERIC ("VALUE"), /* 1 */ - NULL, +static gconstpointer +_metagen_general_permissions_get_fcn (const NMMetaEnvironment *environment, + gpointer environment_user_data, + const NmcMetaGenericInfo *info, + gpointer target, + NMMetaAccessorGetType get_type, + NMMetaAccessorGetFlags get_flags, + NMMetaAccessorGetOutFlags *out_flags, + gpointer *out_to_free) +{ + NMClientPermission perm = GPOINTER_TO_UINT (target); + NmCli *nmc = environment_user_data; + NMClientPermissionResult perm_result; + const char *s; + + switch (info->info_type) { + case NMC_GENERIC_INFO_TYPE_GENERAL_PERMISSIONS_PERMISSION: + NMC_HANDLE_TERMFORMAT (NM_META_TERM_COLOR_NORMAL); + return permission_to_string (perm); + case NMC_GENERIC_INFO_TYPE_GENERAL_PERMISSIONS_VALUE: + perm_result = nm_client_get_permission_result (nmc->client, perm); + NMC_HANDLE_TERMFORMAT (permission_result_to_color (perm_result)); + s = permission_result_to_string_no_l10n (perm_result); + if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY) + return _(s); + return s; + default: + break; + } + + g_return_val_if_reached (NULL); +} + +static const NmcMetaGenericInfo *const metagen_general_permissions[_NMC_GENERIC_INFO_TYPE_GENERAL_PERMISSIONS_NUM + 1] = { +#define _METAGEN_GENERAL_PERMISSIONS(type, name) \ + [type] = NMC_META_GENERIC(name, .info_type = type, .get_fcn = _metagen_general_permissions_get_fcn) + _METAGEN_GENERAL_PERMISSIONS (NMC_GENERIC_INFO_TYPE_GENERAL_PERMISSIONS_PERMISSION, "PERMISSION"), + _METAGEN_GENERAL_PERMISSIONS (NMC_GENERIC_INFO_TYPE_GENERAL_PERMISSIONS_VALUE, "VALUE"), }; -#define NMC_FIELDS_NM_PERMISSIONS_ALL "PERMISSION,VALUE" -#define NMC_FIELDS_NM_PERMISSIONS_COMMON "PERMISSION,VALUE" -/* Available fields for 'general logging' */ -static const NmcMetaGenericInfo *const nmc_fields_nm_logging[] = { - NMC_META_GENERIC ("LEVEL"), /* 0 */ - NMC_META_GENERIC ("DOMAINS"), /* 1 */ - NULL, +/*****************************************************************************/ + +typedef struct { + bool initialized; + char **level; + char **domains; +} GetGeneralLoggingData; + +static gconstpointer +_metagen_general_logging_get_fcn (const NMMetaEnvironment *environment, + gpointer environment_user_data, + const NmcMetaGenericInfo *info, + gpointer target, + NMMetaAccessorGetType get_type, + NMMetaAccessorGetFlags get_flags, + NMMetaAccessorGetOutFlags *out_flags, + gpointer *out_to_free) +{ + NmCli *nmc = environment_user_data; + GetGeneralLoggingData *d = target; + + nm_assert (info->info_type < _NMC_GENERIC_INFO_TYPE_GENERAL_LOGGING_NUM); + + NMC_HANDLE_TERMFORMAT (NM_META_TERM_COLOR_NORMAL); + + if (!d->initialized) { + d->initialized = TRUE; + if (!nm_client_get_logging (nmc->client, + d->level, + d->domains, + NULL)) + return NULL; + } + + if (info->info_type == NMC_GENERIC_INFO_TYPE_GENERAL_LOGGING_LEVEL) + return *d->level; + else + return *d->domains; +} + +static const NmcMetaGenericInfo *const metagen_general_logging[_NMC_GENERIC_INFO_TYPE_GENERAL_LOGGING_NUM + 1] = { +#define _METAGEN_GENERAL_LOGGING(type, name) \ + [type] = NMC_META_GENERIC(name, .info_type = type, .get_fcn = _metagen_general_logging_get_fcn) + _METAGEN_GENERAL_LOGGING (NMC_GENERIC_INFO_TYPE_GENERAL_LOGGING_LEVEL, "LEVEL"), + _METAGEN_GENERAL_LOGGING (NMC_GENERIC_INFO_TYPE_GENERAL_LOGGING_DOMAINS, "DOMAINS"), }; -#define NMC_FIELDS_NM_LOGGING_ALL "LEVEL,DOMAINS" -#define NMC_FIELDS_NM_LOGGING_COMMON "LEVEL,DOMAINS" - - -/* glib main loop variable - defined in nmcli.c */ -extern GMainLoop *loop; +/*****************************************************************************/ static void usage_general (void) @@ -223,107 +500,19 @@ usage_monitor (void) "Prints a line whenever a change occurs in NetworkManager\n\n")); } -/* quit main loop */ static void quit (void) { - g_main_loop_quit (loop); /* quit main loop */ -} - -static const char * -nm_state_to_string (NMState state) -{ - switch (state) { - case NM_STATE_ASLEEP: - return _("asleep"); - case NM_STATE_CONNECTING: - return _("connecting"); - case NM_STATE_CONNECTED_LOCAL: - return _("connected (local only)"); - case NM_STATE_CONNECTED_SITE: - return _("connected (site only)"); - case NM_STATE_CONNECTED_GLOBAL: - return _("connected"); - case NM_STATE_DISCONNECTING: - return _("disconnecting"); - case NM_STATE_DISCONNECTED: - return _("disconnected"); - case NM_STATE_UNKNOWN: - default: - return _("unknown"); - } -} - -static NMMetaTermColor -state_to_color (NMState state) -{ - switch (state) { - case NM_STATE_CONNECTING: - return NM_META_TERM_COLOR_YELLOW; - case NM_STATE_CONNECTED_LOCAL: - case NM_STATE_CONNECTED_SITE: - case NM_STATE_CONNECTED_GLOBAL: - return NM_META_TERM_COLOR_GREEN; - case NM_STATE_DISCONNECTING: - return NM_META_TERM_COLOR_YELLOW; - case NM_STATE_ASLEEP: - case NM_STATE_DISCONNECTED: - return NM_META_TERM_COLOR_RED; - default: - return NM_META_TERM_COLOR_NORMAL; - } -} - -static const char * -nm_connectivity_to_string (NMConnectivityState connectivity) -{ - switch (connectivity) { - case NM_CONNECTIVITY_NONE: - return _("none"); - case NM_CONNECTIVITY_PORTAL: - return _("portal"); - case NM_CONNECTIVITY_LIMITED: - return _("limited"); - case NM_CONNECTIVITY_FULL: - return _("full"); - case NM_CONNECTIVITY_UNKNOWN: - default: - return _("unknown"); - } -} - -static NMMetaTermColor -connectivity_to_color (NMConnectivityState connectivity) -{ - switch (connectivity) { - case NM_CONNECTIVITY_NONE: - return NM_META_TERM_COLOR_RED; - case NM_CONNECTIVITY_PORTAL: - case NM_CONNECTIVITY_LIMITED: - return NM_META_TERM_COLOR_YELLOW; - case NM_CONNECTIVITY_FULL: - return NM_META_TERM_COLOR_GREEN; - default: - return NM_META_TERM_COLOR_NORMAL; - } + g_main_loop_quit (loop); } static gboolean show_nm_status (NmCli *nmc, const char *pretty_header_name, const char *print_flds) { - gboolean startup = FALSE; - NMState state = NM_STATE_UNKNOWN; - NMConnectivityState connectivity = NM_CONNECTIVITY_UNKNOWN; - gboolean net_enabled; - gboolean wireless_hw_enabled, wireless_enabled; - gboolean wwan_hw_enabled, wwan_enabled; - GError *error = NULL; + gs_free_error GError *error = NULL; const char *fields_str; const char *fields_all = print_flds ? print_flds : NMC_FIELDS_NM_STATUS_ALL; const char *fields_common = print_flds ? print_flds : NMC_FIELDS_NM_STATUS_COMMON; - const NMMetaAbstractInfo *const*tmpl; - NmcOutputField *arr; - NMC_OUTPUT_DATA_DEFINE_SCOPED (out); if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0) fields_str = fields_common; @@ -332,57 +521,16 @@ show_nm_status (NmCli *nmc, const char *pretty_header_name, const char *print_fl else fields_str = nmc->required_fields; - tmpl = (const NMMetaAbstractInfo *const*) nmc_fields_nm_status; - out_indices = parse_output_fields (fields_str, tmpl, FALSE, NULL, &error); - - if (error) { + if (!nmc_print (&nmc->nmc_config, + (gpointer[]) { nmc, NULL }, + pretty_header_name ?: N_("NetworkManager status"), + (const NMMetaAbstractInfo *const*) metagen_general_status, + fields_str, + &error)) { g_string_printf (nmc->return_text, _("Error: only these fields are allowed: %s"), fields_all); - g_error_free (error); nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; return FALSE; } - - state = nm_client_get_state (nmc->client); - startup = nm_client_get_startup (nmc->client); - connectivity = nm_client_get_connectivity (nmc->client); - net_enabled = nm_client_networking_get_enabled (nmc->client); - wireless_hw_enabled = nm_client_wireless_hardware_get_enabled (nmc->client); - wireless_enabled = nm_client_wireless_get_enabled (nmc->client); - wwan_hw_enabled = nm_client_wwan_hardware_get_enabled (nmc->client); - wwan_enabled = nm_client_wwan_get_enabled (nmc->client); - - arr = nmc_dup_fields_array (tmpl, NMC_OF_FLAG_MAIN_HEADER_ADD | NMC_OF_FLAG_FIELD_NAMES); - g_ptr_array_add (out.output_data, arr); - - arr = nmc_dup_fields_array (tmpl, 0); - set_val_strc (arr, 0, _("running")); - set_val_strc (arr, 1, nm_client_get_version (nmc->client)); - set_val_strc (arr, 2, nm_state_to_string (state)); - set_val_strc (arr, 3, startup ? _("starting") : _("started")); - set_val_strc (arr, 4, nm_connectivity_to_string (connectivity)); - set_val_strc (arr, 5, net_enabled ? _("enabled") : _("disabled")); - set_val_strc (arr, 6, wireless_hw_enabled ? _("enabled") : _("disabled")); - set_val_strc (arr, 7, wireless_enabled ? _("enabled") : _("disabled")); - set_val_strc (arr, 8, wwan_hw_enabled ? _("enabled") : _("disabled")); - set_val_strc (arr, 9, wwan_enabled ? _("enabled") : _("disabled")); - - /* Set colors */ - arr[2].color = state_to_color (state); - arr[3].color = startup ? NM_META_TERM_COLOR_YELLOW : NM_META_TERM_COLOR_GREEN; - arr[4].color = connectivity_to_color (connectivity); - arr[5].color = net_enabled ? NM_META_TERM_COLOR_GREEN : NM_META_TERM_COLOR_RED; - arr[6].color = wireless_hw_enabled ? NM_META_TERM_COLOR_GREEN : NM_META_TERM_COLOR_RED; - arr[7].color = wireless_enabled ? NM_META_TERM_COLOR_GREEN : NM_META_TERM_COLOR_RED; - arr[8].color = wwan_hw_enabled ? NM_META_TERM_COLOR_GREEN : NM_META_TERM_COLOR_RED; - arr[9].color = wwan_enabled ? NM_META_TERM_COLOR_GREEN : NM_META_TERM_COLOR_RED; - - g_ptr_array_add (out.output_data, arr); - - print_data_prepare_width (out.output_data); - print_data (&nmc->nmc_config, out_indices, - pretty_header_name ?: _("NetworkManager status"), - 0, &out); - return TRUE; } @@ -397,60 +545,6 @@ do_general_status (NmCli *nmc, int argc, char **argv) return nmc->return_value; } -static const char * -permission_to_string (NMClientPermission perm) -{ - switch (perm) { - case NM_CLIENT_PERMISSION_ENABLE_DISABLE_NETWORK: - return NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK; - case NM_CLIENT_PERMISSION_ENABLE_DISABLE_WIFI: - return NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI; - case NM_CLIENT_PERMISSION_ENABLE_DISABLE_WWAN: - return NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN; - case NM_CLIENT_PERMISSION_ENABLE_DISABLE_WIMAX: - return NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX; - case NM_CLIENT_PERMISSION_SLEEP_WAKE: - return NM_AUTH_PERMISSION_SLEEP_WAKE; - case NM_CLIENT_PERMISSION_NETWORK_CONTROL: - return NM_AUTH_PERMISSION_NETWORK_CONTROL; - case NM_CLIENT_PERMISSION_WIFI_SHARE_PROTECTED: - return NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED; - case NM_CLIENT_PERMISSION_WIFI_SHARE_OPEN: - return NM_AUTH_PERMISSION_WIFI_SHARE_OPEN; - case NM_CLIENT_PERMISSION_SETTINGS_MODIFY_SYSTEM: - return NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM; - case NM_CLIENT_PERMISSION_SETTINGS_MODIFY_OWN: - return NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN; - case NM_CLIENT_PERMISSION_SETTINGS_MODIFY_HOSTNAME: - return NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME; - case NM_CLIENT_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS: - return NM_AUTH_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS; - case NM_CLIENT_PERMISSION_RELOAD: - return NM_AUTH_PERMISSION_RELOAD; - case NM_CLIENT_PERMISSION_CHECKPOINT_ROLLBACK: - return NM_AUTH_PERMISSION_CHECKPOINT_ROLLBACK; - case NM_CLIENT_PERMISSION_ENABLE_DISABLE_STATISTICS: - return NM_AUTH_PERMISSION_ENABLE_DISABLE_STATISTICS; - default: - return _("unknown"); - } -} - -static const char * -permission_result_to_string (NMClientPermissionResult perm_result) -{ - switch (perm_result) { - case NM_CLIENT_PERMISSION_RESULT_YES: - return _("yes"); - case NM_CLIENT_PERMISSION_RESULT_NO: - return _("no"); - case NM_CLIENT_PERMISSION_RESULT_AUTH: - return _("auth"); - default: - return _("unknown"); - } -} - static gboolean timeout_cb (gpointer user_data) { @@ -466,50 +560,31 @@ static int print_permissions (void *user_data) { NmCli *nmc = user_data; + gs_free_error GError *error = NULL; + const char *fields_str = NULL; NMClientPermission perm; - GError *error = NULL; - const char *fields_str; - const char *fields_all = NMC_FIELDS_NM_PERMISSIONS_ALL; - const char *fields_common = NMC_FIELDS_NM_PERMISSIONS_COMMON; - const NMMetaAbstractInfo *const*tmpl; - NmcOutputField *arr; - NMC_OUTPUT_DATA_DEFINE_SCOPED (out); + guint i; + gpointer permissions[NM_CLIENT_PERMISSION_LAST + 1]; - if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0) - fields_str = fields_common; - else if (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0) - fields_str = fields_all; - else + if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0) { + } else if (strcasecmp (nmc->required_fields, "all") == 0) { + } else fields_str = nmc->required_fields; - tmpl = (const NMMetaAbstractInfo *const*) nmc_fields_nm_permissions; - out_indices = parse_output_fields (fields_str, tmpl, FALSE, NULL, &error); + for (i = 0, perm = NM_CLIENT_PERMISSION_NONE + 1; perm <= NM_CLIENT_PERMISSION_LAST; perm++) + permissions[i++] = GINT_TO_POINTER (perm); + permissions[i++] = NULL; - if (error) { + if (!nmc_print (&nmc->nmc_config, + permissions, + _("NetworkManager permissions"), + (const NMMetaAbstractInfo *const*) metagen_general_permissions, + fields_str, + &error)) { g_string_printf (nmc->return_text, _("Error: 'general permissions': %s"), error->message); - g_error_free (error); nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return FALSE; } - arr = nmc_dup_fields_array (tmpl, NMC_OF_FLAG_MAIN_HEADER_ADD | NMC_OF_FLAG_FIELD_NAMES); - g_ptr_array_add (out.output_data, arr); - - - for (perm = NM_CLIENT_PERMISSION_NONE + 1; perm <= NM_CLIENT_PERMISSION_LAST; perm++) { - NMClientPermissionResult perm_result = nm_client_get_permission_result (nmc->client, perm); - - arr = nmc_dup_fields_array (tmpl, 0); - set_val_strc (arr, 0, permission_to_string (perm)); - set_val_strc (arr, 1, permission_result_to_string (perm_result)); - g_ptr_array_add (out.output_data, arr); - } - print_data_prepare_width (out.output_data); - print_data (&nmc->nmc_config, - out_indices, - _("NetworkManager permissions"), - 0, &out); - quit (); return G_SOURCE_REMOVE; } @@ -575,58 +650,32 @@ do_general_permissions (NmCli *nmc, int argc, char **argv) return nmc->return_value; } -static gboolean +static void show_general_logging (NmCli *nmc) { - char *level = NULL; - char *domains = NULL; - GError *error = NULL; - const char *fields_str; - const char *fields_all = NMC_FIELDS_NM_LOGGING_ALL; - const char *fields_common = NMC_FIELDS_NM_LOGGING_COMMON; - const NMMetaAbstractInfo *const*tmpl; - NmcOutputField *arr; - NMC_OUTPUT_DATA_DEFINE_SCOPED (out); + gs_free char *level_cache = NULL; + gs_free char *domains_cache = NULL; + gs_free GError *error = NULL; + const char *fields_str = NULL; + GetGeneralLoggingData d = { + .level = &level_cache, + .domains = &domains_cache, + }; - if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0) - fields_str = fields_common; - else if (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0) - fields_str = fields_all; - else + if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0) { + } else if (strcasecmp (nmc->required_fields, "all") == 0) { + } else fields_str = nmc->required_fields; - tmpl = (const NMMetaAbstractInfo *const*) nmc_fields_nm_logging; - out_indices = parse_output_fields (fields_str, tmpl, FALSE, NULL, &error); - - if (error) { + if (!nmc_print (&nmc->nmc_config, + (gpointer const []) { &d, NULL }, + _("NetworkManager logging"), + (const NMMetaAbstractInfo *const*) metagen_general_logging, + fields_str, + &error)) { g_string_printf (nmc->return_text, _("Error: 'general logging': %s"), error->message); - g_error_free (error); nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return FALSE; } - - nm_client_get_logging (nmc->client, &level, &domains, &error); - if (error) { - g_string_printf (nmc->return_text, _("Error: %s."), error->message); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - g_error_free (error); - return FALSE; - } - - arr = nmc_dup_fields_array (tmpl, NMC_OF_FLAG_MAIN_HEADER_ADD | NMC_OF_FLAG_FIELD_NAMES); - g_ptr_array_add (out.output_data, arr); - - arr = nmc_dup_fields_array (tmpl, 0); - set_val_str (arr, 0, level); - set_val_str (arr, 1, domains); - g_ptr_array_add (out.output_data, arr); - - print_data_prepare_width (out.output_data); - print_data (&nmc->nmc_config, out_indices, - _("NetworkManager logging"), - 0, &out); - - return TRUE; } static void @@ -865,7 +914,7 @@ do_networking_connectivity (NmCli *nmc, int argc, char **argv) if (!argc) { /* no arguments -> get current state */ - nmc_switch_show (nmc, NMC_FIELDS_NM_CONNECTIVITY, _("Connectivity")); + nmc_switch_show (nmc, NMC_FIELDS_NM_CONNECTIVITY, N_("Connectivity")); } else if (matches (*argv, "check")) { gs_free_error GError *error = NULL; @@ -877,7 +926,7 @@ do_networking_connectivity (NmCli *nmc, int argc, char **argv) g_string_printf (nmc->return_text, _("Error: %s."), error->message); nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; } else - nmc_switch_show (nmc, NMC_FIELDS_NM_CONNECTIVITY, _("Connectivity")); + nmc_switch_show (nmc, NMC_FIELDS_NM_CONNECTIVITY, N_("Connectivity")); } else { usage_networking (); g_string_printf (nmc->return_text, _("Error: 'networking' command '%s' is not valid."), *argv); @@ -894,7 +943,7 @@ do_networking_show (NmCli *nmc, int argc, char **argv) if (nmc->complete) return nmc->return_value; - nmc_switch_show (nmc, NMC_FIELDS_NM_NETWORKING, _("Networking")); + nmc_switch_show (nmc, NMC_FIELDS_NM_NETWORKING, N_("Networking")); return nmc->return_value; } @@ -929,7 +978,7 @@ do_radio_all (NmCli *nmc, int argc, char **argv) return nmc->return_value; /* no argument, show all radio switches */ - show_nm_status (nmc, _("Radio switches"), NMC_FIELDS_NM_STATUS_RADIO); + show_nm_status (nmc, N_("Radio switches"), NMC_FIELDS_NM_STATUS_RADIO); } else { if (nmc->complete) { if (argc == 1) @@ -959,7 +1008,7 @@ do_radio_wifi (NmCli *nmc, int argc, char **argv) return nmc->return_value; /* no argument, show current WiFi state */ - nmc_switch_show (nmc, NMC_FIELDS_NM_WIFI, _("Wi-Fi radio switch")); + nmc_switch_show (nmc, NMC_FIELDS_NM_WIFI, N_("Wi-Fi radio switch")); } else { if (nmc->complete) { if (argc == 1) @@ -986,7 +1035,7 @@ do_radio_wwan (NmCli *nmc, int argc, char **argv) return nmc->return_value; /* no argument, show current WWAN (mobile broadband) state */ - nmc_switch_show (nmc, NMC_FIELDS_NM_WWAN, _("WWAN radio switch")); + nmc_switch_show (nmc, NMC_FIELDS_NM_WWAN, N_("WWAN radio switch")); } else { if (nmc->complete) { if (argc == 1) diff --git a/clients/cli/nmcli.c b/clients/cli/nmcli.c index dcb86fe1dc..4420291719 100644 --- a/clients/cli/nmcli.c +++ b/clients/cli/nmcli.c @@ -75,8 +75,6 @@ complete_field_setting (GHashTable *h, NMMetaSettingType setting_type) guint i; for (i = 0; i < setting_info->properties_num; i++) { - if (setting_info->properties[i].is_name) - continue; g_hash_table_add (h, g_strdup_printf ("%s.%s", setting_info->general->setting_name, setting_info->properties[i].property_name)); @@ -119,7 +117,7 @@ complete_fields (const char *prefix) h = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - complete_field (h, nmc_fields_ip4_config); + complete_field (h, metagen_ip4_config); complete_field (h, nmc_fields_dhcp4_config); complete_field (h, nmc_fields_ip6_config); complete_field (h, nmc_fields_dhcp6_config); @@ -538,12 +536,11 @@ nmc_init (NmCli *nmc) nmc->required_fields = NULL; nmc->ask = FALSE; nmc->complete = FALSE; - nmc->show_secrets = FALSE; + nmc->nmc_config_mutable.show_secrets = FALSE; nmc->nmc_config_mutable.use_colors = NMC_USE_COLOR_AUTO; nmc->nmc_config_mutable.in_editor = FALSE; nmc->editor_status_line = FALSE; nmc->editor_save_confirmation = TRUE; - nmc->editor_show_secrets = FALSE; nmc->editor_prompt_color = NM_META_TERM_COLOR_NORMAL; } diff --git a/clients/cli/nmcli.h b/clients/cli/nmcli.h index c3949b5f68..839a49bbc0 100644 --- a/clients/cli/nmcli.h +++ b/clients/cli/nmcli.h @@ -32,6 +32,8 @@ typedef gpointer NMPolkitListener; #endif +typedef char *(*NmcCompEntryFunc) (const char *, int); + /* nmcli exit codes */ typedef enum { /* Indicates successful execution */ @@ -111,9 +113,10 @@ typedef enum { typedef struct _NmcConfig { NMCPrintOutput print_output; /* Output mode */ NmcColorOption use_colors; /* Whether to use colors for output: option '--color' */ - gboolean multiline_output; /* Multiline output instead of default tabular */ - gboolean escape_values; /* Whether to escape ':' and '\' in terse tabular mode */ - gboolean in_editor; /* Whether running the editor - nmcli con edit' */ + bool multiline_output; /* Multiline output instead of default tabular */ + bool escape_values; /* Whether to escape ':' and '\' in terse tabular mode */ + bool in_editor; /* Whether running the editor - nmcli con edit' */ + bool show_secrets; /* Whether to display secrets (both input and output): option '--show-secrets' */ } NmcConfig; typedef struct _NmcOutputData { @@ -143,11 +146,9 @@ typedef struct _NmCli { char *required_fields; /* Required fields in output: '--fields' option */ gboolean ask; /* Ask for missing parameters: option '--ask' */ gboolean complete; /* Autocomplete the command line */ - gboolean show_secrets; /* Whether to display secrets (both input and output): option '--show-secrets' */ gboolean editor_status_line; /* Whether to display status line in connection editor */ gboolean editor_save_confirmation; /* Whether to ask for confirmation on saving connections with 'autoconnect=yes' */ - gboolean editor_show_secrets; /* Whether to display secrets in the editor' */ - NMMetaTermColor editor_prompt_color; /* Color of prompt in connection editor */ + NMMetaTermColor editor_prompt_color; /* Color of prompt in connection editor */ } NmCli; extern NmCli nm_cli; @@ -156,6 +157,8 @@ extern NmCli nm_cli; #define NMCLI_ERROR (nmcli_error_quark ()) GQuark nmcli_error_quark (void); +extern GMainLoop *loop; + gboolean nmc_seen_sigint (void); void nmc_clear_sigint (void); void nmc_set_sigquit_internal (void); diff --git a/clients/cli/settings.c b/clients/cli/settings.c index 99eaa4f700..0f18ec7f67 100644 --- a/clients/cli/settings.c +++ b/clients/cli/settings.c @@ -304,74 +304,6 @@ nmc_setting_connection_connect_handlers (NMSettingConnection *setting, NMConnect G_CALLBACK (connection_master_changed_cb), connection); } -/* - * Customize some properties of the setting so that the setting has sensible - * values. - */ -void -nmc_setting_custom_init (NMSetting *setting) -{ - g_return_if_fail (NM_IS_SETTING (setting)); - - if (NM_IS_SETTING_VLAN (setting)) { - /* Set sensible initial VLAN values */ - g_object_set (NM_SETTING_VLAN (setting), - NM_SETTING_VLAN_ID, 1, - NULL); - } else if (NM_IS_SETTING_INFINIBAND (setting)) { - /* Initialize 'transport-mode' so that 'infiniband' is valid */ - g_object_set (NM_SETTING_INFINIBAND (setting), - NM_SETTING_INFINIBAND_TRANSPORT_MODE, "datagram", - NULL); - } else if (NM_IS_SETTING_CDMA (setting)) { - /* Initialize 'number' so that 'cdma' is valid */ - g_object_set (NM_SETTING_CDMA (setting), - NM_SETTING_CDMA_NUMBER, "#777", - NULL); - } else if (NM_IS_SETTING_GSM (setting)) { - /* Initialize 'number' so that 'gsm' is valid */ - g_object_set (NM_SETTING_GSM (setting), - NM_SETTING_GSM_NUMBER, "*99#", - NULL); - } else if (NM_IS_SETTING_OLPC_MESH (setting)) { - g_object_set (NM_SETTING_OLPC_MESH (setting), - NM_SETTING_OLPC_MESH_CHANNEL, 1, - NULL); - } else if (NM_IS_SETTING_WIRELESS (setting)) { - /* For Wi-Fi set mode to "infrastructure". Even though mode == NULL - * is regarded as "infrastructure", explicit value makes no doubts. - */ - g_object_set (NM_SETTING_WIRELESS (setting), - NM_SETTING_WIRELESS_MODE, NM_SETTING_WIRELESS_MODE_INFRA, - NULL); - } else if (NM_IS_SETTING_ADSL (setting)) { - /* Initialize a protocol */ - g_object_set (NM_SETTING_ADSL (setting), - NM_SETTING_ADSL_PROTOCOL, NM_SETTING_ADSL_PROTOCOL_PPPOE, - NULL); - } else if (NM_IS_SETTING_IP4_CONFIG (setting)) { - g_object_set (NM_SETTING_IP_CONFIG (setting), - NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, - NULL); - } else if (NM_IS_SETTING_IP6_CONFIG (setting)) { - g_object_set (NM_SETTING_IP_CONFIG (setting), - NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO, - NULL); - } else if (NM_IS_SETTING_PROXY (setting)) { - g_object_set (NM_SETTING_PROXY (setting), - NM_SETTING_PROXY_METHOD, (int) NM_SETTING_PROXY_METHOD_NONE, - NULL); - } else if (NM_IS_SETTING_TUN (setting)) { - g_object_set (NM_SETTING_TUN (setting), - NM_SETTING_TUN_MODE, NM_SETTING_TUN_MODE_TUN, - NULL); - } else if (NM_IS_SETTING_BLUETOOTH (setting)) { - g_object_set (NM_SETTING_BLUETOOTH (setting), - NM_SETTING_BLUETOOTH_TYPE, NM_SETTING_BLUETOOTH_TYPE_PANU, - NULL); - } -} - /*****************************************************************************/ static gboolean @@ -456,31 +388,89 @@ _env_warn_fcn_handle (const NMMetaEnvironment *environment, g_print (_("Error: %s\n"), m); } +static NMDevice *const* +_env_get_nm_devices (const NMMetaEnvironment *environment, + gpointer environment_user_data, + guint *out_len) +{ + NmCli *nmc = environment_user_data; + const GPtrArray *devices; + + nm_assert (nmc); + + /* the returned list is *not* NULL terminated. Need to + * provide and honor the out_len argument. */ + nm_assert (out_len); + + devices = nm_client_get_devices (nmc->client); + if (!devices) { + *out_len = 0; + return NULL; + } + + *out_len = devices->len; + return (NMDevice *const*) devices->pdata; +} + +static NMRemoteConnection *const* +_env_get_nm_connections (const NMMetaEnvironment *environment, + gpointer environment_user_data, + guint *out_len) +{ + NmCli *nmc = environment_user_data; + const GPtrArray *values; + + nm_assert (nmc); + + /* the returned list is *not* NULL terminated. Need to + * provide and honor the out_len argument. */ + nm_assert (out_len); + + values = nm_client_get_connections (nmc->client); + if (!values) { + *out_len = 0; + return NULL; + } + + *out_len = values->len; + return (NMRemoteConnection *const*) values->pdata; +} + /*****************************************************************************/ -static const NMMetaEnvironment meta_environment = { +const NMMetaEnvironment *const nmc_meta_environment = &((NMMetaEnvironment) { .warn_fcn = _env_warn_fcn_handle, -}; + .get_nm_devices = _env_get_nm_devices, + .get_nm_connections = _env_get_nm_connections, +}); + +NmCli *const nmc_meta_environment_arg = &nm_cli; static char * get_property_val (NMSetting *setting, const char *prop, NMMetaAccessorGetType get_type, gboolean show_secrets, 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); + g_return_val_if_fail (NM_IS_SETTING (setting), NULL); + g_return_val_if_fail (!error || !*error, NULL); + g_return_val_if_fail (NM_IN_SET (get_type, NM_META_ACCESSOR_GET_TYPE_PARSABLE, NM_META_ACCESSOR_GET_TYPE_PRETTY), NULL); if ((property_info = nm_meta_property_info_find_by_setting (setting, prop))) { - if (property_info->is_name) { - /* Traditionally, the "name" property was not handled here. - * For the moment, skip it from get_property_val(). */ - } else if (property_info->property_type->get_fcn) { - return property_info->property_type->get_fcn (&meta_environment, - NULL, - property_info, - setting, - get_type, - show_secrets ? NM_META_ACCESSOR_GET_FLAGS_SHOW_SECRETS : 0); + if (property_info->property_type->get_fcn) { + NMMetaAccessorGetOutFlags out_flags = NM_META_ACCESSOR_GET_OUT_FLAGS_NONE; + char *to_free = NULL; + const char *value; + + value = property_info->property_type->get_fcn (property_info, + nmc_meta_environment, + nmc_meta_environment_arg, + setting, + get_type, + show_secrets ? NM_META_ACCESSOR_GET_FLAGS_SHOW_SECRETS : 0, + &out_flags, + (gpointer *) &to_free); + nm_assert (!out_flags); + return to_free ?: g_strdup (value); } } @@ -517,9 +507,9 @@ _set_fcn_call (const NMMetaPropertyInfo *property_info, const char *value, GError **error) { - return property_info->property_type->set_fcn (&meta_environment, - NULL, - property_info, + return property_info->property_type->set_fcn (property_info, + nmc_meta_environment, + nmc_meta_environment_arg, setting, value, error); @@ -549,10 +539,7 @@ nmc_setting_set_property (NMSetting *setting, const char *prop, const char *valu return TRUE; } - if (property_info->is_name) { - /* Traditionally, the "name" property was not handled here. - * For the moment, skip it from get_property_val(). */ - } else if (property_info->property_type->set_fcn) { + 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)) { @@ -613,10 +600,7 @@ nmc_setting_reset_property (NMSetting *setting, const char *prop, GError **error 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->is_name) { - /* Traditionally, the "name" property was not handled here. - * For the moment, skip it from get_property_val(). */ - } else if (property_info->property_type->set_fcn) { + if (property_info->property_type->set_fcn) { nmc_property_set_default_value (setting, prop); return TRUE; } @@ -648,13 +632,10 @@ nmc_setting_remove_property_option (NMSetting *setting, 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->is_name) { - /* Traditionally, the "name" property was not handled here. - * For the moment, skip it from get_property_val(). */ - } else if (property_info->property_type->remove_fcn) { - return property_info->property_type->remove_fcn (&meta_environment, - NULL, - property_info, + 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, @@ -707,10 +688,7 @@ nmc_setting_get_property_allowed_values (NMSetting *setting, const char *prop, c *out_to_free = NULL; if ((property_info = nm_meta_property_info_find_by_setting (setting, prop))) { - if (property_info->is_name) { - /* Traditionally, the "name" property was not handled here. - * For the moment, skip it from get_property_val(). */ - } else if (property_info->property_type->values_fcn) { + if (property_info->property_type->values_fcn) { return property_info->property_type->values_fcn (property_info, out_to_free); } else if (property_info->property_typ_data && property_info->property_typ_data->values_static) @@ -751,10 +729,7 @@ nmc_setting_get_property_desc (NMSetting *setting, const char *prop) setting_desc_title = _("[NM property description]"); } - if (property_info->is_name) { - /* Traditionally, the "name" property was not handled here. - * For the moment, skip it from get_property_val(). */ - } else if (property_info->property_type->describe_fcn) { + if (property_info->property_type->describe_fcn) { desc = property_info->property_type->describe_fcn (property_info, &desc_to_free); } else desc = property_info->describe_message; @@ -809,29 +784,12 @@ nmc_property_set_gvalue (NMSetting *setting, const char *prop, GValue *value) /*****************************************************************************/ -static NmcOutputField * -_dup_fields_array (const NMMetaSettingInfoEditor *setting_info, NmcOfFlags flags) -{ - NmcOutputField *row; - gsize l; - - l = setting_info->properties_num; - - row = g_malloc0 ((l + 1) * sizeof (NmcOutputField)); - for (l = 0; l < setting_info->properties_num; l++) - row[l].info = (const NMMetaAbstractInfo *) &setting_info->properties[l]; - row[0].flags = flags; - return row; -} - gboolean -setting_details (const NmcConfig *nmc_config, NMSetting *setting, const char *one_prop, gboolean show_secrets) +setting_details (const NmcConfig *nmc_config, NMSetting *setting, const char *one_prop) { const NMMetaSettingInfoEditor *setting_info; - NmcOutputField *arr; - guint i; - NMMetaAccessorGetType type = NM_META_ACCESSOR_GET_TYPE_PRETTY; - NMC_OUTPUT_DATA_DEFINE_SCOPED (out); + gs_free_error GError *error = NULL; + gs_free char *fields_str = NULL; g_return_val_if_fail (NM_IS_SETTING (setting), FALSE); @@ -839,36 +797,20 @@ setting_details (const NmcConfig *nmc_config, NMSetting *setting, const char *on if (!setting_info) return FALSE; - if (nmc_config->print_output == NMC_PRINT_TERSE) - type = NM_META_ACCESSOR_GET_TYPE_PARSABLE; - - out_indices = parse_output_fields (one_prop, - (const NMMetaAbstractInfo *const*) nm_property_infos_for_setting_type (setting_info->general->meta_type), - FALSE, NULL, NULL); - arr = _dup_fields_array (setting_info, NMC_OF_FLAG_FIELD_NAMES); - g_ptr_array_add (out.output_data, arr); - - arr = _dup_fields_array (setting_info, NMC_OF_FLAG_SECTION_PREFIX); - for (i = 0; i < setting_info->properties_num; i++) { - const NMMetaPropertyInfo *property_info = &setting_info->properties[i]; - - nm_assert (property_info->setting_info == setting_info); - - if (!property_info->is_secret || show_secrets) { - set_val_str (arr, i, property_info->property_type->get_fcn (&meta_environment, - NULL, - property_info, - setting, - type, - show_secrets ? NM_META_ACCESSOR_GET_FLAGS_SHOW_SECRETS : 0)); - } else - set_val_str (arr, i, g_strdup (_(NM_META_TEXT_HIDDEN))); + if (one_prop) { + /* hack around setting-details being called for one setting. Must prefix the + * property name with the setting name. Later we should remove setting_details() + * and merge it into the caller. */ + fields_str = g_strdup_printf ("%s.%s", nm_setting_get_name (setting), one_prop); } - g_ptr_array_add (out.output_data, arr); - - print_data_prepare_width (out.output_data); - print_data (nmc_config, out_indices, NULL, 0, &out); + if (!nmc_print (nmc_config, + (gpointer[]) { setting, NULL }, + NULL, + (const NMMetaAbstractInfo *const[]) { (const NMMetaAbstractInfo *) setting_info, NULL }, + fields_str, + &error)) + return FALSE; return TRUE; } diff --git a/clients/cli/settings.h b/clients/cli/settings.h index 2a90753057..7dad622bf8 100644 --- a/clients/cli/settings.h +++ b/clients/cli/settings.h @@ -27,7 +27,6 @@ /*****************************************************************************/ -void nmc_setting_custom_init (NMSetting *setting); void nmc_setting_ip4_connect_handlers (NMSettingIPConfig *setting); void nmc_setting_ip6_connect_handlers (NMSettingIPConfig *setting); void nmc_setting_proxy_connect_handlers (NMSettingProxy *setting); @@ -60,6 +59,6 @@ void nmc_property_set_default_value (NMSetting *setting, const char *prop); gboolean nmc_property_get_gvalue (NMSetting *setting, const char *prop, GValue *value); gboolean nmc_property_set_gvalue (NMSetting *setting, const char *prop, GValue *value); -gboolean setting_details (const NmcConfig *nmc_config, NMSetting *setting, const char *one_prop, gboolean secrets); +gboolean setting_details (const NmcConfig *nmc_config, NMSetting *setting, const char *one_prop); #endif /* NMC_SETTINGS_H */ diff --git a/clients/cli/utils.c b/clients/cli/utils.c index f67df6a3fd..ebafaa127b 100644 --- a/clients/cli/utils.c +++ b/clients/cli/utils.c @@ -35,12 +35,19 @@ #include "common.h" #include "settings.h" +#define ML_HEADER_WIDTH 79 +#define ML_VALUE_INDENT 40 + /*****************************************************************************/ static const char * -_meta_type_nmc_generic_info_get_name (const NMMetaAbstractInfo *abstract_info) +_meta_type_nmc_generic_info_get_name (const NMMetaAbstractInfo *abstract_info, gboolean for_header) { - return ((const NmcMetaGenericInfo *) abstract_info)->name; + const NmcMetaGenericInfo *info = (const NmcMetaGenericInfo *) abstract_info; + + if (for_header) + return info->name_header ?: info->name; + return info->name; } static const NMMetaAbstractInfo *const* @@ -66,24 +73,49 @@ _meta_type_nmc_generic_info_get_nested (const NMMetaAbstractInfo *abstract_info, } static gconstpointer -_meta_type_nmc_generic_info_get_fcn (const NMMetaEnvironment *environment, +_meta_type_nmc_generic_info_get_fcn (const NMMetaAbstractInfo *abstract_info, + const NMMetaEnvironment *environment, gpointer environment_user_data, - const NMMetaAbstractInfo *abstract_info, gpointer target, NMMetaAccessorGetType get_type, NMMetaAccessorGetFlags get_flags, + NMMetaAccessorGetOutFlags *out_flags, gpointer *out_to_free) { const NmcMetaGenericInfo *info = (const NmcMetaGenericInfo *) abstract_info; - nm_assert (out_to_free && !*out_to_free); + nm_assert (!out_to_free || !*out_to_free); + nm_assert (out_flags && !*out_flags); - if (!info->get_fcn) + if (!NM_IN_SET (get_type, + NM_META_ACCESSOR_GET_TYPE_PARSABLE, + NM_META_ACCESSOR_GET_TYPE_PRETTY, + NM_META_ACCESSOR_GET_TYPE_TERMFORMAT)) g_return_val_if_reached (NULL); - return info->get_fcn (environment, environment_user_data, - info, target, - get_type, get_flags, - out_to_free); + + /* omitting the out_to_free value is only allowed for TERMFORMAT. */ + nm_assert (out_to_free || NM_IN_SET (get_type, NM_META_ACCESSOR_GET_TYPE_TERMFORMAT)); + + if (info->get_fcn) { + return info->get_fcn (environment, environment_user_data, + info, target, + get_type, + get_flags, + out_flags, + out_to_free); + } + + if (info->nested) { + const char *s; + + NMC_HANDLE_TERMFORMAT (NM_META_TERM_COLOR_NORMAL); + s = info->name; + if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY) + return _(s); + return s; + } + + g_return_val_if_reached (NULL); } const NMMetaType nmc_meta_type_generic_info = { @@ -95,13 +127,52 @@ const NMMetaType nmc_meta_type_generic_info = { /*****************************************************************************/ +static gboolean +use_colors (NmcColorOption color_option) +{ + if (color_option == NMC_USE_COLOR_AUTO) { + static NmcColorOption cached = NMC_USE_COLOR_AUTO; + + if (G_UNLIKELY (cached == NMC_USE_COLOR_AUTO)) { + if ( g_strcmp0 (g_getenv ("TERM"), "dumb") == 0 + || !isatty (fileno (stdout))) + cached = NMC_USE_COLOR_NO; + else + cached = NMC_USE_COLOR_YES; + } + return cached == NMC_USE_COLOR_YES; + } + + return color_option == NMC_USE_COLOR_YES; +} + +static const char * +colorize_string (NmcColorOption color_option, + NMMetaTermColor color, + NMMetaTermFormat color_fmt, + const char *str, + char **out_to_free) +{ + const char *out = str; + + if ( use_colors (color_option) + && (color != NM_META_TERM_COLOR_NORMAL || color_fmt != NM_META_TERM_FORMAT_NORMAL)) { + *out_to_free = nmc_colorize (color_option, color, color_fmt, "%s", str); + out = *out_to_free; + } + + return out; +} + +/*****************************************************************************/ + static gboolean parse_global_arg (NmCli *nmc, const char *arg) { if (nmc_arg_is_option (arg, "ask")) nmc->ask = TRUE; else if (nmc_arg_is_option (arg, "show-secrets")) - nmc->show_secrets = TRUE; + nmc->nmc_config_mutable.show_secrets = TRUE; else return FALSE; @@ -419,25 +490,6 @@ nmc_term_format_sequence (NMMetaTermFormat format) } } -static gboolean -use_colors (NmcColorOption color_option) -{ - if (color_option == NMC_USE_COLOR_AUTO) { - static NmcColorOption cached = NMC_USE_COLOR_AUTO; - - if (G_UNLIKELY (cached == NMC_USE_COLOR_AUTO)) { - if ( g_strcmp0 (g_getenv ("TERM"), "dumb") == 0 - || !isatty (fileno (stdout))) - cached = NMC_USE_COLOR_NO; - else - cached = NMC_USE_COLOR_YES; - } - return cached == NMC_USE_COLOR_YES; - } - - return color_option == NMC_USE_COLOR_YES; -} - char * nmc_colorize (NmcColorOption color_option, NMMetaTermColor color, NMMetaTermFormat format, const char *fmt, ...) { @@ -710,26 +762,185 @@ nmc_free_output_field_values (NmcOutputField fields_array[]) } } +/*****************************************************************************/ + typedef struct { guint idx; - gsize offset_plus_1; + gsize self_offset_plus_1; + gsize sub_offset_plus_1; } OutputSelectionItem; -NmcOutputSelection * -nmc_output_selection_create (const NMMetaAbstractInfo *const* fields_array, - const char *fields_str, - GError **error) +static NmcOutputSelection * +_output_selection_pack (const NMMetaAbstractInfo *const* fields_array, + GArray *array, + GString *str) +{ + NmcOutputSelection *result; + guint i; + guint len; + + len = array ? array->len : 0; + + /* re-organize the collected output data in one buffer that can be freed using + * g_free(). This makes allocation more complicated, but saves us from special + * handling for free. */ + result = g_malloc0 (sizeof (NmcOutputSelection) + (len * sizeof (NmcOutputSelectionItem)) + (str ? str->len : 0)); + *((guint *) &result->num) = len; + if (len > 0) { + char *pdata = &((char *) result)[sizeof (NmcOutputSelection) + (len * sizeof (NmcOutputSelectionItem))]; + + if (str) + memcpy (pdata, str->str, str->len); + for (i = 0; i < len; i++) { + const OutputSelectionItem *a = &g_array_index (array, OutputSelectionItem, i); + NmcOutputSelectionItem *p = (NmcOutputSelectionItem *) &result->items[i]; + + p->info = fields_array[a->idx]; + p->idx = a->idx; + if (a->self_offset_plus_1 > 0) + p->self_selection = &pdata[a->self_offset_plus_1 - 1]; + if (a->sub_offset_plus_1 > 0) + p->sub_selection = &pdata[a->sub_offset_plus_1 - 1]; + } + } + + return result; +} + +static gboolean +_output_selection_select_one (const NMMetaAbstractInfo *const* fields_array, + const char *fields_prefix, + const char *fields_str, + gboolean validate_nested, + GArray **p_array, + GString **p_str, + GError **error) +{ + guint i, j; + const char *i_name; + const char *right; + gboolean found = FALSE; + const NMMetaAbstractInfo *fields_array_failure = NULL; + gs_free char *fields_str_clone = NULL; + + nm_assert (fields_str); + nm_assert (p_array); + nm_assert (p_str); + nm_assert (!error || !*error); + + right = strchr (fields_str, '.'); + if (right) { + fields_str_clone = g_strdup (fields_str); + fields_str_clone[right - fields_str] = '\0'; + i_name = fields_str_clone; + right = &fields_str_clone[right - fields_str + 1]; + } else + i_name = fields_str; + + if (!fields_array) + goto not_found; + + for (i = 0; fields_array[i]; i++) { + const NMMetaAbstractInfo *fi = fields_array[i]; + + if (g_ascii_strcasecmp (i_name, nm_meta_abstract_info_get_name (fi, FALSE)) != 0) + continue; + + if (!right || !validate_nested) { + found = TRUE; + break; + } + + if (fi->meta_type == &nm_meta_type_setting_info_editor) { + const NMMetaSettingInfoEditor *fi_s = (const NMMetaSettingInfoEditor *) fi; + + for (j = 0; j < fi_s->properties_num; j++) { + if (g_ascii_strcasecmp (right, fi_s->properties[j].property_name) == 0) { + found = TRUE; + break; + } + } + } else if (fi->meta_type == &nmc_meta_type_generic_info) { + const NmcMetaGenericInfo *fi_g = (const NmcMetaGenericInfo *) fi; + + for (j = 0; fi_g->nested && fi_g->nested[j]; j++) { + if (g_ascii_strcasecmp (right, nm_meta_abstract_info_get_name ((const NMMetaAbstractInfo *) fi_g->nested[j], FALSE)) == 0) { + found = TRUE; + break; + } + } + } + fields_array_failure = fields_array[i]; + break; + } + + if (!found) { +not_found: + if ( !right + && !fields_prefix + && ( !g_ascii_strcasecmp (i_name, "all") + || !g_ascii_strcasecmp (i_name, "common"))) + g_set_error (error, NMCLI_ERROR, 0, _("field '%s' has to be alone"), i_name); + else { + gs_free char *allowed_fields = NULL; + + if (fields_array_failure) { + gs_free char *p = NULL; + + if (fields_prefix) { + p = g_strdup_printf ("%s.%s", fields_prefix, + nm_meta_abstract_info_get_name (fields_array_failure, FALSE)); + } + allowed_fields = nmc_get_allowed_fields_nested (fields_array_failure, p); + } else + allowed_fields = nmc_get_allowed_fields (fields_array, NULL); + + g_set_error (error, NMCLI_ERROR, 1, _("invalid field '%s%s%s%s%s'; %s%s%s"), + fields_prefix ?: "", fields_prefix ? "." : "", + i_name, right ? "." : "", right ?: "", + NM_PRINT_FMT_QUOTED (allowed_fields, "allowed fields: ", allowed_fields, "", "no fields")); + } + return FALSE; + } + + { + GString *str; + OutputSelectionItem s = { + .idx = i, + }; + + if (!*p_str) + *p_str = g_string_sized_new (64); + str = *p_str; + + s.self_offset_plus_1 = str->len + 1; + if (fields_prefix) { + g_string_append (str, fields_prefix); + g_string_append_c (str, '.'); + } + g_string_append_len (str, i_name, strlen (i_name) + 1); + + if (right) { + s.sub_offset_plus_1 = str->len + 1; + g_string_append_len (str, right, strlen (right) + 1); + } + + if (!*p_array) + *p_array = g_array_new (FALSE, FALSE, sizeof (OutputSelectionItem)); + g_array_append_val (*p_array, s); + } + + return TRUE; +} + +static NmcOutputSelection * +_output_selection_create_all (const NMMetaAbstractInfo *const* fields_array) { gs_unref_array GArray *array = NULL; - nm_auto_free_gstring GString *str = NULL; - guint i, j; - NmcOutputSelection *result; + guint i; - g_return_val_if_fail (!error || !*error, NULL); - - array = g_array_new (FALSE, FALSE, sizeof (OutputSelectionItem)); - - if (!fields_str) { + if (fields_array) { + array = g_array_new (FALSE, FALSE, sizeof (OutputSelectionItem)); for (i = 0; fields_array[i]; i++) { OutputSelectionItem s = { .idx = i, @@ -737,131 +948,224 @@ nmc_output_selection_create (const NMMetaAbstractInfo *const* fields_array, g_array_append_val (array, s); } - } else { - gs_free char *fields_str_clone = NULL; - char *fields_str_cur; - char *fields_str_next; - - fields_str_clone = g_strdup (fields_str); - for (fields_str_cur = fields_str_clone; fields_str_cur; fields_str_cur = fields_str_next) { - const char *i_name; - const char *right = NULL; - gboolean found = FALSE; - const NMMetaAbstractInfo *fields_array_failure = NULL; - - fields_str_cur = nm_str_skip_leading_spaces (fields_str_cur); - fields_str_next = strchr (fields_str_cur, ','); - if (fields_str_next) - *fields_str_next++ = '\0'; - - g_strchomp (fields_str_cur); - if (!fields_str_cur[0]) - continue; - - i_name = fields_str_cur; - fields_str_cur = strchr (fields_str_cur, '.'); - if (fields_str_cur) { - right = fields_str_cur + 1; - *fields_str_cur = '\0'; - } - - for (i = 0; fields_array[i]; i++) { - const NMMetaAbstractInfo *fi = fields_array[i]; - - if (g_ascii_strcasecmp (i_name, nm_meta_abstract_info_get_name (fi)) != 0) - continue; - - if (!right) - found = TRUE; - else { - found = FALSE; - if (fi->meta_type == &nm_meta_type_setting_info_editor) { - const NMMetaSettingInfoEditor *fi_s = &fi->as.setting_info; - - for (j = 1; j < fi_s->properties_num; j++) { - if (g_ascii_strcasecmp (right, fi_s->properties[j].property_name) == 0) { - found = TRUE; - break; - } - } - } else if (fi->meta_type == &nmc_meta_type_generic_info) { - const NmcMetaGenericInfo *fi_g = (const NmcMetaGenericInfo *) fi; - - for (j = 0; fi_g->nested && fi_g->nested[j]; j++) { - if (g_ascii_strcasecmp (right, nm_meta_abstract_info_get_name ((const NMMetaAbstractInfo *) fi_g->nested[j])) == 0) { - found = TRUE; - break; - } - } - } - } - - if (found) { - OutputSelectionItem s = { - .idx = i, - }; - - if (right) { - if (!str) - str = g_string_sized_new (32); - - s.offset_plus_1 = str->len + 1; - g_string_append_len (str, right, strlen (right) + 1); - } - - g_array_append_val (array, s); - } - - fields_array_failure = fields_array[i]; - break; - } - - if (!found) { - if ( !right - && ( !g_ascii_strcasecmp (i_name, "all") - || !g_ascii_strcasecmp (i_name, "common"))) - g_set_error (error, NMCLI_ERROR, 0, _("field '%s' has to be alone"), i_name); - else { - gs_free char *allowed_fields = NULL; - - if (fields_array_failure) - allowed_fields = nmc_get_allowed_fields_nested (fields_array_failure); - else - allowed_fields = nmc_get_allowed_fields (fields_array); - - g_set_error (error, NMCLI_ERROR, 1, _("invalid field '%s%s%s'; allowed fields: %s"), - i_name, right ? "." : "", right ?: "", allowed_fields); - } - - return NULL; - } - } } - /* re-organize the collected output data in one buffer that can be freed using - * g_free(). This makes allocation more complicated, but saves us from special - * handling for free. */ - result = g_malloc0 (sizeof (NmcOutputSelection) + (array->len * sizeof (NmcOutputSelectionItem)) + (str ? str->len : 0)); - *((guint *) &result->num) = array->len; - if (array->len > 0) { - char *pdata = &((char *) result)[sizeof (NmcOutputSelection) + (array->len * sizeof (NmcOutputSelectionItem))]; - - if (str) - memcpy (pdata, str->str, str->len); - for (i = 0; i < array->len; i++) { - const OutputSelectionItem *a = &g_array_index (array, OutputSelectionItem, i); - NmcOutputSelectionItem *p = (NmcOutputSelectionItem *) &result->items[i]; - - p->info = fields_array[a->idx]; - p->idx = a->idx; - if (a->offset_plus_1 > 0) - p->sub_selection = &pdata[a->offset_plus_1 - 1]; - } - } - - return result; + return _output_selection_pack (fields_array, array, NULL); } +static NmcOutputSelection * +_output_selection_create_one (const NMMetaAbstractInfo *const* fields_array, + const char *fields_prefix, + const char *fields_str, /* one field selector (contains not commas) and is alrady stripped of spaces. */ + gboolean validate_nested, + GError **error) +{ + gs_unref_array GArray *array = NULL; + nm_auto_free_gstring GString *str = NULL; + + g_return_val_if_fail (!error || !*error, NULL); + nm_assert (fields_str && !strchr (fields_str, ',')); + + if (!_output_selection_select_one (fields_array, + fields_prefix, + fields_str, + validate_nested, + &array, + &str, + error)) + return NULL; + return _output_selection_pack (fields_array, array, str); + +} + +#define PRINT_DATA_COL_PARENT_NIL (G_MAXUINT) + +typedef struct { + const NmcOutputSelectionItem *selection_item; + guint parent_idx; + guint self_idx; + bool is_leaf; +} PrintDataCol; + +static gboolean +_output_selection_append (GArray *cols, + const char *fields_prefix, + guint parent_idx, + const NmcOutputSelectionItem *selection_item, + GPtrArray *gfree_keeper, + GError **error) +{ + gs_free gpointer nested_to_free = NULL; + guint col_idx; + guint i; + const NMMetaAbstractInfo *const*nested; + NmcOutputSelection *selection; + const NmcOutputSelectionItem *si; + + col_idx = cols->len; + + { + PrintDataCol col = { + .selection_item = selection_item, + .parent_idx = parent_idx, + .self_idx = col_idx, + .is_leaf = TRUE, + }; + g_array_append_val (cols, col); + } + + nested = nm_meta_abstract_info_get_nested (selection_item->info, NULL, &nested_to_free); + + if (selection_item->sub_selection) { + if (!nested) { + gs_free char *allowed_fields = NULL; + + if (parent_idx != PRINT_DATA_COL_PARENT_NIL) { + si = g_array_index (cols, PrintDataCol, parent_idx).selection_item; + allowed_fields = nmc_get_allowed_fields_nested (si->info, si->self_selection); + } + if (!allowed_fields) { + g_set_error (error, NMCLI_ERROR, 1, _("invalid field '%s%s%s'; no such field"), + selection_item->self_selection ?: "", selection_item->self_selection ? "." : "", + selection_item->sub_selection); + } else { + g_set_error (error, NMCLI_ERROR, 1, _("invalid field '%s%s%s'; allowed fields: [%s]"), + selection_item->self_selection ?: "", selection_item->self_selection ? "." : "", + selection_item->sub_selection, + allowed_fields); + } + return FALSE; + } + + selection = _output_selection_create_one (nested, selection_item->self_selection, + selection_item->sub_selection, FALSE, error); + if (!selection) + return FALSE; + nm_assert (selection->num == 1); + } else if (nested) { + selection = _output_selection_create_all (nested); + nm_assert (selection && selection->num > 0); + } else + selection = NULL; + + if (selection) { + g_ptr_array_add (gfree_keeper, selection); + + for (i = 0; i < selection->num; i++) { + si = &selection->items[i]; + if (!_output_selection_append (cols, si->self_selection, col_idx, + si, gfree_keeper, error)) + return FALSE; + } + + if (!NM_IN_SET(selection_item->info->meta_type, + &nm_meta_type_setting_info_editor, + &nmc_meta_type_generic_info)) + g_array_index (cols, PrintDataCol, col_idx).is_leaf = FALSE; + } + + return TRUE; +} + +/*****************************************************************************/ + +NmcOutputSelection * +nmc_output_selection_create (const NMMetaAbstractInfo *const* fields_array, + const char *fields_prefix, + const char *fields_str, /* a comma separated list of selectors */ + gboolean validate_nested, + GError **error) +{ + gs_unref_array GArray *array = NULL; + nm_auto_free_gstring GString *str = NULL; + gs_free char *fields_str_clone = NULL; + char *fields_str_cur; + char *fields_str_next; + + g_return_val_if_fail (!error || !*error, NULL); + + if (!fields_str) + return _output_selection_create_all (fields_array); + + fields_str_clone = g_strdup (fields_str); + for (fields_str_cur = fields_str_clone; fields_str_cur; fields_str_cur = fields_str_next) { + fields_str_cur = nm_str_skip_leading_spaces (fields_str_cur); + fields_str_next = strchr (fields_str_cur, ','); + if (fields_str_next) + *fields_str_next++ = '\0'; + + g_strchomp (fields_str_cur); + if (!fields_str_cur[0]) + continue; + if (!_output_selection_select_one (fields_array, + fields_prefix, + fields_str_cur, + validate_nested, + &array, + &str, + error)) + return NULL; + } + + return _output_selection_pack (fields_array, array, str); +} + +/** + * _output_selection_parse: + * @fields: a %NULL terminated array of meta-data fields + * @fields_str: a comma separated selector for fields. Nested fields + * can be specified using '.' notation. + * @out_cols: (transfer full): the result, parsed as an GArray of PrintDataCol items. + * The order of the items is as specified by @fields_str. Meta data + * items that contain nested elements are unpacked (note the is_leaf + * and parent properties of PrintDataCol). + * @out_gfree_keeper: (transfer full): an output GPtrArray that owns + * strings to which @out_cols points to. The lifetime of @out_cols + * and @out_gfree_keeper should correspond. + * @error: + * + * Returns: %TRUE on success. + */ +static gboolean +_output_selection_parse (const NMMetaAbstractInfo *const*fields, + const char *fields_str, + GArray **out_cols, + GPtrArray **out_gfree_keeper, + GError **error) +{ + NmcOutputSelection *selection; + gs_unref_ptrarray GPtrArray *gfree_keeper = NULL; + gs_unref_array GArray *cols = NULL; + guint i; + + selection = nmc_output_selection_create (fields, NULL, fields_str, FALSE, error); + if (!selection) + return FALSE; + + if (!selection->num) { + g_set_error (error, NMCLI_ERROR, 1, _("failure to select field")); + return FALSE; + } + + gfree_keeper = g_ptr_array_new_with_free_func (g_free); + g_ptr_array_add (gfree_keeper, selection); + + cols = g_array_new (FALSE, TRUE, sizeof (PrintDataCol)); + + for (i = 0; i < selection->num; i++) { + const NmcOutputSelectionItem *si = &selection->items[i]; + + if (!_output_selection_append (cols, NULL, PRINT_DATA_COL_PARENT_NIL, + si, gfree_keeper, error)) + return FALSE; + } + + *out_cols = g_steal_pointer (&cols); + *out_gfree_keeper = g_steal_pointer (&gfree_keeper); + return TRUE; +} + +/*****************************************************************************/ /** * parse_output_fields: @@ -898,7 +1202,7 @@ parse_output_fields (const char *fields_str, g_return_val_if_fail (!error || !*error, NULL); g_return_val_if_fail (!out_group_fields || !*out_group_fields, NULL); - selection = nmc_output_selection_create (fields_array, fields_str, error); + selection = nmc_output_selection_create (fields_array, NULL, fields_str, TRUE, error); if (!selection) return NULL; @@ -920,40 +1224,46 @@ parse_output_fields (const char *fields_str, } char * -nmc_get_allowed_fields_nested (const NMMetaAbstractInfo *abstract_info) +nmc_get_allowed_fields_nested (const NMMetaAbstractInfo *abstract_info, const char *name_prefix) { - GString *allowed_fields = g_string_sized_new (256); - int i; - const char *name = nm_meta_abstract_info_get_name (abstract_info); gs_free gpointer nested_to_free = NULL; - const NMMetaAbstractInfo *const*nested = NULL; + guint i; + const NMMetaAbstractInfo *const*nested; + GString *allowed_fields; nested = nm_meta_abstract_info_get_nested (abstract_info, NULL, &nested_to_free); - if (nested) { - for (i = 0; nested && nested[i]; i++) { - g_string_append_printf (allowed_fields, "%s.%s,", - name, nm_meta_abstract_info_get_name (nested[i])); - } - } else - g_string_append_printf (allowed_fields, "%s,", name); + if (!nested) + return NULL; + allowed_fields = g_string_sized_new (256); + + if (!name_prefix) + name_prefix = nm_meta_abstract_info_get_name (abstract_info, FALSE); + + for (i = 0; nested[i]; i++) { + g_string_append_printf (allowed_fields, "%s.%s,", + name_prefix, nm_meta_abstract_info_get_name (nested[i], FALSE)); + } g_string_truncate (allowed_fields, allowed_fields->len - 1); - return g_string_free (allowed_fields, FALSE); } char * -nmc_get_allowed_fields (const NMMetaAbstractInfo *const*fields_array) +nmc_get_allowed_fields (const NMMetaAbstractInfo *const*fields_array, const char *name_prefix) { - GString *allowed_fields = g_string_sized_new (256); + GString *allowed_fields; guint i; - for (i = 0; fields_array[i]; i++) - g_string_append_printf (allowed_fields, "%s,", nm_meta_abstract_info_get_name (fields_array[i])); - - if (allowed_fields->len) - g_string_truncate (allowed_fields, allowed_fields->len - 1); + if (!fields_array || !fields_array[0]) + return NULL; + allowed_fields = g_string_sized_new (256); + for (i = 0; fields_array[i]; i++) { + if (name_prefix) + g_string_append_printf (allowed_fields, "%s.", name_prefix); + g_string_append_printf (allowed_fields, "%s,", nm_meta_abstract_info_get_name (fields_array[i], FALSE)); + } + g_string_truncate (allowed_fields, allowed_fields->len - 1); return g_string_free (allowed_fields, FALSE); } @@ -989,24 +1299,475 @@ nmc_empty_output_fields (NmcOutputData *output_data) g_ptr_array_remove_range (output_data->output_data, 0, output_data->output_data->len); } -static const char * -colorize_string (NmcColorOption color_option, - NMMetaTermColor color, - NMMetaTermFormat color_fmt, - const char *str, - char **out_to_free) -{ - const char *out = str; +/*****************************************************************************/ - if ( use_colors (color_option) - && (color != NM_META_TERM_COLOR_NORMAL || color_fmt != NM_META_TERM_FORMAT_NORMAL)) { - *out_to_free = nmc_colorize (color_option, color, color_fmt, "%s", str); - out = *out_to_free; +typedef struct { + guint col_idx; + const PrintDataCol *col; + const char *title; + bool title_to_free:1; + int width; +} PrintDataHeaderCell; + +typedef enum { + PRINT_DATA_CELL_FORMAT_TYPE_PLAIN = 0, + PRINT_DATA_CELL_FORMAT_TYPE_STRV, +} PrintDataCellFormatType; + +typedef struct { + guint row_idx; + const PrintDataHeaderCell *header_cell; + NMMetaTermColor term_color; + NMMetaTermFormat term_format; + union { + const char *plain; + const char *const*strv; + } text; + PrintDataCellFormatType text_format:3; + bool text_to_free:1; +} PrintDataCell; + +static void +_print_data_header_cell_clear (gpointer cell_p) +{ + PrintDataHeaderCell *cell = cell_p; + + if (cell->title_to_free) { + g_free ((char *) cell->title); + cell->title_to_free = FALSE; + } + cell->title = NULL; +} + +static void +_print_data_cell_clear_text (PrintDataCell *cell) +{ + if (cell->text_to_free) { + switch (cell->text_format) { + case PRINT_DATA_CELL_FORMAT_TYPE_PLAIN: + g_free ((char *) cell->text.plain); + break; + case PRINT_DATA_CELL_FORMAT_TYPE_STRV: + g_strfreev ((char **) cell->text.strv); + break; + }; + cell->text_to_free = FALSE; + } + memset (&cell->text, 0, sizeof (cell->text)); +} + +static void +_print_data_cell_clear (gpointer cell_p) +{ + PrintDataCell *cell = cell_p; + + _print_data_cell_clear_text (cell); +} + +static void +_print_fill (const NmcConfig *nmc_config, + gpointer const *targets, + const PrintDataCol *cols, + guint cols_len, + GArray **out_header_row, + GArray **out_cells) +{ + GArray *cells; + GArray *header_row; + guint i_row, i_col; + guint targets_len; + gboolean pretty; + NMMetaAccessorGetType text_get_type; + NMMetaAccessorGetFlags text_get_flags; + + pretty = (nmc_config->print_output != NMC_PRINT_TERSE); + + header_row = g_array_sized_new (FALSE, TRUE, sizeof (PrintDataHeaderCell), cols_len); + g_array_set_clear_func (header_row, _print_data_header_cell_clear); + + for (i_col = 0; i_col < cols_len; i_col++) { + const PrintDataCol *col; + PrintDataHeaderCell *header_cell; + guint col_idx; + const NMMetaAbstractInfo *info; + gboolean translate_title; + + col = &cols[i_col]; + if (!col->is_leaf) + continue; + + info = col->selection_item->info; + + col_idx = header_row->len; + g_array_set_size (header_row, col_idx + 1); + + header_cell = &g_array_index (header_row, PrintDataHeaderCell, col_idx); + + header_cell->col_idx = col_idx; + header_cell->col = col; + + translate_title = pretty; + + header_cell->title = nm_meta_abstract_info_get_name (info, TRUE); + if ( nmc_config->multiline_output + && col->parent_idx != PRINT_DATA_COL_PARENT_NIL + && NM_IN_SET (info->meta_type, + &nm_meta_type_property_info, + &nmc_meta_type_generic_info)) { + header_cell->title = g_strdup_printf ("%s.%s", + nm_meta_abstract_info_get_name (cols[col->parent_idx].selection_item->info, FALSE), + header_cell->title); + header_cell->title_to_free = TRUE; + } else { + if (translate_title) + header_cell->title = _(header_cell->title); + } } - return out; + targets_len = NM_PTRARRAY_LEN (targets); + + cells = g_array_sized_new (FALSE, TRUE, sizeof (PrintDataCell), targets_len * header_row->len); + g_array_set_clear_func (cells, _print_data_cell_clear); + g_array_set_size (cells, targets_len * header_row->len); + + text_get_type = pretty + ? NM_META_ACCESSOR_GET_TYPE_PRETTY + : NM_META_ACCESSOR_GET_TYPE_PARSABLE; + text_get_flags = NM_META_ACCESSOR_GET_FLAGS_ACCEPT_STRV; + if (nmc_config->show_secrets) + text_get_flags |= NM_META_ACCESSOR_GET_FLAGS_SHOW_SECRETS; + + for (i_row = 0; i_row < targets_len; i_row++) { + gpointer target = targets[i_row]; + PrintDataCell *cells_line = &g_array_index (cells, PrintDataCell, i_row * header_row->len); + + for (i_col = 0; i_col < header_row->len; i_col++) { + char *to_free = NULL; + PrintDataCell *cell = &cells_line[i_col]; + const PrintDataHeaderCell *header_cell; + const NMMetaAbstractInfo *info; + NMMetaAccessorGetOutFlags text_out_flags, color_out_flags; + gconstpointer value; + + header_cell = &g_array_index (header_row, PrintDataHeaderCell, i_col); + info = header_cell->col->selection_item->info; + + cell->row_idx = i_row; + cell->header_cell = header_cell; + + value = nm_meta_abstract_info_get (info, + nmc_meta_environment, + nmc_meta_environment_arg, + target, + text_get_type, + text_get_flags, + &text_out_flags, + (gpointer *) &to_free); + if (NM_FLAGS_HAS (text_out_flags, NM_META_ACCESSOR_GET_OUT_FLAGS_STRV)) { + if (value) { + if (nmc_config->multiline_output) { + cell->text_format = PRINT_DATA_CELL_FORMAT_TYPE_STRV; + cell->text.strv = value; + cell->text_to_free = !!to_free; + } else { + cell->text.plain = g_strjoinv (" | ", (char **) value); + cell->text_to_free = TRUE; + if (to_free) + g_strfreev ((char **) to_free); + } + } + } else { + cell->text.plain = value; + cell->text_to_free = !!to_free; + } + + nm_meta_termformat_unpack (nm_meta_abstract_info_get (info, + nmc_meta_environment, + nmc_meta_environment_arg, + target, + NM_META_ACCESSOR_GET_TYPE_TERMFORMAT, + NM_META_ACCESSOR_GET_FLAGS_NONE, + &color_out_flags, + NULL), + &cell->term_color, + &cell->term_format); + + if (cell->text_format == PRINT_DATA_CELL_FORMAT_TYPE_PLAIN) { + if (pretty && (!cell->text.plain|| !cell->text.plain[0])) { + _print_data_cell_clear_text (cell); + cell->text.plain = "--"; + } else if (!cell->text.plain) + cell->text.plain = ""; + } + } + } + + for (i_col = 0; i_col < header_row->len; i_col++) { + PrintDataHeaderCell *header_cell = &g_array_index (header_row, PrintDataHeaderCell, i_col); + + header_cell->width = nmc_string_screen_width (header_cell->title, NULL); + + for (i_row = 0; i_row < targets_len; i_row++) { + const PrintDataCell *cell = &g_array_index (cells, PrintDataCell, i_row * cols_len + i_col); + const char *const*i_strv; + + switch (cell->text_format) { + case PRINT_DATA_CELL_FORMAT_TYPE_PLAIN: + header_cell->width = NM_MAX (header_cell->width, + nmc_string_screen_width (cell->text.plain, NULL)); + break; + case PRINT_DATA_CELL_FORMAT_TYPE_STRV: + i_strv = cell->text.strv; + if (i_strv) { + for (; *i_strv; i_strv++) { + header_cell->width = NM_MAX (header_cell->width, + nmc_string_screen_width (*i_strv, NULL)); + } + } + break; + } + } + + header_cell->width += 1; + } + + *out_header_row = header_row; + *out_cells = cells; } +static gboolean +_print_skip_column (const NmcConfig *nmc_config, + const PrintDataHeaderCell *header_cell) +{ + const NmcOutputSelectionItem *selection_item; + const NMMetaAbstractInfo *info; + + selection_item = header_cell->col->selection_item; + info = selection_item->info; + + if (nmc_config->multiline_output) { + if (info->meta_type == &nm_meta_type_setting_info_editor) { + /* we skip the "name" entry for the setting in multiline output. */ + return TRUE; + } + if ( info->meta_type == &nmc_meta_type_generic_info + && ((const NmcMetaGenericInfo *) info)->nested) { + /* skip the "name" entry for parent generic-infos */ + return TRUE; + } + } else { + if ( NM_IN_SET (info->meta_type, + &nm_meta_type_setting_info_editor, + &nmc_meta_type_generic_info) + && selection_item->sub_selection) { + /* in tabular form, we skip the "name" entry for sections that have sub-selections. + * That is, for "ipv4.may-fail", but not for "ipv4". */ + return TRUE; + } + } + return FALSE; +} + +static void +_print_do (const NmcConfig *nmc_config, + const char *header_name_no_l10n, + guint col_len, + guint row_len, + const PrintDataHeaderCell *header_row, + const PrintDataCell *cells) +{ + int width1, width2; + int table_width = 0; + gboolean pretty = (nmc_config->print_output == NMC_PRINT_PRETTY); + gboolean terse = (nmc_config->print_output == NMC_PRINT_TERSE); + gboolean multiline = nmc_config->multiline_output; + guint i_row, i_col; + nm_auto_free_gstring GString *str = NULL; + + g_assert (col_len && row_len); + + /* Main header */ + if (pretty && header_name_no_l10n) { + gs_free char *line = NULL; + int header_width; + const char *header_name = _(header_name_no_l10n); + + header_width = nmc_string_screen_width (header_name, NULL) + 4; + + if (multiline) { + table_width = NM_MAX (header_width, ML_HEADER_WIDTH); + line = g_strnfill (ML_HEADER_WIDTH, '='); + } else { /* tabular */ + table_width = NM_MAX (table_width, header_width); + line = g_strnfill (table_width, '='); + } + + width1 = strlen (header_name); + width2 = nmc_string_screen_width (header_name, NULL); + g_print ("%s\n", line); + g_print ("%*s\n", (table_width + width2)/2 + width1 - width2, header_name); + g_print ("%s\n", line); + } + + str = !multiline + ? g_string_sized_new (100) + : NULL; + + /* print the header for the tabular form */ + if (!multiline && !terse) { + for (i_col = 0; i_col < col_len; i_col++) { + const PrintDataHeaderCell *header_cell = &header_row[i_col]; + const char *title; + + if (_print_skip_column (nmc_config, header_cell)) + continue; + + title = header_cell->title; + + width1 = strlen (title); + width2 = nmc_string_screen_width (title, NULL); /* Width of the string (in screen colums) */ + g_string_append_printf (str, "%-*s", (int) (header_cell->width + width1 - width2), title); + g_string_append_c (str, ' '); /* Column separator */ + table_width += header_cell->width + width1 - width2 + 1; + } + + if (str->len) + g_string_truncate (str, str->len-1); /* Chop off last column separator */ + g_print ("%s\n", str->str); + g_string_truncate (str, 0); + + /* Print horizontal separator */ + if (pretty) { + gs_free char *line = NULL; + + g_print ("%s\n", (line = g_strnfill (table_width, '-'))); + } + } + + for (i_row = 0; i_row < row_len; i_row++) { + const PrintDataCell *current_line = &cells[i_row * col_len]; + + for (i_col = 0; i_col < col_len; i_col++) { + const PrintDataCell *cell = ¤t_line[i_col]; + const char *const*lines = NULL; + guint i_lines, lines_len; + + if (_print_skip_column (nmc_config, cell->header_cell)) + continue; + + lines_len = 0; + switch (cell->text_format) { + case PRINT_DATA_CELL_FORMAT_TYPE_PLAIN: + lines = &cell->text.plain; + lines_len = 1; + break; + case PRINT_DATA_CELL_FORMAT_TYPE_STRV: + nm_assert (multiline); + lines = cell->text.strv; + lines_len = NM_PTRARRAY_LEN (lines); + break; + } + + for (i_lines = 0; i_lines < lines_len; i_lines++) { + gs_free char *text_to_free = NULL; + const char *text; + + text = colorize_string (nmc_config->use_colors, + cell->term_color, cell->term_format, + lines[i_lines], &text_to_free); + if (multiline) { + gs_free char *prefix = NULL; + + if (cell->text_format == PRINT_DATA_CELL_FORMAT_TYPE_STRV) + prefix = g_strdup_printf ("%s[%u]:", cell->header_cell->title, i_lines + 1); + else + prefix = g_strdup_printf ("%s:", cell->header_cell->title); + width1 = strlen (prefix); + width2 = nmc_string_screen_width (prefix, NULL); + g_print ("%-*s%s\n", (int) (terse ? 0 : ML_VALUE_INDENT+width1-width2), prefix, text); + } else { + nm_assert (str); + if (terse) { + if (nmc_config->escape_values) { + const char *p = text; + while (*p) { + if (*p == ':' || *p == '\\') + g_string_append_c (str, '\\'); /* Escaping by '\' */ + g_string_append_c (str, *p); + p++; + } + } + else + g_string_append_printf (str, "%s", text); + g_string_append_c (str, ':'); /* Column separator */ + } else { + const PrintDataHeaderCell *header_cell = &header_row[i_col]; + + width1 = strlen (text); + width2 = nmc_string_screen_width (text, NULL); /* Width of the string (in screen colums) */ + g_string_append_printf (str, "%-*s", (int) (header_cell->width + width1 - width2), text); + g_string_append_c (str, ' '); /* Column separator */ + table_width += header_cell->width + width1 - width2 + 1; + } + } + } + } + + if (!multiline) { + if (str->len) + g_string_truncate (str, str->len-1); /* Chop off last column separator */ + g_print ("%s\n", str->str); + + g_string_truncate (str, 0); + } + + if ( pretty + && ( i_row < row_len - 1 + || multiline)) { + gs_free char *line = NULL; + + g_print ("%s\n", (line = g_strnfill (ML_HEADER_WIDTH, '-'))); + } + } +} + +gboolean +nmc_print (const NmcConfig *nmc_config, + gpointer const *targets, + const char *header_name_no_l10n, + const NMMetaAbstractInfo *const*fields, + const char *fields_str, + GError **error) +{ + gs_unref_ptrarray GPtrArray *gfree_keeper = NULL; + gs_unref_array GArray *cols = NULL; + gs_unref_array GArray *header_row = NULL; + gs_unref_array GArray *cells = NULL; + + if (!_output_selection_parse (fields, fields_str, + &cols, &gfree_keeper, + error)) + return FALSE; + + _print_fill (nmc_config, + targets, + &g_array_index (cols, PrintDataCol, 0), + cols->len, + &header_row, + &cells); + + _print_do (nmc_config, + header_name_no_l10n, + header_row->len, + cells->len / header_row->len, + &g_array_index (header_row, PrintDataHeaderCell, 0), + &g_array_index (cells, PrintDataCell, 0)); + + return TRUE; +} + +/*****************************************************************************/ + static const char * get_value_to_print (NmcColorOption color_option, const NmcOutputField *field, @@ -1022,7 +1783,7 @@ get_value_to_print (NmcColorOption color_option, nm_assert (out_to_free && !*out_to_free); if (field_name) - value = _(nm_meta_abstract_info_get_name (field->info)); + value = _(nm_meta_abstract_info_get_name (field->info, FALSE)); else { value = field->value ? (is_array @@ -1059,35 +1820,30 @@ print_required_fields (const NmcConfig *nmc_config, int indent, const NmcOutputField *field_values) { - GString *str; + nm_auto_free_gstring GString *str = NULL; int width1, width2; int table_width = 0; - char *line = NULL; - char *indent_str; - const char *not_set_str = "--"; + const char *not_set_str; int i; - gboolean multiline = nmc_config->multiline_output; gboolean terse = (nmc_config->print_output == NMC_PRINT_TERSE); gboolean pretty = (nmc_config->print_output == NMC_PRINT_PRETTY); - gboolean escape = nmc_config->escape_values; gboolean main_header_add = of_flags & NMC_OF_FLAG_MAIN_HEADER_ADD; gboolean main_header_only = of_flags & NMC_OF_FLAG_MAIN_HEADER_ONLY; gboolean field_names = of_flags & NMC_OF_FLAG_FIELD_NAMES; gboolean section_prefix = of_flags & NMC_OF_FLAG_SECTION_PREFIX; - enum { ML_HEADER_WIDTH = 79 }; - enum { ML_VALUE_INDENT = 40 }; - - /* --- Main header --- */ if ((main_header_add || main_header_only) && pretty) { - int header_width = nmc_string_screen_width (header_name, NULL) + 4; + gs_free char *line = NULL; + int header_width; - if (multiline) { - table_width = header_width < ML_HEADER_WIDTH ? ML_HEADER_WIDTH : header_width; + header_width = nmc_string_screen_width (header_name, NULL) + 4; + + if (nmc_config->multiline_output) { + table_width = NM_MAX (header_width, ML_HEADER_WIDTH); line = g_strnfill (ML_HEADER_WIDTH, '='); } else { /* tabular */ - table_width = table_width < header_width ? header_width : table_width; + table_width = NM_MAX (table_width, header_width); line = g_strnfill (table_width, '='); } @@ -1096,23 +1852,20 @@ print_required_fields (const NmcConfig *nmc_config, g_print ("%s\n", line); g_print ("%*s\n", (table_width + width2)/2 + width1 - width2, header_name); g_print ("%s\n", line); - g_free (line); } if (main_header_only) return; /* No field headers are printed in terse mode nor for multiline output */ - if ((terse || multiline) && field_names) + if ((terse || nmc_config->multiline_output) && field_names) return; - if (terse) - not_set_str = ""; /* Don't replace empty strings in terse mode */ + /* Don't replace empty strings in terse mode */ + not_set_str = terse ? "" : "--"; - - if (multiline) { + if (nmc_config->multiline_output) { for (i = 0; i < indices->len; i++) { - char *tmp; int idx = g_array_index (indices, int, i); gboolean is_array = field_values[idx].value_is_array; @@ -1123,31 +1876,35 @@ print_required_fields (const NmcConfig *nmc_config, continue; if (is_array) { - /* value is a null-terminated string array */ - const char **p, *val, *print_val; gs_free char *val_to_free = NULL; + const char **p, *val, *print_val; int j; + /* value is a null-terminated string array */ + for (p = (const char **) field_values[idx].value, j = 1; p && *p; p++, j++) { - val = *p ? *p : not_set_str; + gs_free char *tmp = NULL; + + val = *p ?: not_set_str; print_val = colorize_string (nmc_config->use_colors, field_values[idx].color, field_values[idx].color_fmt, val, &val_to_free); tmp = g_strdup_printf ("%s%s%s[%d]:", section_prefix ? (const char*) field_values[0].value : "", section_prefix ? "." : "", - _(nm_meta_abstract_info_get_name (field_values[idx].info)), + _(nm_meta_abstract_info_get_name (field_values[idx].info, FALSE)), j); width1 = strlen (tmp); width2 = nmc_string_screen_width (tmp, NULL); - g_print ("%-*s%s\n", terse ? 0 : ML_VALUE_INDENT+width1-width2, tmp, print_val); - g_free (tmp); + g_print ("%-*s%s\n", (int) (terse ? 0 : ML_VALUE_INDENT+width1-width2), tmp, print_val); } } else { - /* value is a string */ + gs_free char *val_to_free = NULL; + gs_free char *tmp = NULL; const char *hdr_name = (const char*) field_values[0].value; const char *val = (const char*) field_values[idx].value; const char *print_val; - gs_free char *val_to_free = NULL; + + /* value is a string */ val = val && *val ? val : not_set_str; print_val = colorize_string (nmc_config->use_colors, field_values[idx].color, field_values[idx].color_fmt, @@ -1155,17 +1912,16 @@ print_required_fields (const NmcConfig *nmc_config, tmp = g_strdup_printf ("%s%s%s:", section_prefix ? hdr_name : "", section_prefix ? "." : "", - _(nm_meta_abstract_info_get_name (field_values[idx].info))); + _(nm_meta_abstract_info_get_name (field_values[idx].info, FALSE))); width1 = strlen (tmp); width2 = nmc_string_screen_width (tmp, NULL); - g_print ("%-*s%s\n", terse ? 0 : ML_VALUE_INDENT+width1-width2, tmp, print_val); - g_free (tmp); + g_print ("%-*s%s\n", (int) (terse ? 0 : ML_VALUE_INDENT+width1-width2), tmp, print_val); } } if (pretty) { - line = g_strnfill (ML_HEADER_WIDTH, '-'); - g_print ("%s\n", line); - g_free (line); + gs_free char *line = NULL; + + g_print ("%s\n", (line = g_strnfill (ML_HEADER_WIDTH, '-'))); } return; @@ -1176,13 +1932,17 @@ print_required_fields (const NmcConfig *nmc_config, str = g_string_new (NULL); for (i = 0; i < indices->len; i++) { - int idx = g_array_index (indices, int, i); gs_free char *val_to_free = NULL; - const char *value = get_value_to_print (nmc_config->use_colors, (NmcOutputField *) field_values+idx, field_names, - not_set_str, &val_to_free); + int idx; + const char *value; + + idx = g_array_index (indices, int, i); + + value = get_value_to_print (nmc_config->use_colors, (NmcOutputField *) field_values+idx, field_names, + not_set_str, &val_to_free); if (terse) { - if (escape) { + if (nmc_config->escape_values) { const char *p = value; while (*p) { if (*p == ':' || *p == '\\') @@ -1207,21 +1967,20 @@ print_required_fields (const NmcConfig *nmc_config, if (str->len > 0) { g_string_truncate (str, str->len-1); /* Chop off last column separator */ if (indent > 0) { - indent_str = g_strnfill (indent, ' '); - g_string_prepend (str, indent_str); - g_free (indent_str); + gs_free char *indent_str = NULL; + + g_string_prepend (str, (indent_str = g_strnfill (indent, ' '))); } + g_print ("%s\n", str->str); /* Print horizontal separator */ if (field_names && pretty) { - line = g_strnfill (table_width, '-'); - g_print ("%s\n", line); - g_free (line); + gs_free char *line = NULL; + + g_print ("%s\n", (line = g_strnfill (table_width, '-'))); } } - - g_string_free (str, TRUE); } void diff --git a/clients/cli/utils.h b/clients/cli/utils.h index d212ecb31a..01ad694ae2 100644 --- a/clients/cli/utils.h +++ b/clients/cli/utils.h @@ -63,6 +63,7 @@ void nmc_free_output_field_values (NmcOutputField fields_array[]); typedef struct { const NMMetaAbstractInfo *info; + const char *self_selection; const char *sub_selection; guint idx; } NmcOutputSelectionItem; @@ -73,7 +74,9 @@ typedef struct { } NmcOutputSelection; NmcOutputSelection *nmc_output_selection_create (const NMMetaAbstractInfo *const* fields_array, + const char *fields_prefix, const char *fields_str, + gboolean validate_nested, GError **error); GArray *parse_output_fields (const char *fields_str, @@ -81,8 +84,8 @@ GArray *parse_output_fields (const char *fields_str, gboolean parse_groups, GPtrArray **group_fields, GError **error); -char *nmc_get_allowed_fields_nested (const NMMetaAbstractInfo *abstract_info); -char *nmc_get_allowed_fields (const NMMetaAbstractInfo *const*fields_array); +char *nmc_get_allowed_fields_nested (const NMMetaAbstractInfo *abstract_info, const char *name_prefix); +char *nmc_get_allowed_fields (const NMMetaAbstractInfo *const*fields_array, const char *name_prefix); NmcOutputField *nmc_dup_fields_array (const NMMetaAbstractInfo *const*fields, NmcOfFlags flags); void nmc_empty_output_fields (NmcOutputData *output_data); void print_required_fields (const NmcConfig *nmc_config, @@ -100,9 +103,54 @@ void print_data (const NmcConfig *nmc_config, /*****************************************************************************/ +extern const NMMetaEnvironment *const nmc_meta_environment; +extern NmCli *const nmc_meta_environment_arg; + +typedef enum { + + NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_RUNNING = 0, + NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_VERSION, + NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_STATE, + NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_STARTUP, + NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_CONNECTIVITY, + NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_NETWORKING, + NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WIFI_HW, + NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WIFI, + NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WWAN_HW, + NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WWAN, + NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WIMAX_HW, + NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WIMAX, + _NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_NUM, + + NMC_GENERIC_INFO_TYPE_GENERAL_PERMISSIONS_PERMISSION = 0, + NMC_GENERIC_INFO_TYPE_GENERAL_PERMISSIONS_VALUE, + _NMC_GENERIC_INFO_TYPE_GENERAL_PERMISSIONS_NUM, + + NMC_GENERIC_INFO_TYPE_GENERAL_LOGGING_LEVEL = 0, + NMC_GENERIC_INFO_TYPE_GENERAL_LOGGING_DOMAINS, + _NMC_GENERIC_INFO_TYPE_GENERAL_LOGGING_NUM, + + NMC_GENERIC_INFO_TYPE_IP4_CONFIG_ADDRESS = 0, + NMC_GENERIC_INFO_TYPE_IP4_CONFIG_GATEWAY, + NMC_GENERIC_INFO_TYPE_IP4_CONFIG_ROUTE, + NMC_GENERIC_INFO_TYPE_IP4_CONFIG_DNS, + NMC_GENERIC_INFO_TYPE_IP4_CONFIG_DOMAIN, + NMC_GENERIC_INFO_TYPE_IP4_CONFIG_WINS, + _NMC_GENERIC_INFO_TYPE_IP4_CONFIG_NUM, + +} NmcGenericInfoType; + +#define NMC_HANDLE_TERMFORMAT(color) \ + G_STMT_START { \ + if (get_type == NM_META_ACCESSOR_GET_TYPE_TERMFORMAT) \ + return nm_meta_termformat_pack ((color), NM_META_TERM_FORMAT_NORMAL); \ + } G_STMT_END + struct _NmcMetaGenericInfo { const NMMetaType *meta_type; + NmcGenericInfoType info_type; const char *name; + const char *name_header; const NmcMetaGenericInfo *const*nested; gconstpointer (*get_fcn) (const NMMetaEnvironment *environment, gpointer environment_user_data, @@ -110,6 +158,7 @@ struct _NmcMetaGenericInfo { gpointer target, NMMetaAccessorGetType get_type, NMMetaAccessorGetFlags get_flags, + NMMetaAccessorGetOutFlags *out_flags, gpointer *out_to_free); }; @@ -120,8 +169,17 @@ struct _NmcMetaGenericInfo { __VA_ARGS__ \ })) -#define NMC_META_GENERIC_WITH_NESTED(n, nest) \ - NMC_META_GENERIC (n, .nested = (nest)) +#define NMC_META_GENERIC_WITH_NESTED(n, nest, ...) \ + NMC_META_GENERIC (n, .nested = (nest), __VA_ARGS__) + +/*****************************************************************************/ + +gboolean nmc_print (const NmcConfig *nmc_config, + gpointer const *targets, + const char *header_name_no_l10n, + const NMMetaAbstractInfo *const*fields, + const char *fields_str, + GError **error); /*****************************************************************************/ diff --git a/clients/common/nm-client-utils.c b/clients/common/nm-client-utils.c index 8f8b51606b..84e7061772 100644 --- a/clients/common/nm-client-utils.c +++ b/clients/common/nm-client-utils.c @@ -92,8 +92,8 @@ nmc_string_to_uint (const char *str, gboolean nmc_string_to_bool (const char *str, gboolean *val_bool, GError **error) { - const char *s_true[] = { "true", "yes", "on", NULL }; - const char *s_false[] = { "false", "no", "off", NULL }; + const char *s_true[] = { "true", "yes", "on", "1", NULL }; + const char *s_false[] = { "false", "no", "off", "0", NULL }; g_return_val_if_fail (error == NULL || *error == NULL, FALSE); diff --git a/clients/common/nm-meta-setting-access.c b/clients/common/nm-meta-setting-access.c index 6da71448fc..4b5f82d3e4 100644 --- a/clients/common/nm-meta-setting-access.c +++ b/clients/common/nm-meta-setting-access.c @@ -24,26 +24,31 @@ /*****************************************************************************/ const NMMetaSettingInfoEditor * -nm_meta_setting_info_editor_find_by_name (const char *setting_name) +nm_meta_setting_info_editor_find_by_name (const char *setting_name, gboolean use_alias) { const NMMetaSettingInfo *meta_setting_info; const NMMetaSettingInfoEditor *setting_info; + guint i; g_return_val_if_fail (setting_name, NULL); meta_setting_info = nm_meta_setting_infos_by_name (setting_name); - - if (!meta_setting_info) - return NULL; - - g_return_val_if_fail (nm_streq0 (meta_setting_info->setting_name, setting_name), NULL); - - if (meta_setting_info->meta_type >= G_N_ELEMENTS (nm_meta_setting_infos_editor)) - return NULL; - - setting_info = &nm_meta_setting_infos_editor[meta_setting_info->meta_type]; - - g_return_val_if_fail (setting_info->general == meta_setting_info, NULL); + setting_info = NULL; + if (meta_setting_info) { + nm_assert (nm_streq0 (meta_setting_info->setting_name, setting_name)); + if (meta_setting_info->meta_type < G_N_ELEMENTS (nm_meta_setting_infos_editor)) { + setting_info = &nm_meta_setting_infos_editor[meta_setting_info->meta_type]; + nm_assert (setting_info->general == meta_setting_info); + } + } + if (!setting_info && use_alias) { + for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++) { + if (nm_streq0 (nm_meta_setting_infos_editor[i].alias, setting_name)) { + setting_info = &nm_meta_setting_infos_editor[i]; + break; + } + } + } return setting_info; } @@ -81,7 +86,7 @@ nm_meta_setting_info_editor_find_by_setting (NMSetting *setting) setting_info = nm_meta_setting_info_editor_find_by_gtype (G_OBJECT_TYPE (setting)); - nm_assert (setting_info == nm_meta_setting_info_editor_find_by_name (nm_setting_get_name (setting))); + nm_assert (setting_info == nm_meta_setting_info_editor_find_by_name (nm_setting_get_name (setting), FALSE)); nm_assert (!setting_info || G_TYPE_CHECK_INSTANCE_TYPE (setting, setting_info->general->get_setting_gtype ())); return setting_info; @@ -111,7 +116,7 @@ nm_meta_property_info_find_by_name (const char *setting_name, const char *proper const NMMetaSettingInfoEditor *setting_info; const NMMetaPropertyInfo *property_info; - setting_info = nm_meta_setting_info_editor_find_by_name (setting_name); + setting_info = nm_meta_setting_info_editor_find_by_name (setting_name, FALSE); if (!setting_info) return NULL; @@ -143,6 +148,26 @@ nm_meta_property_info_find_by_setting (NMSetting *setting, const char *property_ return property_info; } +NMSetting * +nm_meta_setting_info_editor_new_setting (const NMMetaSettingInfoEditor *setting_info, + NMMetaAccessorSettingInitType init_type) +{ + NMSetting *setting; + + g_return_val_if_fail (setting_info, NULL); + + setting = g_object_new (setting_info->general->get_setting_gtype (), NULL); + + if ( setting_info->setting_init_fcn + && init_type != NM_META_ACCESSOR_SETTING_INIT_TYPE_DEFAULT) { + setting_info->setting_init_fcn (setting_info, + setting, + init_type); + } + + return setting; +} + /*****************************************************************************/ /* this basically returns NMMetaSettingType.properties, but with type @@ -186,14 +211,14 @@ nm_meta_setting_infos_editor_p (void) /*****************************************************************************/ const char * -nm_meta_abstract_info_get_name (const NMMetaAbstractInfo *abstract_info) +nm_meta_abstract_info_get_name (const NMMetaAbstractInfo *abstract_info, gboolean for_header) { const char *n; nm_assert (abstract_info); nm_assert (abstract_info->meta_type); nm_assert (abstract_info->meta_type->get_name); - n = abstract_info->meta_type->get_name (abstract_info); + n = abstract_info->meta_type->get_name (abstract_info, for_header); nm_assert (n && n[0]); return n; } @@ -223,3 +248,104 @@ nm_meta_abstract_info_get_nested (const NMMetaAbstractInfo *abstract_info, NM_SET_OUT (out_len, 0); return NULL; } + +gconstpointer +nm_meta_abstract_info_get (const NMMetaAbstractInfo *abstract_info, + const NMMetaEnvironment *environment, + gpointer environment_user_data, + gpointer target, + NMMetaAccessorGetType get_type, + NMMetaAccessorGetFlags get_flags, + NMMetaAccessorGetOutFlags *out_flags, + gpointer *out_to_free) +{ + nm_assert (abstract_info); + nm_assert (abstract_info->meta_type); + nm_assert (!out_to_free || !*out_to_free); + nm_assert (out_flags); + + *out_flags = NM_META_ACCESSOR_GET_OUT_FLAGS_NONE; + + if (!abstract_info->meta_type->get_fcn) + g_return_val_if_reached (NULL); + + return abstract_info->meta_type->get_fcn (abstract_info, + environment, + environment_user_data, + target, + get_type, + get_flags, + out_flags, + out_to_free); +} + +const char *const* +nm_meta_abstract_info_complete (const NMMetaAbstractInfo *abstract_info, + const NMMetaEnvironment *environment, + gpointer environment_user_data, + const NMMetaOperationContext *operation_context, + const char *text, + char ***out_to_free) +{ + const char *const*values; + gsize i, j, text_len; + + nm_assert (abstract_info); + nm_assert (abstract_info->meta_type); + nm_assert (out_to_free && !*out_to_free); + + *out_to_free = NULL; + + if (!abstract_info->meta_type->complete_fcn) + return NULL; + + values = abstract_info->meta_type->complete_fcn (abstract_info, + environment, + environment_user_data, + operation_context, + text, + out_to_free); + + nm_assert (!*out_to_free || values == (const char *const*) *out_to_free); + + if (!text || !text[0] || !values || !values[0]) + return values; + + /* for convenience, we all the complete_fcn() implementations to + * ignore "text". We filter out invalid matches here. */ + + text_len = strlen (text); + + if (*out_to_free) { + char **v = *out_to_free; + + for (i =0, j = 0; v[i]; i++) { + if (strncmp (v[i], text, text_len) != 0) + continue; + v[j++] = v[i]; + } + v[j++] = NULL; + return (const char *const*) *out_to_free; + } else { + const char *const*v = values; + char **r; + + for (i = 0, j = 0; v[i]; i++) { + if (strncmp (v[i], text, text_len) != 0) + continue; + j++; + } + if (j == i) + return values; + + r = g_new (char *, j + 1); + v = values; + for (i = 0, j = 0; v[i]; i++) { + if (strncmp (v[i], text, text_len) != 0) + continue; + r[j++] = g_strdup (v[i]); + } + r[j++] = NULL; + return (const char *const*) (*out_to_free = r); + } +} diff --git a/clients/common/nm-meta-setting-access.h b/clients/common/nm-meta-setting-access.h index 553f41136f..9863a96f14 100644 --- a/clients/common/nm-meta-setting-access.h +++ b/clients/common/nm-meta-setting-access.h @@ -25,7 +25,10 @@ /*****************************************************************************/ -const NMMetaSettingInfoEditor *nm_meta_setting_info_editor_find_by_name (const char *setting_name); +NMSetting *nm_meta_setting_info_editor_new_setting (const NMMetaSettingInfoEditor *setting_info, + NMMetaAccessorSettingInitType init_type); + +const NMMetaSettingInfoEditor *nm_meta_setting_info_editor_find_by_name (const char *setting_name, gboolean use_alias); const NMMetaSettingInfoEditor *nm_meta_setting_info_editor_find_by_gtype (GType gtype); const NMMetaSettingInfoEditor *nm_meta_setting_info_editor_find_by_setting (NMSetting *setting); @@ -44,12 +47,28 @@ const NMMetaSettingInfoEditor *const*nm_meta_setting_infos_editor_p (void); /*****************************************************************************/ -const char *nm_meta_abstract_info_get_name (const NMMetaAbstractInfo *abstract_info); +const char *nm_meta_abstract_info_get_name (const NMMetaAbstractInfo *abstract_info, gboolean for_header); const NMMetaAbstractInfo *const*nm_meta_abstract_info_get_nested (const NMMetaAbstractInfo *abstract_info, guint *out_len, gpointer *nested_to_free); +gconstpointer nm_meta_abstract_info_get (const NMMetaAbstractInfo *abstract_info, + const NMMetaEnvironment *environment, + gpointer environment_user_data, + gpointer target, + NMMetaAccessorGetType get_type, + NMMetaAccessorGetFlags get_flags, + NMMetaAccessorGetOutFlags *out_flags, + gpointer *out_to_free); + +const char *const*nm_meta_abstract_info_complete (const NMMetaAbstractInfo *abstract_info, + const NMMetaEnvironment *environment, + gpointer environment_user_data, + const NMMetaOperationContext *operation_context, + const char *text, + char ***out_to_free); + /*****************************************************************************/ #endif /* _NM_META_SETTING_ACCESS_H__ */ diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c index 1af0dbad8d..981ecddf30 100644 --- a/clients/common/nm-meta-setting-desc.c +++ b/clients/common/nm-meta-setting-desc.c @@ -477,6 +477,14 @@ nmc_team_check_config (const char *config, char **out_config, GError **error) return TRUE; } +static const char * +_get_text_hidden (NMMetaAccessorGetType get_type) +{ + if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY) + return _(NM_META_TEXT_HIDDEN); + return NM_META_TEXT_HIDDEN; +} + /*****************************************************************************/ G_GNUC_PRINTF (4, 5) @@ -507,35 +515,52 @@ _env_warn_fcn (const NMMetaEnvironment *environment, const NMMetaPropertyInfo *property_info, char **out_to_free #define ARGS_GET_FCN \ - const NMMetaEnvironment *environment, gpointer environment_user_data, const NMMetaPropertyInfo *property_info, NMSetting *setting, NMMetaAccessorGetType get_type, NMMetaAccessorGetFlags get_flags + const NMMetaPropertyInfo *property_info, const NMMetaEnvironment *environment, gpointer environment_user_data, NMSetting *setting, NMMetaAccessorGetType get_type, NMMetaAccessorGetFlags get_flags, NMMetaAccessorGetOutFlags *out_flags, gpointer *out_to_free #define ARGS_SET_FCN \ - const NMMetaEnvironment *environment, gpointer environment_user_data, const NMMetaPropertyInfo *property_info, NMSetting *setting, const char *value, GError **error + const NMMetaPropertyInfo *property_info, const NMMetaEnvironment *environment, gpointer environment_user_data, NMSetting *setting, const char *value, GError **error #define ARGS_REMOVE_FCN \ - const NMMetaEnvironment *environment, gpointer environment_user_data, const NMMetaPropertyInfo *property_info, NMSetting *setting, const char *value, guint32 idx, GError **error + const NMMetaPropertyInfo *property_info, const NMMetaEnvironment *environment, gpointer environment_user_data, NMSetting *setting, const char *value, guint32 idx, GError **error + +#define ARGS_COMPLETE_FCN \ + const NMMetaPropertyInfo *property_info, const NMMetaEnvironment *environment, gpointer environment_user_data, const NMMetaOperationContext *operation_context, const char *text, char ***out_to_free #define ARGS_VALUES_FCN \ const NMMetaPropertyInfo *property_info, char ***out_to_free -static char * -_get_fcn_name (ARGS_GET_FCN) -{ - nm_assert (nm_streq0 (nm_setting_get_name (setting), property_info->setting_info->general->setting_name)); - return g_strdup (property_info->setting_info->general->setting_name); -} +#define ARGS_SETTING_INIT_FCN \ + const NMMetaSettingInfoEditor *setting_info, NMSetting *setting, NMMetaAccessorSettingInitType init_type -static char * +#define RETURN_UNSUPPORTED_GET_TYPE() \ + G_STMT_START { \ + if (!NM_IN_SET (get_type, \ + NM_META_ACCESSOR_GET_TYPE_PARSABLE, \ + NM_META_ACCESSOR_GET_TYPE_PRETTY)) { \ + nm_assert_not_reached (); \ + return NULL; \ + } \ + } G_STMT_END; + +#define RETURN_STR_TO_FREE(val) \ + G_STMT_START { \ + char *_val = (val); \ + return ((*(out_to_free)) = _val); \ + } G_STMT_END + +static gconstpointer _get_fcn_nmc_with_default (ARGS_GET_FCN) { const char *s; char *s_full; GValue val = G_VALUE_INIT; + RETURN_UNSUPPORTED_GET_TYPE (); + if (property_info->property_typ_data->subtype.get_with_default.fcn (setting)) { if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY) - return g_strdup (_("(default)")); - return g_strdup (""); + return _("(default)"); + return ""; } g_value_init (&val, G_TYPE_STRING); @@ -546,19 +571,22 @@ _get_fcn_nmc_with_default (ARGS_GET_FCN) else s_full = g_strdup (s && *s ? s : " "); g_value_unset (&val); - return s_full; + RETURN_STR_TO_FREE (s_full); } -static char * +static gconstpointer _get_fcn_gobject_impl (const NMMetaPropertyInfo *property_info, NMSetting *setting, - NMMetaAccessorGetType get_type) + NMMetaAccessorGetType get_type, + gpointer *out_to_free) { char *s; const char *s_c; GType gtype_prop; nm_auto_unset_gvalue GValue val = G_VALUE_INIT; + RETURN_UNSUPPORTED_GET_TYPE (); + gtype_prop = _gobject_property_get_gtype (G_OBJECT (setting), property_info->property_name); if (gtype_prop == G_TYPE_BOOLEAN) { @@ -571,53 +599,57 @@ _get_fcn_gobject_impl (const NMMetaPropertyInfo *property_info, s_c = b ? _("yes") : _("no"); else s_c = b ? "yes" : "no"; - s = g_strdup (s_c); + return s_c; } else { g_value_init (&val, G_TYPE_STRING); g_object_get_property (G_OBJECT (setting), property_info->property_name, &val); s = g_value_dup_string (&val); + RETURN_STR_TO_FREE (s); } - return s; } -static char * +static gconstpointer _get_fcn_gobject (ARGS_GET_FCN) { - return _get_fcn_gobject_impl (property_info, setting, get_type); + return _get_fcn_gobject_impl (property_info, setting, get_type, out_to_free); } -static char * +static gconstpointer _get_fcn_gobject_mtu (ARGS_GET_FCN) { guint32 mtu; + RETURN_UNSUPPORTED_GET_TYPE (); + if ( !property_info->property_typ_data || !property_info->property_typ_data->subtype.mtu.get_fcn) - return _get_fcn_gobject_impl (property_info, setting, get_type); + return _get_fcn_gobject_impl (property_info, setting, get_type, out_to_free); mtu = property_info->property_typ_data->subtype.mtu.get_fcn (setting); if (mtu == 0) { if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY) - return g_strdup (_("auto")); - return g_strdup ("auto"); + return _("auto"); + return "auto"; } - return g_strdup_printf ("%u", (unsigned) mtu); + RETURN_STR_TO_FREE (g_strdup_printf ("%u", (unsigned) mtu)); } -static char * +static gconstpointer _get_fcn_gobject_secret_flags (ARGS_GET_FCN) { guint v; GValue val = G_VALUE_INIT; + RETURN_UNSUPPORTED_GET_TYPE (); + g_value_init (&val, G_TYPE_UINT); g_object_get_property (G_OBJECT (setting), property_info->property_name, &val); v = g_value_get_uint (&val); g_value_unset (&val); - return secret_flags_to_string (v, get_type); + RETURN_STR_TO_FREE (secret_flags_to_string (v, get_type)); } -static char * +static gconstpointer _get_fcn_gobject_enum (ARGS_GET_FCN) { GType gtype = 0; @@ -635,6 +667,8 @@ _get_fcn_gobject_enum (ARGS_GET_FCN) gs_free char *s = NULL; char s_numeric[64]; + RETURN_UNSUPPORTED_GET_TYPE (); + if (property_info->property_typ_data) { if (property_info->property_typ_data->subtype.gobject_enum.get_gtype) { gtype = property_info->property_typ_data->subtype.gobject_enum.get_gtype (); @@ -715,11 +749,12 @@ _get_fcn_gobject_enum (ARGS_GET_FCN) })); if (format_numeric && !format_text) { - return format_numeric_hex - || ( format_numeric_hex_unknown - && !G_IS_ENUM_CLASS (gtype_class ?: (gtype_class = g_type_class_ref (gtype)))) - ? g_strdup_printf ("0x%"G_GINT64_FORMAT, v) - : g_strdup_printf ("%"G_GINT64_FORMAT, v); + s = format_numeric_hex + || ( format_numeric_hex_unknown + && !G_IS_ENUM_CLASS (gtype_class ?: (gtype_class = g_type_class_ref (gtype)))) + ? g_strdup_printf ("0x%"G_GINT64_FORMAT, v) + : g_strdup_printf ("%"G_GINT64_FORMAT, v); + RETURN_STR_TO_FREE (s); } /* the gobject_enum.value_infos are currently ignored for the getter. They @@ -728,7 +763,7 @@ _get_fcn_gobject_enum (ARGS_GET_FCN) s = nm_utils_enum_to_str (gtype, (int) v); if (!format_numeric) - return g_steal_pointer (&s); + RETURN_STR_TO_FREE (g_steal_pointer (&s)); if ( format_numeric_hex || ( format_numeric_hex_unknown @@ -738,12 +773,12 @@ _get_fcn_gobject_enum (ARGS_GET_FCN) nm_sprintf_buf (s_numeric, "%"G_GINT64_FORMAT, v); if (nm_streq0 (s, s_numeric)) - return g_steal_pointer (&s); + RETURN_STR_TO_FREE (g_steal_pointer (&s)); if (format_text_l10n) - return g_strdup_printf (_("%s (%s)"), s_numeric, s); + RETURN_STR_TO_FREE (g_strdup_printf (_("%s (%s)"), s_numeric, s)); else - return g_strdup_printf ("%s (%s)", s_numeric, s); + RETURN_STR_TO_FREE (g_strdup_printf ("%s (%s)", s_numeric, s)); } /*****************************************************************************/ @@ -830,7 +865,10 @@ _set_fcn_gobject_int64 (ARGS_SET_FCN) } static gboolean -_set_fcn_gobject_uint (ARGS_SET_FCN) +_set_fcn_gobject_uint_impl (const NMMetaPropertyInfo *property_info, + NMSetting *setting, + const char *value, + GError **error) { unsigned long val_int; @@ -849,12 +887,18 @@ _set_fcn_gobject_uint (ARGS_SET_FCN) return TRUE; } +static gboolean +_set_fcn_gobject_uint (ARGS_SET_FCN) +{ + return _set_fcn_gobject_uint_impl (property_info, setting, value, error); +} + static gboolean _set_fcn_gobject_mtu (ARGS_SET_FCN) { if (nm_streq0 (value, "auto")) value = "0"; - return _set_fcn_gobject_uint (environment, environment_user_data, property_info, setting, value, error); + return _set_fcn_gobject_uint_impl (property_info, setting, value, error); } static gboolean @@ -1046,6 +1090,62 @@ _values_fcn_gobject_enum (ARGS_VALUES_FCN) /*****************************************************************************/ +static const char *const* +_complete_fcn_gobject_bool (ARGS_COMPLETE_FCN) +{ + static const char *const v[] = { + "true", + "false", + "on", + "off", + "1", + "0", + "yes", + "no", + NULL, + }; + + if (!text || !text[0]) + return &v[6]; + return v; +} + +static const char *const* +_complete_fcn_gobject_devices (ARGS_COMPLETE_FCN) +{ + NMDevice *const*devices = NULL; + guint i, j; + guint len = 0; + char **ifnames; + + if ( environment + && environment->get_nm_devices) { + devices = environment->get_nm_devices (environment, + environment_user_data, + &len); + } + + if (len == 0) + return NULL; + + ifnames = g_new (char *, len + 1); + for (i = 0, j = 0; i < len; i++) { + const char *ifname; + + nm_assert (NM_IS_DEVICE (devices[i])); + + ifname = nm_device_get_iface (devices[i]); + if (ifname) + ifnames[j++] = g_strdup (ifname); + } + ifnames[j++] = NULL; + + *out_to_free = ifnames; + return (const char *const*) ifnames; +} + +/*****************************************************************************/ + static char * wep_key_type_to_string (NMWepKeyType type) { @@ -1556,6 +1656,34 @@ _set_fcn_vpn_service_type (ARGS_SET_FCN) return TRUE; } +static const char *const* +_complete_fcn_vpn_service_type (ARGS_COMPLETE_FCN) +{ + gsize i, j; + char **values; + + values = nm_vpn_plugin_info_list_get_service_types (nm_vpn_get_plugin_infos (), FALSE, TRUE); + if (!values) + return NULL; + + if (!text || !*text) { + /* If the prompt text is empty or contains no '.', + * filter out full names. */ + for (i = 0, j = 0; values[i]; i++) { + if (strchr (values[i], '.')) { + g_free (values[i]); + continue; + } + + if (i != j) + values[j] = values[i]; + j++; + } + values[j++] = NULL; + } + return (const char *const*) (*out_to_free = values); +} + static gboolean nmc_util_is_domain (const char *domain) { @@ -1609,12 +1737,14 @@ done: /*****************************************************************************/ -static char * +static gconstpointer _get_fcn_802_1x_ca_cert (ARGS_GET_FCN) { NMSetting8021x *s_8021X = NM_SETTING_802_1X (setting); char *ca_cert_str = NULL; + RETURN_UNSUPPORTED_GET_TYPE (); + switch (nm_setting_802_1x_get_ca_cert_scheme (s_8021X)) { case NM_SETTING_802_1X_CK_SCHEME_BLOB: ca_cert_str = bytes_to_string (nm_setting_802_1x_get_ca_cert_blob (s_8021X)); @@ -1629,21 +1759,23 @@ _get_fcn_802_1x_ca_cert (ARGS_GET_FCN) break; } - return ca_cert_str; + RETURN_STR_TO_FREE (ca_cert_str); } -static char * +static gconstpointer _get_fcn_802_1x_client_cert (ARGS_GET_FCN) { NMSetting8021x *s_8021X = NM_SETTING_802_1X (setting); char *cert_str = NULL; + RETURN_UNSUPPORTED_GET_TYPE (); + switch (nm_setting_802_1x_get_client_cert_scheme (s_8021X)) { case NM_SETTING_802_1X_CK_SCHEME_BLOB: if (NM_FLAGS_HAS (get_flags, NM_META_ACCESSOR_GET_FLAGS_SHOW_SECRETS)) cert_str = bytes_to_string (nm_setting_802_1x_get_client_cert_blob (s_8021X)); else - cert_str = g_strdup (_(NM_META_TEXT_HIDDEN)); + return _get_text_hidden (get_type); break; case NM_SETTING_802_1X_CK_SCHEME_PATH: cert_str = g_strdup (nm_setting_802_1x_get_client_cert_path (s_8021X)); @@ -1655,15 +1787,17 @@ _get_fcn_802_1x_client_cert (ARGS_GET_FCN) break; } - return cert_str; + RETURN_STR_TO_FREE (cert_str); } -static char * +static gconstpointer _get_fcn_802_1x_phase2_ca_cert (ARGS_GET_FCN) { NMSetting8021x *s_8021X = NM_SETTING_802_1X (setting); char *phase2_ca_cert_str = NULL; + RETURN_UNSUPPORTED_GET_TYPE (); + switch (nm_setting_802_1x_get_phase2_ca_cert_scheme (s_8021X)) { case NM_SETTING_802_1X_CK_SCHEME_BLOB: phase2_ca_cert_str = bytes_to_string (nm_setting_802_1x_get_phase2_ca_cert_blob (s_8021X)); @@ -1678,21 +1812,23 @@ _get_fcn_802_1x_phase2_ca_cert (ARGS_GET_FCN) break; } - return phase2_ca_cert_str; + RETURN_STR_TO_FREE (phase2_ca_cert_str); } -static char * +static gconstpointer _get_fcn_802_1x_phase2_client_cert (ARGS_GET_FCN) { NMSetting8021x *s_8021X = NM_SETTING_802_1X (setting); char *cert_str = NULL; + RETURN_UNSUPPORTED_GET_TYPE (); + switch (nm_setting_802_1x_get_phase2_client_cert_scheme (s_8021X)) { case NM_SETTING_802_1X_CK_SCHEME_BLOB: if (NM_FLAGS_HAS (get_flags, NM_META_ACCESSOR_GET_FLAGS_SHOW_SECRETS)) cert_str = bytes_to_string (nm_setting_802_1x_get_phase2_client_cert_blob (s_8021X)); else - cert_str = g_strdup (_(NM_META_TEXT_HIDDEN)); + return _get_text_hidden (get_type); break; case NM_SETTING_802_1X_CK_SCHEME_PATH: cert_str = g_strdup (nm_setting_802_1x_get_phase2_client_cert_path (s_8021X)); @@ -1704,28 +1840,32 @@ _get_fcn_802_1x_phase2_client_cert (ARGS_GET_FCN) break; } - return cert_str; + RETURN_STR_TO_FREE (cert_str); } -static char * +static gconstpointer _get_fcn_802_1x_password_raw (ARGS_GET_FCN) { NMSetting8021x *s_8021X = NM_SETTING_802_1X (setting); - return bytes_to_string (nm_setting_802_1x_get_password_raw (s_8021X)); + + RETURN_UNSUPPORTED_GET_TYPE (); + RETURN_STR_TO_FREE (bytes_to_string (nm_setting_802_1x_get_password_raw (s_8021X))); } -static char * +static gconstpointer _get_fcn_802_1x_private_key (ARGS_GET_FCN) { NMSetting8021x *s_8021X = NM_SETTING_802_1X (setting); char *key_str = NULL; + RETURN_UNSUPPORTED_GET_TYPE (); + switch (nm_setting_802_1x_get_private_key_scheme (s_8021X)) { case NM_SETTING_802_1X_CK_SCHEME_BLOB: if (NM_FLAGS_HAS (get_flags, NM_META_ACCESSOR_GET_FLAGS_SHOW_SECRETS)) key_str = bytes_to_string (nm_setting_802_1x_get_private_key_blob (s_8021X)); else - key_str = g_strdup (_(NM_META_TEXT_HIDDEN)); + return _get_text_hidden (get_type); break; case NM_SETTING_802_1X_CK_SCHEME_PATH: key_str = g_strdup (nm_setting_802_1x_get_private_key_path (s_8021X)); @@ -1737,21 +1877,23 @@ _get_fcn_802_1x_private_key (ARGS_GET_FCN) break; } - return key_str; + RETURN_STR_TO_FREE (key_str); } -static char * +static gconstpointer _get_fcn_802_1x_phase2_private_key (ARGS_GET_FCN) { NMSetting8021x *s_8021X = NM_SETTING_802_1X (setting); char *key_str = NULL; + RETURN_UNSUPPORTED_GET_TYPE (); + switch (nm_setting_802_1x_get_phase2_private_key_scheme (s_8021X)) { case NM_SETTING_802_1X_CK_SCHEME_BLOB: if (NM_FLAGS_HAS (get_flags, NM_META_ACCESSOR_GET_FLAGS_SHOW_SECRETS)) key_str = bytes_to_string (nm_setting_802_1x_get_phase2_private_key_blob (s_8021X)); else - key_str = g_strdup (_(NM_META_TEXT_HIDDEN)); + return _get_text_hidden (get_type); break; case NM_SETTING_802_1X_CK_SCHEME_PATH: key_str = g_strdup (nm_setting_802_1x_get_phase2_private_key_path (s_8021X)); @@ -1763,7 +1905,7 @@ _get_fcn_802_1x_phase2_private_key (ARGS_GET_FCN) break; } - return key_str; + RETURN_STR_TO_FREE (key_str); } #define DEFINE_SETTER_STR_LIST(def_func, set_func) \ @@ -1928,13 +2070,15 @@ _set_fcn_802_1x_password_raw (ARGS_SET_FCN) return nmc_property_set_byte_array (setting, property_info->property_name, value, error); } -static char * +static gconstpointer _get_fcn_bond_options (ARGS_GET_FCN) { NMSettingBond *s_bond = NM_SETTING_BOND (setting); GString *bond_options_s; int i; + RETURN_UNSUPPORTED_GET_TYPE (); + bond_options_s = g_string_new (NULL); for (i = 0; i < nm_setting_bond_get_num_options (s_bond); i++) { const char *key, *value; @@ -1955,7 +2099,7 @@ _get_fcn_bond_options (ARGS_GET_FCN) } g_string_truncate (bond_options_s, bond_options_s->len-1); /* chop off trailing ',' */ - return g_string_free (bond_options_s, FALSE); + RETURN_STR_TO_FREE (g_string_free (bond_options_s, FALSE)); } /* example: miimon=100,mode=balance-rr, updelay=5 */ @@ -2042,27 +2186,36 @@ _values_fcn_bond_options (ARGS_VALUES_FCN) return nm_setting_bond_get_valid_options (NULL); } -static char * +static gconstpointer _get_fcn_connection_autoconnect_retires (ARGS_GET_FCN) { NMSettingConnection *s_con = NM_SETTING_CONNECTION (setting); gint retries; + char *s; + + RETURN_UNSUPPORTED_GET_TYPE (); retries = nm_setting_connection_get_autoconnect_retries (s_con); if (get_type != NM_META_ACCESSOR_GET_TYPE_PRETTY) - return g_strdup_printf ("%d", retries); - - switch (retries) { - case -1: - return g_strdup_printf (_("%d (default)"), retries); - case 0: - return g_strdup_printf (_("%d (forever)"), retries); - default: - return g_strdup_printf ("%d", retries); + s = g_strdup_printf ("%d", retries); + else { + switch (retries) { + case -1: + s = g_strdup_printf (_("%d (default)"), retries); + break; + case 0: + s = g_strdup_printf (_("%d (forever)"), retries); + break; + default: + s = g_strdup_printf ("%d", retries); + break; + } } + + RETURN_STR_TO_FREE (s); } -static char * +static gconstpointer _get_fcn_connection_permissions (ARGS_GET_FCN) { NMSettingConnection *s_con = NM_SETTING_CONNECTION (setting); @@ -2071,6 +2224,8 @@ _get_fcn_connection_permissions (ARGS_GET_FCN) const char *perm_type; int i; + RETURN_UNSUPPORTED_GET_TYPE (); + perm = g_string_new (NULL); for (i = 0; i < nm_setting_connection_get_num_permissions (s_con); i++) { if (nm_setting_connection_get_permission (s_con, i, &perm_type, &perm_item, NULL)) @@ -2078,18 +2233,20 @@ _get_fcn_connection_permissions (ARGS_GET_FCN) } if (perm->len > 0) { g_string_truncate (perm, perm->len-1); /* remove trailing , */ - return g_string_free (perm, FALSE); + RETURN_STR_TO_FREE (g_string_free (perm, FALSE)); } /* No value from get_permission */ - return g_string_free (perm, TRUE); + g_string_free (perm, TRUE); + return NULL; } -static char * +static gconstpointer _get_fcn_connection_autoconnect_slaves (ARGS_GET_FCN) { NMSettingConnection *s_con = NM_SETTING_CONNECTION (setting); - return autoconnect_slaves_to_string (nm_setting_connection_get_autoconnect_slaves (s_con), get_type); + RETURN_UNSUPPORTED_GET_TYPE (); + RETURN_STR_TO_FREE (autoconnect_slaves_to_string (nm_setting_connection_get_autoconnect_slaves (s_con), get_type)); } static gboolean @@ -2118,6 +2275,37 @@ _set_fcn_connection_type (ARGS_SET_FCN) return TRUE; } +static const char *const* +_complete_fcn_connection_type (ARGS_COMPLETE_FCN) +{ + guint i, j; + char **result; + gsize text_len; + + result = g_new (char *, _NM_META_SETTING_TYPE_NUM * 2 + 1); + + text_len = text ? strlen (text) : 0; + + for (i = 0, j = 0; i < _NM_META_SETTING_TYPE_NUM; i++) { + const NMMetaSettingInfoEditor *setting_info = &nm_meta_setting_infos_editor[i]; + const char *v; + + v = setting_info->alias; + if (v) { + if (!text || strncmp (text, v, text_len) == 0) + result[j++] = g_strdup (v); + } + if (!text || !*text || !v) { + v = setting_info->general->setting_name; + if (!text || strncmp (text, v, text_len) == 0) + result[j++] = g_strdup (v); + } + } + result[j++] = NULL; + + return (const char *const*) (*out_to_free = result); +} + /* define from libnm-core/nm-setting-connection.c */ #define PERM_USER_PREFIX "user:" @@ -2205,6 +2393,68 @@ _set_fcn_connection_master (ARGS_SET_FCN) return TRUE; } +static const char *const* +_complete_fcn_connection_master (ARGS_COMPLETE_FCN) +{ + NMRemoteConnection *const*connections = NULL; + guint len = 0; + guint i, j; + char **result; + NMSettingConnection *s_con; + const char *expected_type = NULL; + gsize text_len; + + if ( environment + && environment->get_nm_connections) { + connections = environment->get_nm_connections (environment, + environment_user_data, + &len); + } + if (!len) + return NULL; + + if ( (!text || !*text) + && operation_context + && operation_context->connection) { + /* if we have no text yet, initially only complete for matching + * slave-type. */ + s_con = nm_connection_get_setting_connection (operation_context->connection); + if (s_con) + expected_type = nm_setting_connection_get_slave_type (s_con); + } + + text_len = strlen (text); + + result = g_new (char *, (2 * len) + 1); + for (i = 0, j = 0; i < len; i++) { + const char *v; + + s_con = nm_connection_get_setting_connection (NM_CONNECTION (connections[i])); + if (!s_con) + continue; + + if ( expected_type + && !nm_streq0 (nm_setting_connection_get_connection_type (s_con), + expected_type)) + continue; + + if (text && text[0]) { + /* if we have text, also complete for the UUID. */ + v = nm_setting_connection_get_uuid (s_con); + if (v && (!text || strncmp (text, v, text_len) == 0)) + result[j++] = g_strdup (v); + } + + v = nm_setting_connection_get_interface_name (s_con); + if (v && (!text || strncmp (text, v, text_len) == 0)) + result[j++] = g_strdup (v); + } + result[j++] = NULL; + + *out_to_free = NULL; + return (const char *const*) result; +} + static gboolean _set_fcn_connection_secondaries (ARGS_SET_FCN) { @@ -2246,31 +2496,27 @@ DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_connection_secondaries, nm_setting_connection_remove_secondary, _validate_and_remove_connection_secondary) -static char * +static gconstpointer _get_fcn_connection_metered (ARGS_GET_FCN) { NMSettingConnection *s_conn = NM_SETTING_CONNECTION (setting); + const char *s; + + RETURN_UNSUPPORTED_GET_TYPE (); - if (get_type != NM_META_ACCESSOR_GET_TYPE_PRETTY) { - switch (nm_setting_connection_get_metered (s_conn)) { - case NM_METERED_YES: - return g_strdup ("yes"); - case NM_METERED_NO: - return g_strdup ("no"); - case NM_METERED_UNKNOWN: - default: - return g_strdup ("unknown"); - } - } switch (nm_setting_connection_get_metered (s_conn)) { case NM_METERED_YES: - return g_strdup (_("yes")); + s = N_("yes"); case NM_METERED_NO: - return g_strdup (_("no")); + s = N_("no"); case NM_METERED_UNKNOWN: default: - return g_strdup (_("unknown")); + s = N_("unknown"); + break; } + if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY) + return _(s); + return s; } static gboolean @@ -2329,16 +2575,18 @@ dcb_flags_to_string (NMSettingDcbFlags flags) } #define DEFINE_DCB_FLAGS_GETTER(func_name, property_name) \ - static char * \ + static gconstpointer \ func_name (ARGS_GET_FCN) \ { \ guint v; \ GValue val = G_VALUE_INIT; \ + \ + RETURN_UNSUPPORTED_GET_TYPE (); \ g_value_init (&val, G_TYPE_UINT); \ g_object_get_property (G_OBJECT (setting), property_name, &val); \ v = g_value_get_uint (&val); \ g_value_unset (&val); \ - return dcb_flags_to_string (v); \ + RETURN_STR_TO_FREE (dcb_flags_to_string (v)); \ } static char * @@ -2348,56 +2596,61 @@ dcb_app_priority_to_string (gint priority) } #define DEFINE_DCB_APP_PRIORITY_GETTER(func_name, property_name) \ - static char * \ + static gconstpointer \ func_name (ARGS_GET_FCN) \ { \ int v; \ GValue val = G_VALUE_INIT; \ + \ + RETURN_UNSUPPORTED_GET_TYPE (); \ g_value_init (&val, G_TYPE_INT); \ g_object_get_property (G_OBJECT (setting), property_name, &val); \ v = g_value_get_int (&val); \ g_value_unset (&val); \ - return dcb_app_priority_to_string (v); \ + RETURN_STR_TO_FREE (dcb_app_priority_to_string (v)); \ } #define DEFINE_DCB_BOOL_GETTER(func_name, getter_func_name) \ - static char * \ + static gconstpointer \ func_name (ARGS_GET_FCN) \ { \ NMSettingDcb *s_dcb = NM_SETTING_DCB (setting); \ GString *str; \ guint i; \ -\ + \ + RETURN_UNSUPPORTED_GET_TYPE (); \ + \ str = g_string_new (NULL); \ for (i = 0; i < 8; i++) { \ if (getter_func_name (s_dcb, i)) \ g_string_append_c (str, '1'); \ else \ g_string_append_c (str, '0'); \ -\ if (i < 7) \ g_string_append_c (str, ','); \ } \ -\ - return g_string_free (str, FALSE); \ + \ + RETURN_STR_TO_FREE (g_string_free (str, FALSE)); \ } #define DEFINE_DCB_UINT_GETTER(func_name, getter_func_name) \ - static char * \ + static gconstpointer \ func_name (ARGS_GET_FCN) \ { \ NMSettingDcb *s_dcb = NM_SETTING_DCB (setting); \ GString *str; \ guint i; \ - \ + \ + RETURN_UNSUPPORTED_GET_TYPE (); \ + \ str = g_string_new (NULL); \ for (i = 0; i < 8; i++) { \ g_string_append_printf (str, "%u", getter_func_name (s_dcb, i)); \ if (i < 7) \ g_string_append_c (str, ','); \ } \ -\ - return g_string_free (str, FALSE); \ + \ + RETURN_STR_TO_FREE (g_string_free (str, FALSE)); \ } DEFINE_DCB_FLAGS_GETTER (_get_fcn_dcb_app_fcoe_flags, NM_SETTING_DCB_APP_FCOE_FLAGS) @@ -2717,30 +2970,34 @@ _set_fcn_infiniband_p_key (ARGS_SET_FCN) } -static char * +static gconstpointer _get_fcn_infiniband_p_key (ARGS_GET_FCN) { NMSettingInfiniband *s_infiniband = NM_SETTING_INFINIBAND (setting); int p_key; + RETURN_UNSUPPORTED_GET_TYPE (); + p_key = nm_setting_infiniband_get_p_key (s_infiniband); if (p_key == -1) { if (get_type != NM_META_ACCESSOR_GET_TYPE_PRETTY) - return g_strdup ("default"); + return "default"; else - return g_strdup (_("default")); + return _("default"); } else - return g_strdup_printf ("0x%04x", p_key); + RETURN_STR_TO_FREE (g_strdup_printf ("0x%04x", p_key)); } -static char * +static gconstpointer _get_fcn_ip_tunnel_mode (ARGS_GET_FCN) { NMSettingIPTunnel *s_ip_tunnel = NM_SETTING_IP_TUNNEL (setting); NMIPTunnelMode mode; + RETURN_UNSUPPORTED_GET_TYPE (); + mode = nm_setting_ip_tunnel_get_mode (s_ip_tunnel); - return nm_utils_enum_to_str (nm_ip_tunnel_mode_get_type (), mode); + RETURN_STR_TO_FREE (nm_utils_enum_to_str (nm_ip_tunnel_mode_get_type (), mode)); } static gboolean @@ -2781,7 +3038,7 @@ _parse_ip_address (int family, const char *address, GError **error) return ipaddr; } -static char * +static gconstpointer _get_fcn_ip_config_addresses (ARGS_GET_FCN) { NMSettingIPConfig *s_ip = NM_SETTING_IP_CONFIG (setting); @@ -2789,6 +3046,8 @@ _get_fcn_ip_config_addresses (ARGS_GET_FCN) guint32 num_addresses, i; NMIPAddress *addr; + RETURN_UNSUPPORTED_GET_TYPE (); + printable = g_string_new (NULL); num_addresses = nm_setting_ip_config_get_num_addresses (s_ip); @@ -2803,10 +3062,10 @@ _get_fcn_ip_config_addresses (ARGS_GET_FCN) nm_ip_address_get_prefix (addr)); } - return g_string_free (printable, FALSE); + RETURN_STR_TO_FREE (g_string_free (printable, FALSE)); } -static char * +static gconstpointer _get_fcn_ip_config_routes (ARGS_GET_FCN) { NMSettingIPConfig *s_ip = NM_SETTING_IP_CONFIG (setting); @@ -2814,6 +3073,8 @@ _get_fcn_ip_config_routes (ARGS_GET_FCN) guint32 num_routes, i; NMIPRoute *route; + RETURN_UNSUPPORTED_GET_TYPE (); + printable = g_string_new (NULL); num_routes = nm_setting_ip_config_get_num_routes (s_ip); @@ -2872,26 +3133,28 @@ _get_fcn_ip_config_routes (ARGS_GET_FCN) } } - return g_string_free (printable, FALSE); + RETURN_STR_TO_FREE (g_string_free (printable, FALSE)); } -static char * +static gconstpointer _get_fcn_ip4_config_dad_timeout (ARGS_GET_FCN) { NMSettingIPConfig *s_ip = NM_SETTING_IP_CONFIG (setting); gint dad_timeout; + RETURN_UNSUPPORTED_GET_TYPE (); + dad_timeout = nm_setting_ip_config_get_dad_timeout (s_ip); if (get_type != NM_META_ACCESSOR_GET_TYPE_PRETTY) - return g_strdup_printf ("%d", dad_timeout); + RETURN_STR_TO_FREE (g_strdup_printf ("%d", dad_timeout)); switch (dad_timeout) { case -1: - return g_strdup_printf (_("%d (default)"), dad_timeout); + RETURN_STR_TO_FREE (g_strdup_printf (_("%d (default)"), dad_timeout)); case 0: - return g_strdup_printf (_("%d (off)"), dad_timeout); + RETURN_STR_TO_FREE (g_strdup_printf (_("%d (off)"), dad_timeout)); default: - return g_strdup_printf ("%d", dad_timeout); + RETURN_STR_TO_FREE (g_strdup_printf ("%d", dad_timeout)); } } @@ -3164,11 +3427,12 @@ DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_ipv4_config_routes, nm_setting_ip_config_remove_route, _validate_and_remove_ipv4_route) -static char * +static gconstpointer _get_fcn_ip6_config_ip6_privacy (ARGS_GET_FCN) { NMSettingIP6Config *s_ip6 = NM_SETTING_IP6_CONFIG (setting); - return ip6_privacy_to_string (nm_setting_ip6_config_get_ip6_privacy (s_ip6), get_type); + RETURN_UNSUPPORTED_GET_TYPE (); + RETURN_STR_TO_FREE (ip6_privacy_to_string (nm_setting_ip6_config_get_ip6_privacy (s_ip6), get_type)); } static const char *ipv6_valid_methods[] = { @@ -3463,14 +3727,16 @@ _set_fcn_ip6_config_ip6_privacy (ARGS_SET_FCN) return TRUE; } -static char * +static gconstpointer _get_fcn_macsec_mode (ARGS_GET_FCN) { NMSettingMacsec *s_macsec = NM_SETTING_MACSEC (setting); NMSettingMacsecMode mode; + RETURN_UNSUPPORTED_GET_TYPE (); + mode = nm_setting_macsec_get_mode (s_macsec); - return nm_utils_enum_to_str (nm_setting_macsec_mode_get_type (), mode); + RETURN_STR_TO_FREE (nm_utils_enum_to_str (nm_setting_macsec_mode_get_type (), mode)); } static gboolean @@ -3494,14 +3760,16 @@ _set_fcn_macsec_mode (ARGS_SET_FCN) return TRUE; } -static char * +static gconstpointer _get_fcn_macsec_validation (ARGS_GET_FCN) { NMSettingMacsec *s_macsec = NM_SETTING_MACSEC (setting); NMSettingMacsecValidation validation; + RETURN_UNSUPPORTED_GET_TYPE (); + validation = nm_setting_macsec_get_validation (s_macsec); - return nm_utils_enum_to_str (nm_setting_macsec_validation_get_type (), validation); + RETURN_STR_TO_FREE (nm_utils_enum_to_str (nm_setting_macsec_validation_get_type (), validation)); } static gboolean @@ -3525,23 +3793,26 @@ _set_fcn_macsec_validation (ARGS_SET_FCN) return TRUE; } -static char * +static gconstpointer _get_fcn_macvlan_mode (ARGS_GET_FCN) { NMSettingMacvlan *s_macvlan = NM_SETTING_MACVLAN (setting); NMSettingMacvlanMode mode; char *tmp, *str; + RETURN_UNSUPPORTED_GET_TYPE (); + mode = nm_setting_macvlan_get_mode (s_macvlan); tmp = nm_utils_enum_to_str (nm_setting_macvlan_mode_get_type (), mode); if (get_type != NM_META_ACCESSOR_GET_TYPE_PRETTY) - str = g_strdup (tmp ? tmp : ""); - else - str = g_strdup_printf ("%d (%s)", mode, tmp ? tmp : ""); - g_free (tmp); + str = tmp ?: g_strdup (""); + else { + str = g_strdup_printf ("%d (%s)", mode, tmp ?: ""); + g_free (tmp); + } - return str; + RETURN_STR_TO_FREE (str); } static gboolean @@ -3574,20 +3845,22 @@ _set_fcn_macvlan_mode (ARGS_SET_FCN) return TRUE; } -static char * +static gconstpointer _get_fcn_olpc_mesh_ssid (ARGS_GET_FCN) { NMSettingOlpcMesh *s_olpc_mesh = NM_SETTING_OLPC_MESH (setting); GBytes *ssid; char *ssid_str = NULL; + RETURN_UNSUPPORTED_GET_TYPE (); + ssid = nm_setting_olpc_mesh_get_ssid (s_olpc_mesh); if (ssid) { ssid_str = nm_utils_ssid_to_utf8 (g_bytes_get_data (ssid, NULL), g_bytes_get_size (ssid)); } - return ssid_str; + RETURN_STR_TO_FREE (ssid_str); } static gboolean @@ -3605,14 +3878,16 @@ _set_fcn_olpc_mesh_channel (ARGS_SET_FCN) return TRUE; } -static char * +static gconstpointer _get_fcn_proxy_method (ARGS_GET_FCN) { NMSettingProxy *s_proxy = NM_SETTING_PROXY (setting); NMSettingProxyMethod method; + RETURN_UNSUPPORTED_GET_TYPE (); + method = nm_setting_proxy_get_method (s_proxy); - return nm_utils_enum_to_str (nm_setting_proxy_method_get_type (), method); + RETURN_STR_TO_FREE (nm_utils_enum_to_str (nm_setting_proxy_method_get_type (), method)); } static gboolean @@ -3657,19 +3932,21 @@ _set_fcn_proxy_pac_script (ARGS_SET_FCN) return TRUE; } -static char * +static gconstpointer _get_fcn_serial_parity (ARGS_GET_FCN) { NMSettingSerial *s_serial = NM_SETTING_SERIAL (setting); + RETURN_UNSUPPORTED_GET_TYPE (); + switch (nm_setting_serial_get_parity (s_serial)) { case NM_SETTING_SERIAL_PARITY_EVEN: - return g_strdup ("even"); + return "even"; case NM_SETTING_SERIAL_PARITY_ODD: - return g_strdup ("odd"); + return "odd"; default: case NM_SETTING_SERIAL_PARITY_NONE: - return g_strdup ("none"); + return "none"; } } @@ -3708,21 +3985,24 @@ _set_fcn_team_config (ARGS_SET_FCN) return TRUE; } -static char * +static gconstpointer _get_fcn_tun_mode (ARGS_GET_FCN) { NMSettingTun *s_tun = NM_SETTING_TUN (setting); NMSettingTunMode mode; char *tmp, *str; + RETURN_UNSUPPORTED_GET_TYPE (); + mode = nm_setting_tun_get_mode (s_tun); tmp = nm_utils_enum_to_str (nm_setting_tun_mode_get_type (), mode); if (get_type != NM_META_ACCESSOR_GET_TYPE_PRETTY) - str = g_strdup_printf ("%s", tmp ? tmp : ""); - else + str = tmp ?: g_strdup (""); + else { str = g_strdup_printf ("%d (%s)", mode, tmp ? tmp : ""); - g_free (tmp); - return str; + g_free (tmp); + } + RETURN_STR_TO_FREE (str); } static gboolean @@ -3749,25 +4029,28 @@ _set_fcn_tun_mode (ARGS_SET_FCN) return TRUE; } -static char * +static gconstpointer _get_fcn_vlan_flags (ARGS_GET_FCN) { NMSettingVlan *s_vlan = NM_SETTING_VLAN (setting); - return vlan_flags_to_string (nm_setting_vlan_get_flags (s_vlan), get_type); + RETURN_UNSUPPORTED_GET_TYPE (); + RETURN_STR_TO_FREE (vlan_flags_to_string (nm_setting_vlan_get_flags (s_vlan), get_type)); } -static char * +static gconstpointer _get_fcn_vlan_ingress_priority_map (ARGS_GET_FCN) { NMSettingVlan *s_vlan = NM_SETTING_VLAN (setting); - return vlan_priorities_to_string (s_vlan, NM_VLAN_INGRESS_MAP); + RETURN_UNSUPPORTED_GET_TYPE (); + RETURN_STR_TO_FREE (vlan_priorities_to_string (s_vlan, NM_VLAN_INGRESS_MAP)); } -static char * +static gconstpointer _get_fcn_vlan_egress_priority_map (ARGS_GET_FCN) { NMSettingVlan *s_vlan = NM_SETTING_VLAN (setting); - return vlan_priorities_to_string (s_vlan, NM_VLAN_EGRESS_MAP); + RETURN_UNSUPPORTED_GET_TYPE (); + RETURN_STR_TO_FREE (vlan_priorities_to_string (s_vlan, NM_VLAN_EGRESS_MAP)); } static gboolean @@ -3880,28 +4163,32 @@ _remove_fcn_vlan_egress_priority_map (ARGS_REMOVE_FCN) error); } -static char * +static gconstpointer _get_fcn_vpn_data (ARGS_GET_FCN) { NMSettingVpn *s_vpn = NM_SETTING_VPN (setting); GString *data_item_str; + RETURN_UNSUPPORTED_GET_TYPE (); + data_item_str = g_string_new (NULL); nm_setting_vpn_foreach_data_item (s_vpn, &vpn_data_item, data_item_str); - return g_string_free (data_item_str, FALSE); + RETURN_STR_TO_FREE (g_string_free (data_item_str, FALSE)); } -static char * +static gconstpointer _get_fcn_vpn_secrets (ARGS_GET_FCN) { NMSettingVpn *s_vpn = NM_SETTING_VPN (setting); GString *secret_str; + RETURN_UNSUPPORTED_GET_TYPE (); + secret_str = g_string_new (NULL); nm_setting_vpn_foreach_secret (s_vpn, &vpn_data_item, secret_str); - return g_string_free (secret_str, FALSE); + RETURN_STR_TO_FREE (g_string_free (secret_str, FALSE)); } static const char * @@ -3936,13 +4223,15 @@ DEFINE_REMOVER_OPTION (_remove_fcn_vpn_secrets, NM_SETTING_VPN, nm_setting_vpn_remove_secret) -static char * +static gconstpointer _get_fcn_wired_wake_on_lan (ARGS_GET_FCN) { NMSettingWired *s_wired = NM_SETTING_WIRED (setting); NMSettingWiredWakeOnLan wol; char *tmp, *str; + RETURN_UNSUPPORTED_GET_TYPE (); + wol = nm_setting_wired_get_wake_on_lan (s_wired); tmp = nm_utils_enum_to_str (nm_setting_wired_wake_on_lan_get_type (), wol); if (get_type != NM_META_ACCESSOR_GET_TYPE_PRETTY) @@ -3950,7 +4239,7 @@ _get_fcn_wired_wake_on_lan (ARGS_GET_FCN) else str = g_strdup_printf ("%d (%s)", wol, tmp && *tmp ? tmp : "none"); g_free (tmp); - return str; + RETURN_STR_TO_FREE (str); } static gboolean @@ -4088,36 +4377,45 @@ _describe_fcn_wired_s390_options (ARGS_DESCRIBE_FCN) } -static char * +static gconstpointer _get_fcn_wireless_ssid (ARGS_GET_FCN) { NMSettingWireless *s_wireless = NM_SETTING_WIRELESS (setting); GBytes *ssid; char *ssid_str = NULL; + RETURN_UNSUPPORTED_GET_TYPE (); + ssid = nm_setting_wireless_get_ssid (s_wireless); if (ssid) { ssid_str = nm_utils_ssid_to_utf8 (g_bytes_get_data (ssid, NULL), g_bytes_get_size (ssid)); } - return ssid_str; + RETURN_STR_TO_FREE (ssid_str); } -static char * +static gconstpointer _get_fcn_wireless_mac_address_randomization (ARGS_GET_FCN) { NMSettingWireless *s_wifi = NM_SETTING_WIRELESS (setting); NMSettingMacRandomization randomization = nm_setting_wireless_get_mac_address_randomization (s_wifi); + const char *s; + + RETURN_UNSUPPORTED_GET_TYPE (); if (randomization == NM_SETTING_MAC_RANDOMIZATION_DEFAULT) - return g_strdup (_("default")); + s = N_("default"); else if (randomization == NM_SETTING_MAC_RANDOMIZATION_NEVER) - return g_strdup (_("never")); + s = N_("never"); else if (randomization == NM_SETTING_MAC_RANDOMIZATION_ALWAYS) - return g_strdup_printf (_("always")); + s = N_("always"); else - return g_strdup_printf (_("unknown")); + s = N_("unknown"); + + if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY) + return _(s); + return s; } static gboolean @@ -4200,38 +4498,47 @@ _set_fcn_wireless_mac_address_randomization (ARGS_SET_FCN) return TRUE; } -static char * +static gconstpointer _get_fcn_wireless_security_wep_key0 (ARGS_GET_FCN) { NMSettingWirelessSecurity *s_wireless_sec = NM_SETTING_WIRELESS_SECURITY (setting); - return g_strdup (nm_setting_wireless_security_get_wep_key (s_wireless_sec, 0)); + + RETURN_UNSUPPORTED_GET_TYPE (); + RETURN_STR_TO_FREE (g_strdup (nm_setting_wireless_security_get_wep_key (s_wireless_sec, 0))); } -static char * +static gconstpointer _get_fcn_wireless_security_wep_key1 (ARGS_GET_FCN) { NMSettingWirelessSecurity *s_wireless_sec = NM_SETTING_WIRELESS_SECURITY (setting); - return g_strdup (nm_setting_wireless_security_get_wep_key (s_wireless_sec, 1)); + + RETURN_UNSUPPORTED_GET_TYPE (); + RETURN_STR_TO_FREE (g_strdup (nm_setting_wireless_security_get_wep_key (s_wireless_sec, 1))); } -static char * +static gconstpointer _get_fcn_wireless_security_wep_key2 (ARGS_GET_FCN) { NMSettingWirelessSecurity *s_wireless_sec = NM_SETTING_WIRELESS_SECURITY (setting); - return g_strdup (nm_setting_wireless_security_get_wep_key (s_wireless_sec, 2)); + + RETURN_UNSUPPORTED_GET_TYPE (); + RETURN_STR_TO_FREE (g_strdup (nm_setting_wireless_security_get_wep_key (s_wireless_sec, 2))); } -static char * +static gconstpointer _get_fcn_wireless_security_wep_key3 (ARGS_GET_FCN) { NMSettingWirelessSecurity *s_wireless_sec = NM_SETTING_WIRELESS_SECURITY (setting); - return g_strdup (nm_setting_wireless_security_get_wep_key (s_wireless_sec, 3)); + + RETURN_UNSUPPORTED_GET_TYPE (); + RETURN_STR_TO_FREE (g_strdup (nm_setting_wireless_security_get_wep_key (s_wireless_sec, 3))); } -static char * +static gconstpointer _get_fcn_wireless_security_wep_key_type (ARGS_GET_FCN) { - return wep_key_type_to_string (nm_setting_wireless_security_get_wep_key_type (NM_SETTING_WIRELESS_SECURITY (setting))); + RETURN_UNSUPPORTED_GET_TYPE (); + RETURN_STR_TO_FREE (wep_key_type_to_string (nm_setting_wireless_security_get_wep_key_type (NM_SETTING_WIRELESS_SECURITY (setting)))); } static const char *wifi_sec_valid_protos[] = { "wpa", "rsn", NULL }; @@ -4457,6 +4764,77 @@ _set_fcn_wireless_security_psk (ARGS_SET_FCN) /*****************************************************************************/ +static const NMMetaPropertyInfo property_infos_BOND[]; + +#define NESTED_PROPERTY_INFO_BOND \ + .meta_type = &nm_meta_type_nested_property_info, \ + .parent_info = &property_infos_BOND[0] + +static const NMMetaNestedPropertyTypeInfo meta_nested_property_type_infos_bond[] = { + { + NESTED_PROPERTY_INFO_BOND, + .field_name = "mode", + .prompt = NM_META_TEXT_PROMPT_BOND_MODE, + .def_hint = "[balance-rr]", + }, + { + NESTED_PROPERTY_INFO_BOND, + .field_name = "primary", + .inf_flags = NM_META_PROPERTY_INF_FLAG_DONT_ASK, + .prompt = N_("Bonding primary interface [none]"), + }, + { + NESTED_PROPERTY_INFO_BOND, + /* this is a virtual property, only needed during "ask" mode. */ + .field_name = NULL, + .prompt = N_("Bonding monitoring mode"), + .def_hint = NM_META_TEXT_PROMPT_BOND_MON_MODE_CHOICES, + }, + { + NESTED_PROPERTY_INFO_BOND, + .field_name = "miimon", + .inf_flags = NM_META_PROPERTY_INF_FLAG_DONT_ASK, + .prompt = N_("Bonding miimon [100]"), + }, + { + NESTED_PROPERTY_INFO_BOND, + .field_name = "downdelay", + .inf_flags = NM_META_PROPERTY_INF_FLAG_DONT_ASK, + .prompt = N_("Bonding downdelay [0]"), + }, + { + NESTED_PROPERTY_INFO_BOND, + .field_name = "updelay", + .inf_flags = NM_META_PROPERTY_INF_FLAG_DONT_ASK, + .prompt = N_("Bonding updelay [0]"), + }, + { + NESTED_PROPERTY_INFO_BOND, + .field_name = "arp-interval", + .inf_flags = NM_META_PROPERTY_INF_FLAG_DONT_ASK, + .prompt = N_("Bonding arp-interval [0]"), + }, + { + NESTED_PROPERTY_INFO_BOND, + .field_name = "arp-ip-target", + .inf_flags = NM_META_PROPERTY_INF_FLAG_DONT_ASK, + .prompt = N_("Bonding arp-ip-target [none]"), + }, + { + NESTED_PROPERTY_INFO_BOND, + .field_name = "lacp-rate", + .inf_flags = NM_META_PROPERTY_INF_FLAG_DONT_ASK, + .prompt = N_("LACP rate ('slow' or 'fast') [slow]"), + }, +}; + +const NMMetaPropertyTypDataNested nm_meta_property_typ_data_bond = { + .nested = meta_nested_property_type_infos_bond, + .nested_len = G_N_ELEMENTS (meta_nested_property_type_infos_bond), +}; + +/*****************************************************************************/ + #define DEFINE_PROPERTY_TYPE(...) \ (&((NMMetaPropertyType) { __VA_ARGS__ } )) @@ -4473,10 +4851,6 @@ _set_fcn_wireless_security_psk (ARGS_SET_FCN) PROPERTY_TYP_DATA_SUBTYPE (stype, __VA_ARGS__), \ ) -static const NMMetaPropertyType _pt_name = { - .get_fcn = _get_fcn_name, -}; - static const NMMetaPropertyType _pt_gobject_readonly = { .get_fcn = _get_fcn_gobject, }; @@ -4489,6 +4863,7 @@ static const NMMetaPropertyType _pt_gobject_string = { static const NMMetaPropertyType _pt_gobject_bool = { .get_fcn = _get_fcn_gobject, .set_fcn = _set_fcn_gobject_bool, + .complete_fcn = _complete_fcn_gobject_bool, }; static const NMMetaPropertyType _pt_gobject_int = { @@ -4527,24 +4902,18 @@ static const NMMetaPropertyType _pt_gobject_enum = { .values_fcn = _values_fcn_gobject_enum, }; +static const NMMetaPropertyType _pt_gobject_devices = { + .get_fcn = _get_fcn_gobject, + .set_fcn = _set_fcn_gobject_string, + .complete_fcn = _complete_fcn_gobject_devices, +}; + /*****************************************************************************/ #include "settings-docs.c" /*****************************************************************************/ -/* FIXME: it is wrong to have a property-type "name". The name is a regular - * "property" of the setting. Also, this is redundant to the setting_name - * in NMMetaSettingInfo. */ -#define PROPERTY_INFO_NAME() \ - { \ - .meta_type = &nm_meta_type_property_info, \ - .setting_info = &nm_meta_setting_infos_editor[_CURRENT_NM_META_SETTING_TYPE], \ - .property_name = N_ ("name"), \ - .is_name = TRUE, \ - .property_type = &_pt_name, \ - } - #define PROPERTY_INFO(name, doc) \ .meta_type = &nm_meta_type_property_info, \ .setting_info = &nm_meta_setting_infos_editor[_CURRENT_NM_META_SETTING_TYPE], \ @@ -4578,7 +4947,6 @@ static const NMMetaPropertyType _pt_gobject_enum = { #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_802_1X static const NMMetaPropertyInfo property_infos_802_1X[] = { - PROPERTY_INFO_NAME(), { PROPERTY_INFO_WITH_DESC (NM_SETTING_802_1X_EAP), .property_type = DEFINE_PROPERTY_TYPE ( @@ -4866,13 +5234,19 @@ static const NMMetaPropertyInfo property_infos_802_1X[] = { #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_ADSL static const NMMetaPropertyInfo property_infos_ADSL[] = { - PROPERTY_INFO_NAME(), { PROPERTY_INFO_WITH_DESC (NM_SETTING_ADSL_USERNAME), + .is_cli_option = TRUE, + .property_alias = "username", + .inf_flags = NM_META_PROPERTY_INF_FLAG_REQD, + .prompt = N_("Username"), .property_type = &_pt_gobject_string, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_ADSL_PASSWORD), + .is_cli_option = TRUE, + .property_alias = "password", + .prompt = N_("Password [none]"), .is_secret = TRUE, .property_type = &_pt_gobject_string, }, @@ -4882,6 +5256,11 @@ static const NMMetaPropertyInfo property_infos_ADSL[] = { }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_ADSL_PROTOCOL), + .is_cli_option = TRUE, + .property_alias = "protocol", + .inf_flags = NM_META_PROPERTY_INF_FLAG_REQD, + .prompt = NM_META_TEXT_PROMPT_ADSL_PROTO, + .def_hint = NM_META_TEXT_PROMPT_ADSL_PROTO_CHOICES, .property_type = &_pt_gobject_string, .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( .values_static = VALUES_STATIC (NM_SETTING_ADSL_PROTOCOL_PPPOA, @@ -4891,6 +5270,10 @@ static const NMMetaPropertyInfo property_infos_ADSL[] = { }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_ADSL_ENCAPSULATION), + .is_cli_option = TRUE, + .property_alias = "encapsulation", + .prompt = NM_META_TEXT_PROMPT_ADSL_ENCAP, + .def_hint = NM_META_TEXT_PROMPT_ADSL_ENCAP_CHOICES, .property_type = &_pt_gobject_string, .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( .values_static = VALUES_STATIC (NM_SETTING_ADSL_ENCAPSULATION_VCMUX, @@ -4910,13 +5293,20 @@ static const NMMetaPropertyInfo property_infos_ADSL[] = { #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_BLUETOOTH static const NMMetaPropertyInfo property_infos_BLUETOOTH[] = { - PROPERTY_INFO_NAME(), { PROPERTY_INFO_WITH_DESC (NM_SETTING_BLUETOOTH_BDADDR), + .is_cli_option = TRUE, + .property_alias = "addr", + .inf_flags = NM_META_PROPERTY_INF_FLAG_REQD, + .prompt = N_("Bluetooth device address"), .property_type = &_pt_gobject_mac, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_BLUETOOTH_TYPE), + .is_cli_option = TRUE, + .property_alias = "bt-type", + .prompt = NM_META_TEXT_PROMPT_BT_TYPE, + .def_hint = NM_META_TEXT_PROMPT_BT_TYPE_CHOICES, .property_type = &_pt_gobject_string, .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( .values_static = VALUES_STATIC (NM_SETTING_BLUETOOTH_TYPE_DUN, @@ -4928,7 +5318,6 @@ static const NMMetaPropertyInfo property_infos_BLUETOOTH[] = { #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_BOND static const NMMetaPropertyInfo property_infos_BOND[] = { - PROPERTY_INFO_NAME(), { PROPERTY_INFO_WITH_DESC (NM_SETTING_BOND_OPTIONS), .property_type = DEFINE_PROPERTY_TYPE ( @@ -4938,43 +5327,69 @@ static const NMMetaPropertyInfo property_infos_BOND[] = { .remove_fcn = _remove_fcn_bond_options, .values_fcn = _values_fcn_bond_options, ), + .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (nested, + .data = &nm_meta_property_typ_data_bond, + ), }, }; #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_BRIDGE static const NMMetaPropertyInfo property_infos_BRIDGE[] = { - PROPERTY_INFO_NAME(), { PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_MAC_ADDRESS), + .is_cli_option = TRUE, + .property_alias = "mac", + .prompt = N_("MAC [none]"), .property_type = &_pt_gobject_mac, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_STP), + .is_cli_option = TRUE, + .property_alias = "stp", + .prompt = N_("Enable STP [no]"), .property_type = &_pt_gobject_bool, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_PRIORITY), + .is_cli_option = TRUE, + .property_alias = "priority", + .prompt = N_("STP priority [32768]"), .property_type = &_pt_gobject_uint, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_FORWARD_DELAY), + .is_cli_option = TRUE, + .property_alias = "forward-delay", + .prompt = N_("Forward delay [15]"), .property_type = &_pt_gobject_uint, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_HELLO_TIME), + .is_cli_option = TRUE, + .property_alias = "hello-time", + .prompt = N_("Hello time [2]"), .property_type = &_pt_gobject_uint, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_MAX_AGE), + .is_cli_option = TRUE, + .property_alias = "max-age", + .prompt = N_("Max age [20]"), .property_type = &_pt_gobject_uint, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_AGEING_TIME), + .is_cli_option = TRUE, + .property_alias = "ageing-time", + .prompt = N_("MAC address ageing time [300]"), .property_type = &_pt_gobject_uint, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_MULTICAST_SNOOPING), + .is_cli_option = TRUE, + .property_alias = "multicast-snooping", + .prompt = N_("Enable IGMP snooping [no]"), .property_type = &_pt_gobject_bool, }, }; @@ -4982,17 +5397,25 @@ static const NMMetaPropertyInfo property_infos_BRIDGE[] = { #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_BRIDGE_PORT static const NMMetaPropertyInfo property_infos_BRIDGE_PORT[] = { - PROPERTY_INFO_NAME(), { PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_PORT_PRIORITY), + .is_cli_option = TRUE, + .property_alias = "priority", + .prompt = N_("Bridge port priority [32]"), .property_type = &_pt_gobject_uint, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_PORT_PATH_COST), + .is_cli_option = TRUE, + .property_alias = "path-cost", + .prompt = N_("Bridge port STP path cost [100]"), .property_type = &_pt_gobject_uint, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE), + .is_cli_option = TRUE, + .property_alias = "hairpin", + .prompt = N_("Hairpin [no]"), .property_type = &_pt_gobject_bool, }, }; @@ -5000,17 +5423,22 @@ static const NMMetaPropertyInfo property_infos_BRIDGE_PORT[] = { #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_CDMA static const NMMetaPropertyInfo property_infos_CDMA[] = { - PROPERTY_INFO_NAME(), { PROPERTY_INFO_WITH_DESC (NM_SETTING_CDMA_NUMBER), .property_type = &_pt_gobject_string, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_CDMA_USERNAME), + .is_cli_option = TRUE, + .property_alias = "user", + .prompt = N_("Username [none]"), .property_type = &_pt_gobject_string, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_CDMA_PASSWORD), + .is_cli_option = TRUE, + .property_alias = "password", + .prompt = N_("Password [none]"), .is_secret = TRUE, .property_type = &_pt_gobject_string, }, @@ -5030,9 +5458,11 @@ static const NMMetaPropertyInfo property_infos_CDMA[] = { #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_CONNECTION static const NMMetaPropertyInfo property_infos_CONNECTION[] = { - PROPERTY_INFO_NAME(), { PROPERTY_INFO_WITH_DESC (NM_SETTING_CONNECTION_ID), + .is_cli_option = TRUE, + .property_alias = "con-name", + .inf_flags = NM_META_PROPERTY_INF_FLAG_DONT_ASK, .property_type = &_pt_gobject_string, }, { @@ -5045,20 +5475,33 @@ static const NMMetaPropertyInfo property_infos_CONNECTION[] = { }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_CONNECTION_INTERFACE_NAME), + .is_cli_option = TRUE, + .property_alias = "ifname", + .inf_flags = NM_META_PROPERTY_INF_FLAG_REQD, + .prompt = NM_META_TEXT_PROMPT_IFNAME, .property_type = DEFINE_PROPERTY_TYPE ( .get_fcn = _get_fcn_gobject, .set_fcn = _set_fcn_gobject_ifname, + .complete_fcn = _complete_fcn_gobject_devices, ), }, - { + [_NM_META_PROPERTY_TYPE_CONNECTION_TYPE] = { PROPERTY_INFO_WITH_DESC (NM_SETTING_CONNECTION_TYPE), + .is_cli_option = TRUE, + .property_alias = "type", + .inf_flags = NM_META_PROPERTY_INF_FLAG_REQD, + .prompt = NM_META_TEXT_PROMPT_CON_TYPE, .property_type = DEFINE_PROPERTY_TYPE ( .get_fcn = _get_fcn_gobject, .set_fcn = _set_fcn_connection_type, + .complete_fcn = _complete_fcn_connection_type, ), }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_CONNECTION_AUTOCONNECT), + .is_cli_option = TRUE, + .property_alias = "autoconnect", + .inf_flags = NM_META_PROPERTY_INF_FLAG_DONT_ASK, .property_type = &_pt_gobject_bool, }, { @@ -5099,13 +5542,21 @@ static const NMMetaPropertyInfo property_infos_CONNECTION[] = { }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_CONNECTION_MASTER), + .is_cli_option = TRUE, + .property_alias = "master", + .inf_flags = NM_META_PROPERTY_INF_FLAG_DONT_ASK, + .prompt = NM_META_TEXT_PROMPT_MASTER, .property_type = DEFINE_PROPERTY_TYPE ( .get_fcn = _get_fcn_gobject, .set_fcn = _set_fcn_connection_master, + .complete_fcn = _complete_fcn_connection_master, ), }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_CONNECTION_SLAVE_TYPE), + .is_cli_option = TRUE, + .property_alias = "slave-type", + .inf_flags = NM_META_PROPERTY_INF_FLAG_DONT_ASK, .property_type = &_pt_gobject_string, .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( .values_static = VALUES_STATIC (NM_SETTING_BOND_SETTING_NAME, @@ -5177,7 +5628,6 @@ static const NMMetaPropertyInfo property_infos_CONNECTION[] = { #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_DCB static const NMMetaPropertyInfo property_infos_DCB[] = { - PROPERTY_INFO_NAME(), { PROPERTY_INFO_WITH_DESC (NM_SETTING_DCB_APP_FCOE_FLAGS), .property_type = DEFINE_PROPERTY_TYPE ( @@ -5286,26 +5736,25 @@ static const NMMetaPropertyInfo property_infos_DCB[] = { }, }; -#undef _CURRENT_NM_META_SETTING_TYPE -#define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_DUMMY -static const NMMetaPropertyInfo property_infos_DUMMY[] = { - PROPERTY_INFO_NAME(), -}; - #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_GSM static const NMMetaPropertyInfo property_infos_GSM[] = { - PROPERTY_INFO_NAME(), { PROPERTY_INFO_WITH_DESC (NM_SETTING_GSM_NUMBER), .property_type = &_pt_gobject_string, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_GSM_USERNAME), + .is_cli_option = TRUE, + .property_alias = "user", + .prompt = N_("Username [none]"), .property_type = &_pt_gobject_string, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_GSM_PASSWORD), + .is_cli_option = TRUE, + .property_alias = "password", + .prompt = N_("Password [none]"), .is_secret = TRUE, .property_type = &_pt_gobject_string, }, @@ -5315,6 +5764,10 @@ static const NMMetaPropertyInfo property_infos_GSM[] = { }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_GSM_APN), + .is_cli_option = TRUE, + .property_alias = "apn", + .inf_flags = NM_META_PROPERTY_INF_FLAG_REQD, + .prompt = N_("APN"), .property_type = &_pt_gobject_string, }, { @@ -5361,9 +5814,11 @@ static const NMMetaPropertyInfo property_infos_GSM[] = { #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_INFINIBAND static const NMMetaPropertyInfo property_infos_INFINIBAND[] = { - PROPERTY_INFO_NAME(), { PROPERTY_INFO_WITH_DESC (NM_SETTING_INFINIBAND_MAC_ADDRESS), + .is_cli_option = TRUE, + .property_alias = "mac", + .prompt = N_("MAC [none]"), .property_type = &_pt_gobject_mac, .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (mac, .mode = NM_META_PROPERTY_TYPE_MAC_MODE_INFINIBAND, @@ -5371,6 +5826,9 @@ static const NMMetaPropertyInfo property_infos_INFINIBAND[] = { }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_INFINIBAND_MTU), + .is_cli_option = TRUE, + .property_alias = "mtu", + .prompt = N_("MTU [auto]"), .property_type = &_pt_gobject_mtu, .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (mtu, .get_fcn = MTU_GET_FCN (NMSettingInfiniband, nm_setting_infiniband_get_mtu), @@ -5378,6 +5836,10 @@ static const NMMetaPropertyInfo property_infos_INFINIBAND[] = { }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_INFINIBAND_TRANSPORT_MODE), + .is_cli_option = TRUE, + .property_alias = "transport-mode", + .prompt = NM_META_TEXT_PROMPT_IB_MODE, + .def_hint = NM_META_TEXT_PROMPT_IB_MODE_CHOICES, .property_type = &_pt_gobject_string, .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( .values_static = VALUES_STATIC ("datagram", "connected"), @@ -5385,6 +5847,9 @@ static const NMMetaPropertyInfo property_infos_INFINIBAND[] = { }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_INFINIBAND_P_KEY), + .is_cli_option = TRUE, + .property_alias = "p-key", + .prompt = N_("P_KEY [none]"), .property_type = DEFINE_PROPERTY_TYPE ( .get_fcn = _get_fcn_infiniband_p_key, .set_fcn = _set_fcn_infiniband_p_key, @@ -5392,6 +5857,9 @@ static const NMMetaPropertyInfo property_infos_INFINIBAND[] = { }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_INFINIBAND_PARENT), + .is_cli_option = TRUE, + .property_alias = "parent", + .prompt = N_("Parent interface [none]"), .property_type = DEFINE_PROPERTY_TYPE ( .get_fcn = _get_fcn_gobject, .set_fcn = _set_fcn_gobject_ifname, @@ -5402,7 +5870,6 @@ static const NMMetaPropertyInfo property_infos_INFINIBAND[] = { #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_IP4_CONFIG static const NMMetaPropertyInfo property_infos_IP4_CONFIG[] = { - PROPERTY_INFO_NAME(), { PROPERTY_INFO (NM_SETTING_IP_CONFIG_METHOD, DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_METHOD), .property_type = DEFINE_PROPERTY_TYPE ( @@ -5449,6 +5916,10 @@ static const NMMetaPropertyInfo property_infos_IP4_CONFIG[] = { }, { PROPERTY_INFO (NM_SETTING_IP_CONFIG_ADDRESSES, DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_ADDRESSES), + .is_cli_option = TRUE, + .property_alias = "ip4", + .inf_flags = NM_META_PROPERTY_INF_FLAG_MULTI, + .prompt = N_("IPv4 address (IP[/plen]) [none]"), .describe_message = N_ ("Enter a list of IPv4 addresses formatted as:\n" " ip[/prefix], ip[/prefix],...\n" @@ -5462,6 +5933,9 @@ static const NMMetaPropertyInfo property_infos_IP4_CONFIG[] = { }, { PROPERTY_INFO (NM_SETTING_IP_CONFIG_GATEWAY, DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_GATEWAY), + .is_cli_option = TRUE, + .property_alias = "gw4", + .prompt = N_("IPv4 gateway [none]"), .property_type = DEFINE_PROPERTY_TYPE ( .get_fcn = _get_fcn_gobject, .set_fcn = _set_fcn_ip4_config_gateway, @@ -5535,7 +6009,6 @@ static const NMMetaPropertyInfo property_infos_IP4_CONFIG[] = { #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_IP6_CONFIG static const NMMetaPropertyInfo property_infos_IP6_CONFIG[] = { - PROPERTY_INFO_NAME(), { PROPERTY_INFO (NM_SETTING_IP_CONFIG_METHOD, DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_METHOD), .property_type = DEFINE_PROPERTY_TYPE ( @@ -5588,6 +6061,10 @@ static const NMMetaPropertyInfo property_infos_IP6_CONFIG[] = { }, { PROPERTY_INFO (NM_SETTING_IP_CONFIG_ADDRESSES, DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ADDRESSES), + .is_cli_option = TRUE, + .property_alias = "ip6", + .inf_flags = NM_META_PROPERTY_INF_FLAG_MULTI, + .prompt = N_("IPv6 address (IP[/plen]) [none]"), .describe_message = N_ ("Enter a list of IPv6 addresses formatted as:\n" " ip[/prefix], ip[/prefix],...\n" @@ -5601,6 +6078,9 @@ static const NMMetaPropertyInfo property_infos_IP6_CONFIG[] = { }, { PROPERTY_INFO (NM_SETTING_IP_CONFIG_GATEWAY, DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_GATEWAY), + .is_cli_option = TRUE, + .property_alias = "gw6", + .prompt = N_("IPv6 gateway [none]"), .property_type = DEFINE_PROPERTY_TYPE ( .get_fcn = _get_fcn_gobject, .set_fcn = _set_fcn_ip6_config_gateway, @@ -5677,9 +6157,12 @@ static const NMMetaPropertyInfo property_infos_IP6_CONFIG[] = { #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_IP_TUNNEL static const NMMetaPropertyInfo property_infos_IP_TUNNEL[] = { - PROPERTY_INFO_NAME(), { PROPERTY_INFO_WITH_DESC (NM_SETTING_IP_TUNNEL_MODE), + .is_cli_option = TRUE, + .property_alias = "mode", + .inf_flags = NM_META_PROPERTY_INF_FLAG_REQD, + .prompt = NM_META_TEXT_PROMPT_IP_TUNNEL_MODE, .property_type = DEFINE_PROPERTY_TYPE ( .get_fcn = _get_fcn_ip_tunnel_mode, .set_fcn = _set_fcn_ip_tunnel_mode, @@ -5693,14 +6176,24 @@ static const NMMetaPropertyInfo property_infos_IP_TUNNEL[] = { }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_IP_TUNNEL_PARENT), - .property_type = &_pt_gobject_string, + .is_cli_option = TRUE, + .property_alias = "dev", + .prompt = N_("Parent device [none]"), + .property_type = &_pt_gobject_devices, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_IP_TUNNEL_LOCAL), + .is_cli_option = TRUE, + .property_alias = "local", + .prompt = N_("Local endpoint [none]"), .property_type = &_pt_gobject_string, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_IP_TUNNEL_REMOTE), + .is_cli_option = TRUE, + .property_alias = "remote", + .inf_flags = NM_META_PROPERTY_INF_FLAG_REQD, + .prompt = N_("Remote"), .property_type = &_pt_gobject_string, }, { @@ -5740,13 +6233,21 @@ static const NMMetaPropertyInfo property_infos_IP_TUNNEL[] = { #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_MACSEC static const NMMetaPropertyInfo property_infos_MACSEC[] = { - PROPERTY_INFO_NAME(), { PROPERTY_INFO_WITH_DESC (NM_SETTING_MACSEC_PARENT), + .is_cli_option = TRUE, + .property_alias = "dev", + .inf_flags = NM_META_PROPERTY_INF_FLAG_REQD, + .prompt = N_("MACsec parent device or connection UUID"), .property_type = &_pt_gobject_string, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_MACSEC_MODE), + .is_cli_option = TRUE, + .property_alias = "mode", + .inf_flags = NM_META_PROPERTY_INF_FLAG_REQD, + .prompt = NM_META_TEXT_PROMPT_MACSEC_MODE, + .def_hint = NM_META_TEXT_PROMPT_MACSEC_MODE_CHOICES, .property_type = DEFINE_PROPERTY_TYPE ( .get_fcn = _get_fcn_macsec_mode, .set_fcn = _set_fcn_macsec_mode, @@ -5758,10 +6259,16 @@ static const NMMetaPropertyInfo property_infos_MACSEC[] = { }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_MACSEC_ENCRYPT), + .is_cli_option = TRUE, + .property_alias = "encrypt", + .prompt = N_("Enable encryption [yes]"), .property_type = &_pt_gobject_bool, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_MACSEC_MKA_CAK), + .is_cli_option = TRUE, + .property_alias = "cak", + .prompt = N_("MKA CAK"), .is_secret = TRUE, .property_type = &_pt_gobject_string, }, @@ -5771,10 +6278,16 @@ static const NMMetaPropertyInfo property_infos_MACSEC[] = { }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_MACSEC_MKA_CKN), + .is_cli_option = TRUE, + .property_alias = "ckn", + .prompt = N_("MKA_CKN"), .property_type = &_pt_gobject_string, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_MACSEC_PORT), + .is_cli_option = TRUE, + .property_alias = "port", + .prompt = N_("SCI port [1]"), .property_type = &_pt_gobject_int, }, { @@ -5793,13 +6306,20 @@ static const NMMetaPropertyInfo property_infos_MACSEC[] = { #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_MACVLAN static const NMMetaPropertyInfo property_infos_MACVLAN[] = { - PROPERTY_INFO_NAME(), { PROPERTY_INFO_WITH_DESC (NM_SETTING_MACVLAN_PARENT), - .property_type = &_pt_gobject_string, + .is_cli_option = TRUE, + .property_alias = "dev", + .inf_flags = NM_META_PROPERTY_INF_FLAG_REQD, + .prompt = N_("MACVLAN parent device or connection UUID"), + .property_type = &_pt_gobject_devices, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_MACVLAN_MODE), + .is_cli_option = TRUE, + .property_alias = "mode", + .inf_flags = NM_META_PROPERTY_INF_FLAG_REQD, + .prompt = NM_META_TEXT_PROMPT_MACVLAN_MODE, .property_type = DEFINE_PROPERTY_TYPE ( .get_fcn = _get_fcn_macvlan_mode, .set_fcn = _set_fcn_macvlan_mode, @@ -5817,6 +6337,9 @@ static const NMMetaPropertyInfo property_infos_MACVLAN[] = { }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_MACVLAN_TAP), + .is_cli_option = TRUE, + .property_alias = "tap", + .prompt = N_("Tap [no]"), .property_type = &_pt_gobject_bool, }, }; @@ -5824,9 +6347,12 @@ static const NMMetaPropertyInfo property_infos_MACVLAN[] = { #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_OLPC_MESH static const NMMetaPropertyInfo property_infos_OLPC_MESH[] = { - PROPERTY_INFO_NAME(), { PROPERTY_INFO_WITH_DESC (NM_SETTING_OLPC_MESH_SSID), + .is_cli_option = TRUE, + .property_alias = "ssid", + .inf_flags = NM_META_PROPERTY_INF_FLAG_REQD, + .prompt = N_("SSID"), .property_type = DEFINE_PROPERTY_TYPE ( .get_fcn = _get_fcn_olpc_mesh_ssid, .set_fcn = _set_fcn_gobject_ssid, @@ -5834,6 +6360,9 @@ static const NMMetaPropertyInfo property_infos_OLPC_MESH[] = { }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_OLPC_MESH_CHANNEL), + .is_cli_option = TRUE, + .property_alias = "channel", + .prompt = N_("OLPC Mesh channel [1]"), .property_type = DEFINE_PROPERTY_TYPE ( .get_fcn = _get_fcn_gobject, .set_fcn = _set_fcn_olpc_mesh_channel, @@ -5841,6 +6370,9 @@ static const NMMetaPropertyInfo property_infos_OLPC_MESH[] = { }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_OLPC_MESH_DHCP_ANYCAST_ADDRESS), + .is_cli_option = TRUE, + .property_alias = "dhcp-anycast", + .prompt = N_("DHCP anycast MAC address [none]"), .property_type = &_pt_gobject_mac, }, }; @@ -5848,17 +6380,26 @@ static const NMMetaPropertyInfo property_infos_OLPC_MESH[] = { #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_PPPOE static const NMMetaPropertyInfo property_infos_PPPOE[] = { - PROPERTY_INFO_NAME (), { PROPERTY_INFO_WITH_DESC (NM_SETTING_PPPOE_SERVICE), + .is_cli_option = TRUE, + .property_alias = "service", + .prompt = N_("Service [none]"), .property_type = &_pt_gobject_string, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_PPPOE_USERNAME), + .is_cli_option = TRUE, + .property_alias = "username", + .inf_flags = NM_META_PROPERTY_INF_FLAG_REQD, + .prompt = N_("PPPoE username"), .property_type = &_pt_gobject_string, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_PPPOE_PASSWORD), + .is_cli_option = TRUE, + .property_alias = "password", + .prompt = N_("Password [none]"), .is_secret = TRUE, .property_type = &_pt_gobject_string, }, @@ -5871,7 +6412,6 @@ static const NMMetaPropertyInfo property_infos_PPPOE[] = { #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_PPP static const NMMetaPropertyInfo property_infos_PPP[] = { - PROPERTY_INFO_NAME (), { PROPERTY_INFO_WITH_DESC (NM_SETTING_PPP_NOAUTH), .property_type = &_pt_gobject_bool, @@ -5952,9 +6492,12 @@ static const NMMetaPropertyInfo property_infos_PPP[] = { #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_PROXY static const NMMetaPropertyInfo property_infos_PROXY[] = { - PROPERTY_INFO_NAME(), { PROPERTY_INFO_WITH_DESC (NM_SETTING_PROXY_METHOD), + .is_cli_option = TRUE, + .property_alias = "method", + .prompt = NM_META_TEXT_PROMPT_PROXY_METHOD, + .def_hint = NM_META_TEXT_PROMPT_PROXY_METHOD_CHOICES, .property_type = DEFINE_PROPERTY_TYPE ( .get_fcn = _get_fcn_proxy_method, .set_fcn = _set_fcn_proxy_method, @@ -5968,14 +6511,23 @@ static const NMMetaPropertyInfo property_infos_PROXY[] = { }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_PROXY_BROWSER_ONLY), + .is_cli_option = TRUE, + .property_alias = "browser-only", + .prompt = N_("Browser only [no]"), .property_type = &_pt_gobject_bool }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_PROXY_PAC_URL), + .is_cli_option = TRUE, + .property_alias = "pac-url", + .prompt = N_("PAC URL"), .property_type = &_pt_gobject_string, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_PROXY_PAC_SCRIPT), + .is_cli_option = TRUE, + .property_alias = "pac-script", + .prompt = N_("PAC script"), .property_type = DEFINE_PROPERTY_TYPE ( .get_fcn = _get_fcn_gobject, .set_fcn = _set_fcn_proxy_pac_script, @@ -5986,9 +6538,11 @@ static const NMMetaPropertyInfo property_infos_PROXY[] = { #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_TEAM static const NMMetaPropertyInfo property_infos_TEAM[] = { - PROPERTY_INFO_NAME(), { PROPERTY_INFO_WITH_DESC (NM_SETTING_TEAM_CONFIG), + .is_cli_option = TRUE, + .property_alias = "config", + .prompt = N_("Team JSON configuration [none]"), .describe_message = N_ (TEAM_DESCRIBE_MESSAGE), .property_type = DEFINE_PROPERTY_TYPE ( .get_fcn = _get_fcn_gobject, @@ -6000,9 +6554,11 @@ static const NMMetaPropertyInfo property_infos_TEAM[] = { #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_TEAM_PORT static const NMMetaPropertyInfo property_infos_TEAM_PORT[] = { - PROPERTY_INFO_NAME(), { PROPERTY_INFO_WITH_DESC (NM_SETTING_TEAM_PORT_CONFIG), + .is_cli_option = TRUE, + .property_alias = "config", + .prompt = N_("Team JSON configuration [none]"), .describe_message = N_ (TEAM_DESCRIBE_MESSAGE), .property_type = DEFINE_PROPERTY_TYPE ( .get_fcn = _get_fcn_gobject, @@ -6014,7 +6570,6 @@ static const NMMetaPropertyInfo property_infos_TEAM_PORT[] = { #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_SERIAL static const NMMetaPropertyInfo property_infos_SERIAL[] = { - PROPERTY_INFO_NAME(), { PROPERTY_INFO_WITH_DESC (NM_SETTING_SERIAL_BAUD), .property_type = &_pt_gobject_uint, @@ -6043,9 +6598,12 @@ static const NMMetaPropertyInfo property_infos_SERIAL[] = { #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_TUN static const NMMetaPropertyInfo property_infos_TUN[] = { - PROPERTY_INFO_NAME(), { PROPERTY_INFO_WITH_DESC (NM_SETTING_TUN_MODE), + .is_cli_option = TRUE, + .property_alias = "mode", + .prompt = NM_META_TEXT_PROMPT_TUN_MODE, + .def_hint = NM_META_TEXT_PROMPT_TUN_MODE_CHOICES, .property_type = DEFINE_PROPERTY_TYPE ( .get_fcn = _get_fcn_tun_mode, .set_fcn = _set_fcn_tun_mode, @@ -6056,46 +6614,65 @@ static const NMMetaPropertyInfo property_infos_TUN[] = { }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_TUN_OWNER), + .is_cli_option = TRUE, + .property_alias = "owner", + .prompt = N_("User ID [none]"), .property_type = &_pt_gobject_string, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_TUN_GROUP), + .is_cli_option = TRUE, + .property_alias = "group", + .prompt = N_("Group ID [none]"), .property_type = &_pt_gobject_string, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_TUN_PI), + .is_cli_option = TRUE, + .property_alias = "pi", + .prompt = N_("Enable PI [no]"), .property_type = &_pt_gobject_bool, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_TUN_VNET_HDR), + .is_cli_option = TRUE, + .property_alias = "vnet-hdr", + .prompt = N_("Enable VNET header [no]"), .property_type = &_pt_gobject_bool, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_TUN_MULTI_QUEUE), + .is_cli_option = TRUE, + .property_alias = "multi-queue", + .prompt = N_("Enable multi queue [no]"), .property_type = &_pt_gobject_bool, }, }; -#undef _CURRENT_NM_META_SETTING_TYPE -#define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_USER -static const NMMetaPropertyInfo property_infos_USER[] = { - PROPERTY_INFO_NAME(), -}; - #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_VLAN static const NMMetaPropertyInfo property_infos_VLAN[] = { - PROPERTY_INFO_NAME(), { PROPERTY_INFO_WITH_DESC (NM_SETTING_VLAN_PARENT), - .property_type = &_pt_gobject_string, + .is_cli_option = TRUE, + .property_alias = "dev", + .inf_flags = NM_META_PROPERTY_INF_FLAG_REQD, + .prompt = N_("VLAN parent device or connection UUID"), + .property_type = &_pt_gobject_devices, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_VLAN_ID), + .is_cli_option = TRUE, + .property_alias = "id", + .inf_flags = NM_META_PROPERTY_INF_FLAG_REQD, + .prompt = N_("VLAN ID (<0-4094>)"), .property_type = &_pt_gobject_uint, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_VLAN_FLAGS), + .is_cli_option = TRUE, + .property_alias = "flags", + .prompt = N_("VLAN flags (<0-7>) [none]"), .property_type = DEFINE_PROPERTY_TYPE ( .get_fcn = _get_fcn_vlan_flags, .set_fcn = _set_fcn_gobject_flags, @@ -6103,6 +6680,9 @@ static const NMMetaPropertyInfo property_infos_VLAN[] = { }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_VLAN_INGRESS_PRIORITY_MAP), + .is_cli_option = TRUE, + .property_alias = "ingress", + .prompt = N_("Ingress priority maps [none]"), .property_type = DEFINE_PROPERTY_TYPE ( .get_fcn = _get_fcn_vlan_ingress_priority_map, .set_fcn = _set_fcn_vlan_ingress_priority_map, @@ -6111,6 +6691,9 @@ static const NMMetaPropertyInfo property_infos_VLAN[] = { }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_VLAN_EGRESS_PRIORITY_MAP), + .is_cli_option = TRUE, + .property_alias = "egress", + .prompt = N_("Egress priority maps [none]"), .property_type = DEFINE_PROPERTY_TYPE ( .get_fcn = _get_fcn_vlan_egress_priority_map, .set_fcn = _set_fcn_vlan_egress_priority_map, @@ -6122,16 +6705,23 @@ static const NMMetaPropertyInfo property_infos_VLAN[] = { #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_VPN static const NMMetaPropertyInfo property_infos_VPN[] = { - PROPERTY_INFO_NAME(), - { + [_NM_META_PROPERTY_TYPE_VPN_SERVICE_TYPE] = { PROPERTY_INFO_WITH_DESC (NM_SETTING_VPN_SERVICE_TYPE), + .is_cli_option = TRUE, + .property_alias = "vpn-type", + .inf_flags = NM_META_PROPERTY_INF_FLAG_REQD, + .prompt = NM_META_TEXT_PROMPT_VPN_TYPE, .property_type = DEFINE_PROPERTY_TYPE ( .get_fcn = _get_fcn_gobject, .set_fcn = _set_fcn_vpn_service_type, + .complete_fcn = _complete_fcn_vpn_service_type, ), }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_VPN_USER_NAME), + .is_cli_option = TRUE, + .property_alias = "user", + .prompt = N_("Username [none]"), .property_type = &_pt_gobject_string, }, { @@ -6164,33 +6754,55 @@ static const NMMetaPropertyInfo property_infos_VPN[] = { #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_VXLAN static const NMMetaPropertyInfo property_infos_VXLAN[] = { - PROPERTY_INFO_NAME(), { PROPERTY_INFO_WITH_DESC (NM_SETTING_VXLAN_PARENT), - .property_type = &_pt_gobject_string, + .is_cli_option = TRUE, + .property_alias = "dev", + .prompt = N_("Parent device [none]"), + .property_type = &_pt_gobject_devices, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_VXLAN_ID), + .is_cli_option = TRUE, + .property_alias = "id", + .inf_flags = NM_META_PROPERTY_INF_FLAG_REQD, + .prompt = N_("VXLAN ID"), .property_type = &_pt_gobject_uint, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_VXLAN_LOCAL), + .is_cli_option = TRUE, + .property_alias = "local", + .prompt = N_("Local address [none]"), .property_type = &_pt_gobject_string, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_VXLAN_REMOTE), + .is_cli_option = TRUE, + .property_alias = "remote", + .inf_flags = NM_META_PROPERTY_INF_FLAG_REQD, + .prompt = N_("Remote"), .property_type = &_pt_gobject_string, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_VXLAN_SOURCE_PORT_MIN), + .is_cli_option = TRUE, + .property_alias = "source-port-min", + .prompt = N_("Minimum source port [0]"), .property_type = &_pt_gobject_uint, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_VXLAN_SOURCE_PORT_MAX), + .is_cli_option = TRUE, + .property_alias = "source-port-max", + .prompt = N_("Maximum source port [0]"), .property_type = &_pt_gobject_uint, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_VXLAN_DESTINATION_PORT), + .is_cli_option = TRUE, + .property_alias = "destination-port", + .prompt = N_("Destination port [8472]"), .property_type = &_pt_gobject_uint, }, { @@ -6234,13 +6846,19 @@ static const NMMetaPropertyInfo property_infos_VXLAN[] = { #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_WIMAX static const NMMetaPropertyInfo property_infos_WIMAX[] = { - PROPERTY_INFO_NAME(), { PROPERTY_INFO_WITH_DESC (NM_SETTING_WIMAX_MAC_ADDRESS), + .is_cli_option = TRUE, + .property_alias = "mac", + .prompt = N_("MAC [none]"), .property_type = &_pt_gobject_string, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_WIMAX_NETWORK_NAME), + .is_cli_option = TRUE, + .property_alias = "nsp", + .inf_flags = NM_META_PROPERTY_INF_FLAG_REQD, + .prompt = N_("WiMAX NSP name"), .property_type = &_pt_gobject_mac, }, }; @@ -6248,7 +6866,6 @@ static const NMMetaPropertyInfo property_infos_WIMAX[] = { #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_WIRED static const NMMetaPropertyInfo property_infos_WIRED[] = { - PROPERTY_INFO_NAME(), { PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRED_PORT), /* Do not allow setting 'port' for now. It is not implemented in @@ -6274,10 +6891,16 @@ static const NMMetaPropertyInfo property_infos_WIRED[] = { }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRED_MAC_ADDRESS), + .is_cli_option = TRUE, + .property_alias = "mac", + .prompt = N_("MAC [none]"), .property_type = &_pt_gobject_mac, }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRED_CLONED_MAC_ADDRESS), + .is_cli_option = TRUE, + .property_alias = "cloned-mac", + .prompt = N_("Cloned MAC [none]"), .property_type = &_pt_gobject_mac, .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (mac, .mode = NM_META_PROPERTY_TYPE_MAC_MODE_CLONED, @@ -6297,6 +6920,9 @@ static const NMMetaPropertyInfo property_infos_WIRED[] = { }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRED_MTU), + .is_cli_option = TRUE, + .property_alias = "mtu", + .prompt = N_("MTU [auto]"), .property_type = &_pt_gobject_mtu, .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (mtu, .get_fcn = MTU_GET_FCN (NMSettingWired, nm_setting_wired_get_mtu), @@ -6345,9 +6971,12 @@ static const NMMetaPropertyInfo property_infos_WIRED[] = { #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_WIRELESS static const NMMetaPropertyInfo property_infos_WIRELESS[] = { - PROPERTY_INFO_NAME(), { PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRELESS_SSID), + .is_cli_option = TRUE, + .property_alias = "ssid", + .inf_flags = NM_META_PROPERTY_INF_FLAG_REQD, + .prompt = N_("SSID"), .property_type = DEFINE_PROPERTY_TYPE ( .get_fcn = _get_fcn_wireless_ssid, .set_fcn = _set_fcn_gobject_ssid, @@ -6355,6 +6984,10 @@ static const NMMetaPropertyInfo property_infos_WIRELESS[] = { }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRELESS_MODE), + .is_cli_option = TRUE, + .property_alias = "mode", + .prompt = NM_META_TEXT_PROMPT_WIFI_MODE, + .def_hint = NM_META_TEXT_PROMPT_WIFI_MODE_CHOICES, .property_type = &_pt_gobject_string, .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( .values_static = VALUES_STATIC (NM_SETTING_WIRELESS_MODE_INFRA, @@ -6393,9 +7026,15 @@ static const NMMetaPropertyInfo property_infos_WIRELESS[] = { { PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRELESS_MAC_ADDRESS), .property_type = &_pt_gobject_mac, + .is_cli_option = TRUE, + .property_alias = "mac", + .prompt = N_("MAC [none]"), }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS), + .is_cli_option = TRUE, + .property_alias = "cloned-mac", + .prompt = N_("Cloned MAC [none]"), .property_type = &_pt_gobject_mac, .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (mac, .mode = NM_META_PROPERTY_TYPE_MAC_MODE_CLONED, @@ -6422,6 +7061,9 @@ static const NMMetaPropertyInfo property_infos_WIRELESS[] = { }, { PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRELESS_MTU), + .is_cli_option = TRUE, + .property_alias = "mtu", + .prompt = N_("MTU [auto]"), .property_type = &_pt_gobject_mtu, .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (mtu, .get_fcn = MTU_GET_FCN (NMSettingWireless, nm_setting_wireless_get_mtu), @@ -6450,7 +7092,6 @@ static const NMMetaPropertyInfo property_infos_WIRELESS[] = { #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_WIRELESS_SECURITY static const NMMetaPropertyInfo property_infos_WIRELESS_SECURITY[] = { - PROPERTY_INFO_NAME(), { PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRELESS_SECURITY_KEY_MGMT), .property_type = &_pt_gobject_string, @@ -6575,97 +7216,514 @@ static const NMMetaPropertyInfo property_infos_WIRELESS_SECURITY[] = { }, }; +/*****************************************************************************/ + +static void +_setting_init_fcn_adsl (ARGS_SETTING_INIT_FCN) +{ + if (init_type == NM_META_ACCESSOR_SETTING_INIT_TYPE_CLI) { + /* Initialize a protocol */ + g_object_set (NM_SETTING_ADSL (setting), + NM_SETTING_ADSL_PROTOCOL, NM_SETTING_ADSL_PROTOCOL_PPPOE, + NULL); + } +} + +static void +_setting_init_fcn_bluetooth (ARGS_SETTING_INIT_FCN) +{ + if (init_type == NM_META_ACCESSOR_SETTING_INIT_TYPE_CLI) { + g_object_set (NM_SETTING_BLUETOOTH (setting), + NM_SETTING_BLUETOOTH_TYPE, NM_SETTING_BLUETOOTH_TYPE_PANU, + NULL); + } +} + +static void +_setting_init_fcn_cdma (ARGS_SETTING_INIT_FCN) +{ + if (init_type == NM_META_ACCESSOR_SETTING_INIT_TYPE_CLI) { + /* Initialize 'number' so that 'cdma' is valid */ + g_object_set (NM_SETTING_CDMA (setting), + NM_SETTING_CDMA_NUMBER, "#777", + NULL); + } +} + +static void +_setting_init_fcn_gsm (ARGS_SETTING_INIT_FCN) +{ + if (init_type == NM_META_ACCESSOR_SETTING_INIT_TYPE_CLI) { + /* Initialize 'number' so that 'gsm' is valid */ + g_object_set (NM_SETTING_GSM (setting), + NM_SETTING_GSM_NUMBER, "*99#", + NULL); + } +} + +static void +_setting_init_fcn_infiniband (ARGS_SETTING_INIT_FCN) +{ + if (init_type == NM_META_ACCESSOR_SETTING_INIT_TYPE_CLI) { + /* Initialize 'transport-mode' so that 'infiniband' is valid */ + g_object_set (NM_SETTING_INFINIBAND (setting), + NM_SETTING_INFINIBAND_TRANSPORT_MODE, "datagram", + NULL); + } +} + +static void +_setting_init_fcn_ip4_config (ARGS_SETTING_INIT_FCN) +{ + if (init_type == NM_META_ACCESSOR_SETTING_INIT_TYPE_CLI) { + g_object_set (NM_SETTING_IP_CONFIG (setting), + NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, + NULL); + } +} + +static void +_setting_init_fcn_ip6_config (ARGS_SETTING_INIT_FCN) +{ + if (init_type == NM_META_ACCESSOR_SETTING_INIT_TYPE_CLI) { + g_object_set (NM_SETTING_IP_CONFIG (setting), + NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO, + NULL); + } +} + +static void +_setting_init_fcn_olpc_mesh (ARGS_SETTING_INIT_FCN) +{ + if (init_type == NM_META_ACCESSOR_SETTING_INIT_TYPE_CLI) { + g_object_set (NM_SETTING_OLPC_MESH (setting), + NM_SETTING_OLPC_MESH_CHANNEL, 1, + NULL); + } +} + +static void +_setting_init_fcn_proxy (ARGS_SETTING_INIT_FCN) +{ + if (init_type == NM_META_ACCESSOR_SETTING_INIT_TYPE_CLI) { + g_object_set (NM_SETTING_PROXY (setting), + NM_SETTING_PROXY_METHOD, (int) NM_SETTING_PROXY_METHOD_NONE, + NULL); + } +} + +static void +_setting_init_fcn_tun (ARGS_SETTING_INIT_FCN) +{ + if (init_type == NM_META_ACCESSOR_SETTING_INIT_TYPE_CLI) { + g_object_set (NM_SETTING_TUN (setting), + NM_SETTING_TUN_MODE, NM_SETTING_TUN_MODE_TUN, + NULL); + } +} + +static void +_setting_init_fcn_vlan (ARGS_SETTING_INIT_FCN) +{ + if (init_type == NM_META_ACCESSOR_SETTING_INIT_TYPE_CLI) { + g_object_set (setting, + NM_SETTING_VLAN_ID, 1, + NULL); + } +} + +static void +_setting_init_fcn_wireless (ARGS_SETTING_INIT_FCN) +{ + if (init_type == NM_META_ACCESSOR_SETTING_INIT_TYPE_CLI) { + /* For Wi-Fi set mode to "infrastructure". Even though mode == NULL + * is regarded as "infrastructure", explicit value makes no doubts. + */ + g_object_set (NM_SETTING_WIRELESS (setting), + NM_SETTING_WIRELESS_MODE, NM_SETTING_WIRELESS_MODE_INFRA, + NULL); + } +} + +/*****************************************************************************/ + +#define SETTING_PRETTY_NAME_802_1X "802-1x settings" +#define SETTING_PRETTY_NAME_ADSL "ADSL connection" +#define SETTING_PRETTY_NAME_BLUETOOTH "bluetooth connection" +#define SETTING_PRETTY_NAME_BOND "Bond device" +#define SETTING_PRETTY_NAME_BRIDGE "Bridge device" +#define SETTING_PRETTY_NAME_BRIDGE_PORT "Bridge port" +#define SETTING_PRETTY_NAME_CDMA "CDMA mobile broadband connection" +#define SETTING_PRETTY_NAME_CONNECTION "General settings" +#define SETTING_PRETTY_NAME_DCB "DCB settings" +#define SETTING_PRETTY_NAME_DUMMY "Dummy settings" +#define SETTING_PRETTY_NAME_GENERIC "Generic settings" +#define SETTING_PRETTY_NAME_GSM "GSM mobile broadband connection" +#define SETTING_PRETTY_NAME_INFINIBAND "InfiniBand connection" +#define SETTING_PRETTY_NAME_IP4_CONFIG "IPv4 protocol" +#define SETTING_PRETTY_NAME_IP6_CONFIG "IPv6 protocol" +#define SETTING_PRETTY_NAME_IP_TUNNEL "IP-tunnel settings" +#define SETTING_PRETTY_NAME_MACSEC "MACsec connection" +#define SETTING_PRETTY_NAME_MACVLAN "macvlan connection" +#define SETTING_PRETTY_NAME_OLPC_MESH "OLPC Mesh connection" +#define SETTING_PRETTY_NAME_PPP "PPP settings" +#define SETTING_PRETTY_NAME_PPPOE "PPPoE" +#define SETTING_PRETTY_NAME_PROXY "Proxy" +#define SETTING_PRETTY_NAME_SERIAL "Serial settings" +#define SETTING_PRETTY_NAME_TEAM "Team device" +#define SETTING_PRETTY_NAME_TEAM_PORT "Team port" +#define SETTING_PRETTY_NAME_TUN "Tun device" +#define SETTING_PRETTY_NAME_USER "User settings" +#define SETTING_PRETTY_NAME_VLAN "VLAN connection" +#define SETTING_PRETTY_NAME_VPN "VPN connection" +#define SETTING_PRETTY_NAME_VXLAN "VXLAN connection" +#define SETTING_PRETTY_NAME_WIMAX "WiMAX connection" +#define SETTING_PRETTY_NAME_WIRED "Wired Ethernet" +#define SETTING_PRETTY_NAME_WIRELESS "Wi-Fi connection" +#define SETTING_PRETTY_NAME_WIRELESS_SECURITY "Wi-Fi security settings" + +#define NM_META_SETTING_VALID_PARTS(...) \ + ((const NMMetaSettingValidPartItem *const[]) { __VA_ARGS__ NULL }) + +#define NM_META_SETTING_VALID_PART_ITEM(type, mand) \ + (&((const NMMetaSettingValidPartItem) { \ + .setting_info = &nm_meta_setting_infos_editor[NM_META_SETTING_TYPE_##type], \ + .mandatory = mand, \ + })) + const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = { -#define SETTING_INFO(type) \ +#define SETTING_INFO_EMPTY(type, ...) \ + [NM_META_SETTING_TYPE_##type] = { \ + .meta_type = &nm_meta_type_setting_info_editor, \ + .general = &nm_meta_setting_infos[NM_META_SETTING_TYPE_##type], \ + .pretty_name = N_(SETTING_PRETTY_NAME_##type), \ + __VA_ARGS__ \ + } +#define SETTING_INFO(type, ...) \ [NM_META_SETTING_TYPE_##type] = { \ .meta_type = &nm_meta_type_setting_info_editor, \ .general = &nm_meta_setting_infos[NM_META_SETTING_TYPE_##type], \ .properties = property_infos_##type, \ .properties_num = G_N_ELEMENTS (property_infos_##type), \ + .pretty_name = N_(SETTING_PRETTY_NAME_##type), \ + __VA_ARGS__ \ } SETTING_INFO (802_1X), - SETTING_INFO (ADSL), - SETTING_INFO (BLUETOOTH), - SETTING_INFO (BOND), - SETTING_INFO (BRIDGE), + SETTING_INFO (ADSL, + .valid_parts = NM_META_SETTING_VALID_PARTS ( + NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE), + NM_META_SETTING_VALID_PART_ITEM (ADSL, TRUE), + ), + .setting_init_fcn = _setting_init_fcn_adsl, + ), + SETTING_INFO (BLUETOOTH, + .valid_parts = NM_META_SETTING_VALID_PARTS ( + NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE), + NM_META_SETTING_VALID_PART_ITEM (BLUETOOTH, TRUE), + ), + .setting_init_fcn = _setting_init_fcn_bluetooth, + ), + SETTING_INFO (BOND, + .valid_parts = NM_META_SETTING_VALID_PARTS ( + NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE), + NM_META_SETTING_VALID_PART_ITEM (BOND, TRUE), + NM_META_SETTING_VALID_PART_ITEM (WIRED, FALSE), + ), + ), + SETTING_INFO (BRIDGE, + .valid_parts = NM_META_SETTING_VALID_PARTS ( + NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE), + NM_META_SETTING_VALID_PART_ITEM (BRIDGE, TRUE), + NM_META_SETTING_VALID_PART_ITEM (WIRED, FALSE), + ), + ), SETTING_INFO (BRIDGE_PORT), - SETTING_INFO (CDMA), + SETTING_INFO (CDMA, + .valid_parts = NM_META_SETTING_VALID_PARTS ( + NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE), + NM_META_SETTING_VALID_PART_ITEM (CDMA, TRUE), + NM_META_SETTING_VALID_PART_ITEM (SERIAL, FALSE), + NM_META_SETTING_VALID_PART_ITEM (PPP, FALSE), + ), + .setting_init_fcn = _setting_init_fcn_cdma, + ), SETTING_INFO (CONNECTION), SETTING_INFO (DCB), - SETTING_INFO (DUMMY), - SETTING_INFO (GSM), - SETTING_INFO (INFINIBAND), - SETTING_INFO (IP4_CONFIG), - SETTING_INFO (IP6_CONFIG), - SETTING_INFO (IP_TUNNEL), - SETTING_INFO (MACSEC), - SETTING_INFO (MACVLAN), - SETTING_INFO (OLPC_MESH), - SETTING_INFO (PPPOE), + SETTING_INFO_EMPTY (DUMMY, + .valid_parts = NM_META_SETTING_VALID_PARTS ( + NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE), + NM_META_SETTING_VALID_PART_ITEM (DUMMY, TRUE), + NM_META_SETTING_VALID_PART_ITEM (WIRED, FALSE), + ), + ), + SETTING_INFO_EMPTY (GENERIC, + .valid_parts = NM_META_SETTING_VALID_PARTS ( + NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE), + NM_META_SETTING_VALID_PART_ITEM (GENERIC, TRUE), + ), + ), + SETTING_INFO (GSM, + .valid_parts = NM_META_SETTING_VALID_PARTS ( + NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE), + NM_META_SETTING_VALID_PART_ITEM (GSM, TRUE), + NM_META_SETTING_VALID_PART_ITEM (SERIAL, FALSE), + NM_META_SETTING_VALID_PART_ITEM (PPP, FALSE), + ), + .setting_init_fcn = _setting_init_fcn_gsm, + ), + SETTING_INFO (INFINIBAND, + .valid_parts = NM_META_SETTING_VALID_PARTS ( + NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE), + NM_META_SETTING_VALID_PART_ITEM (INFINIBAND, TRUE), + ), + .setting_init_fcn = _setting_init_fcn_infiniband, + ), + SETTING_INFO (IP4_CONFIG, + .setting_init_fcn = _setting_init_fcn_ip4_config, + ), + SETTING_INFO (IP6_CONFIG, + .setting_init_fcn = _setting_init_fcn_ip6_config, + ), + SETTING_INFO (IP_TUNNEL, + .valid_parts = NM_META_SETTING_VALID_PARTS ( + NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE), + NM_META_SETTING_VALID_PART_ITEM (IP_TUNNEL, TRUE), + ), + ), + SETTING_INFO (MACSEC, + .valid_parts = NM_META_SETTING_VALID_PARTS ( + NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE), + NM_META_SETTING_VALID_PART_ITEM (MACSEC, TRUE), + NM_META_SETTING_VALID_PART_ITEM (WIRED, FALSE), + NM_META_SETTING_VALID_PART_ITEM (802_1X, FALSE), + ), + ), + SETTING_INFO (MACVLAN, + .valid_parts = NM_META_SETTING_VALID_PARTS ( + NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE), + NM_META_SETTING_VALID_PART_ITEM (MACVLAN, TRUE), + NM_META_SETTING_VALID_PART_ITEM (WIRED, FALSE), + ), + ), + SETTING_INFO (OLPC_MESH, + .alias = "olpc-mesh", + .valid_parts = NM_META_SETTING_VALID_PARTS ( + NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE), + NM_META_SETTING_VALID_PART_ITEM (OLPC_MESH, TRUE), + ), + .setting_init_fcn = _setting_init_fcn_olpc_mesh, + ), + SETTING_INFO (PPPOE, + /* PPPoE is a base connection type from historical reasons. + * See libnm-core/nm-setting.c:_nm_setting_is_base_type() + */ + .valid_parts = NM_META_SETTING_VALID_PARTS ( + NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE), + NM_META_SETTING_VALID_PART_ITEM (PPPOE, TRUE), + NM_META_SETTING_VALID_PART_ITEM (WIRED, TRUE), + NM_META_SETTING_VALID_PART_ITEM (PPP, FALSE), + NM_META_SETTING_VALID_PART_ITEM (802_1X, FALSE), + ), + ), SETTING_INFO (PPP), - SETTING_INFO (PROXY), + SETTING_INFO (PROXY, + .setting_init_fcn = _setting_init_fcn_proxy, + ), SETTING_INFO (SERIAL), - SETTING_INFO (TEAM), + SETTING_INFO (TEAM, + .valid_parts = NM_META_SETTING_VALID_PARTS ( + NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE), + NM_META_SETTING_VALID_PART_ITEM (TEAM, TRUE), + NM_META_SETTING_VALID_PART_ITEM (WIRED, FALSE), + ), + ), SETTING_INFO (TEAM_PORT), - SETTING_INFO (TUN), - SETTING_INFO (USER), - SETTING_INFO (VLAN), - SETTING_INFO (VPN), - SETTING_INFO (VXLAN), - SETTING_INFO (WIMAX), - SETTING_INFO (WIRED), - SETTING_INFO (WIRELESS), - SETTING_INFO (WIRELESS_SECURITY), + SETTING_INFO (TUN, + .valid_parts = NM_META_SETTING_VALID_PARTS ( + NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE), + NM_META_SETTING_VALID_PART_ITEM (TUN, TRUE), + NM_META_SETTING_VALID_PART_ITEM (WIRED, FALSE), + ), + .setting_init_fcn = _setting_init_fcn_tun, + ), + SETTING_INFO_EMPTY (USER), + SETTING_INFO (VLAN, + .valid_parts = NM_META_SETTING_VALID_PARTS ( + NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE), + NM_META_SETTING_VALID_PART_ITEM (VLAN, TRUE), + NM_META_SETTING_VALID_PART_ITEM (WIRED, FALSE), + ), + .setting_init_fcn = _setting_init_fcn_vlan, + ), + SETTING_INFO (VPN, + .valid_parts = NM_META_SETTING_VALID_PARTS ( + NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE), + NM_META_SETTING_VALID_PART_ITEM (VPN, TRUE), + ), + ), + SETTING_INFO (VXLAN, + .valid_parts = NM_META_SETTING_VALID_PARTS ( + NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE), + NM_META_SETTING_VALID_PART_ITEM (VXLAN, TRUE), + NM_META_SETTING_VALID_PART_ITEM (WIRED, FALSE), + ), + ), + SETTING_INFO (WIMAX, + .valid_parts = NM_META_SETTING_VALID_PARTS ( + NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE), + NM_META_SETTING_VALID_PART_ITEM (WIMAX, TRUE), + ), + ), + SETTING_INFO (WIRED, + .alias = "ethernet", + .valid_parts = NM_META_SETTING_VALID_PARTS ( + NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE), + NM_META_SETTING_VALID_PART_ITEM (WIRED, TRUE), + NM_META_SETTING_VALID_PART_ITEM (802_1X, FALSE), + NM_META_SETTING_VALID_PART_ITEM (DCB, FALSE), + ), + ), + SETTING_INFO (WIRELESS, + .alias = "wifi", + .valid_parts = NM_META_SETTING_VALID_PARTS ( + NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE), + NM_META_SETTING_VALID_PART_ITEM (WIRELESS, TRUE), + NM_META_SETTING_VALID_PART_ITEM (WIRELESS_SECURITY, FALSE), + NM_META_SETTING_VALID_PART_ITEM (802_1X, FALSE), + ), + .setting_init_fcn = _setting_init_fcn_wireless, + ), + SETTING_INFO (WIRELESS_SECURITY, + .alias = "wifi-sec", + ), }; /*****************************************************************************/ -static const char * -_meta_type_setting_info_editor_get_name (const NMMetaAbstractInfo *abstract_info) +const NMMetaSettingValidPartItem *const nm_meta_setting_info_valid_parts_default[] = { + NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE), + NULL +}; + +/*****************************************************************************/ + +static const NMMetaSettingValidPartItem *const valid_settings_noslave[] = { + NM_META_SETTING_VALID_PART_ITEM (IP4_CONFIG, FALSE), + NM_META_SETTING_VALID_PART_ITEM (IP6_CONFIG, FALSE), + NM_META_SETTING_VALID_PART_ITEM (PROXY, FALSE), + NULL, +}; + +static const NMMetaSettingValidPartItem *const valid_settings_slave_bridge[] = { + NM_META_SETTING_VALID_PART_ITEM (BRIDGE_PORT, TRUE), + NULL, +}; + +static const NMMetaSettingValidPartItem *const valid_settings_slave_team[] = { + NM_META_SETTING_VALID_PART_ITEM (TEAM_PORT, TRUE), + NULL, +}; + +const NMMetaSettingValidPartItem *const* +nm_meta_setting_info_valid_parts_for_slave_type (const char *slave_type, const char **out_slave_name) { + if (!slave_type) { + NM_SET_OUT (out_slave_name, NULL); + return valid_settings_noslave; + } + if (nm_streq (slave_type, NM_SETTING_BOND_SETTING_NAME)) { + NM_SET_OUT (out_slave_name, "bond-slave"); + return NM_PTRARRAY_EMPTY (const NMMetaSettingValidPartItem *); + } + if (nm_streq (slave_type, NM_SETTING_BRIDGE_SETTING_NAME)) { + NM_SET_OUT (out_slave_name, "bridge-slave"); + return valid_settings_slave_bridge; + } + if (nm_streq (slave_type, NM_SETTING_TEAM_SETTING_NAME)) { + NM_SET_OUT (out_slave_name, "team-slave"); + return valid_settings_slave_team; + } + return NULL; +} + +/*****************************************************************************/ + +static const char * +_meta_type_setting_info_editor_get_name (const NMMetaAbstractInfo *abstract_info, gboolean for_header) +{ + if (for_header) + return N_("name"); return ((const NMMetaSettingInfoEditor *) abstract_info)->general->setting_name; } static const char * -_meta_type_property_info_get_name (const NMMetaAbstractInfo *abstract_info) +_meta_type_property_info_get_name (const NMMetaAbstractInfo *abstract_info, gboolean for_header) { return ((const NMMetaPropertyInfo *) abstract_info)->property_name; } static gconstpointer -_meta_type_setting_info_editor_get_fcn (const NMMetaEnvironment *environment, +_meta_type_setting_info_editor_get_fcn (const NMMetaAbstractInfo *abstract_info, + const NMMetaEnvironment *environment, gpointer environment_user_data, - const NMMetaAbstractInfo *abstract_info, gpointer target, NMMetaAccessorGetType get_type, NMMetaAccessorGetFlags get_flags, + NMMetaAccessorGetOutFlags *out_flags, gpointer *out_to_free) { - nm_assert (out_to_free && !*out_to_free); - g_return_val_if_reached (NULL); -} + const NMMetaSettingInfoEditor *info = (const NMMetaSettingInfoEditor *) abstract_info; -static gconstpointer -_meta_type_property_info_get_fcn (const NMMetaEnvironment *environment, - gpointer environment_user_data, - const NMMetaAbstractInfo *abstract_info, - gpointer target, - NMMetaAccessorGetType get_type, - NMMetaAccessorGetFlags get_flags, - gpointer *out_to_free) -{ - const NMMetaPropertyInfo *info = (const NMMetaPropertyInfo *) abstract_info; - - nm_assert (out_to_free && !*out_to_free); + nm_assert (!out_to_free || !*out_to_free); + nm_assert (out_flags && !*out_flags); if (!NM_IN_SET (get_type, NM_META_ACCESSOR_GET_TYPE_PARSABLE, NM_META_ACCESSOR_GET_TYPE_PRETTY)) return NULL; - return (*out_to_free = info->property_type->get_fcn (environment, environment_user_data, - info, target, - get_type, get_flags)); + nm_assert (out_to_free); + + if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY) + return _(info->general->setting_name); + return info->general->setting_name; +} + +static gconstpointer +_meta_type_property_info_get_fcn (const NMMetaAbstractInfo *abstract_info, + const NMMetaEnvironment *environment, + gpointer environment_user_data, + gpointer target, + NMMetaAccessorGetType get_type, + NMMetaAccessorGetFlags get_flags, + NMMetaAccessorGetOutFlags *out_flags, + gpointer *out_to_free) +{ + const NMMetaPropertyInfo *info = (const NMMetaPropertyInfo *) abstract_info; + + nm_assert (!out_to_free || !*out_to_free); + nm_assert (out_flags && !*out_flags); + + if (!NM_IN_SET (get_type, + NM_META_ACCESSOR_GET_TYPE_PARSABLE, + NM_META_ACCESSOR_GET_TYPE_PRETTY)) + return NULL; + + nm_assert (out_to_free); + + if ( info->is_secret + && !NM_FLAGS_HAS (get_flags, NM_META_ACCESSOR_GET_FLAGS_SHOW_SECRETS)) + return _get_text_hidden (get_type); + + return info->property_type->get_fcn (info, + environment, + environment_user_data, + target, + get_type, + get_flags, + out_flags, + out_to_free); + } static const NMMetaAbstractInfo *const* @@ -6692,6 +7750,39 @@ _meta_type_property_info_get_nested (const NMMetaAbstractInfo *abstract_info, return NULL; } +static const char *const* +_meta_type_property_info_complete_fcn (const NMMetaAbstractInfo *abstract_info, + const NMMetaEnvironment *environment, + gpointer environment_user_data, + const NMMetaOperationContext *operation_context, + const char *text, + char ***out_to_free) +{ + const NMMetaPropertyInfo *info = (const NMMetaPropertyInfo *) abstract_info; + + nm_assert (out_to_free && !*out_to_free); + + if (info->property_type->complete_fcn) { + return info->property_type->complete_fcn (info, + environment, + environment_user_data, + operation_context, + text, + out_to_free); + } + + if (info->property_type->values_fcn) { + return info->property_type->values_fcn (info, + out_to_free); + } + + if ( info->property_typ_data + && info->property_typ_data->values_static) + return info->property_typ_data->values_static; + + return NULL; +} + const NMMetaType nm_meta_type_setting_info_editor = { .type_name = "setting_info_editor", .get_name = _meta_type_setting_info_editor_get_name, @@ -6704,4 +7795,9 @@ const NMMetaType nm_meta_type_property_info = { .get_name = _meta_type_property_info_get_name, .get_nested = _meta_type_property_info_get_nested, .get_fcn = _meta_type_property_info_get_fcn, + .complete_fcn = _meta_type_property_info_complete_fcn, +}; + +const NMMetaType nm_meta_type_nested_property_info = { + .type_name = "nested_property_info", }; diff --git a/clients/common/nm-meta-setting-desc.h b/clients/common/nm-meta-setting-desc.h index 37ed367812..cfacd347bf 100644 --- a/clients/common/nm-meta-setting-desc.h +++ b/clients/common/nm-meta-setting-desc.h @@ -22,8 +22,64 @@ #include "nm-meta-setting.h" +struct _NMDevice; + #define NM_META_TEXT_HIDDEN "" +#define NM_META_TEXT_PROMPT_ADSL_PROTO N_("Protocol") +#define NM_META_TEXT_PROMPT_ADSL_PROTO_CHOICES "(" NM_SETTING_ADSL_PROTOCOL_PPPOA "/" NM_SETTING_ADSL_PROTOCOL_PPPOE "/" NM_SETTING_ADSL_PROTOCOL_IPOATM ")" + +#define NM_META_TEXT_PROMPT_ADSL_ENCAP N_("ADSL encapsulation") +#define NM_META_TEXT_PROMPT_ADSL_ENCAP_CHOICES "(" NM_SETTING_ADSL_ENCAPSULATION_VCMUX "/" NM_SETTING_ADSL_ENCAPSULATION_LLC ") [none]" + +#define NM_META_TEXT_PROMPT_CON_TYPE N_("Connection type") +#define NM_META_TEXT_PROMPT_IFNAME N_("Interface name [*]") +#define NM_META_TEXT_PROMPT_VPN_TYPE N_("VPN type") +#define NM_META_TEXT_PROMPT_MASTER N_("Master") + +#define NM_META_TEXT_PROMPT_IB_MODE N_("Transport mode") +#define NM_META_TEXT_WORD_DATAGRAM "datagram" +#define NM_META_TEXT_WORD_CONNECTED "connected" +#define NM_META_TEXT_PROMPT_IB_MODE_CHOICES "(" NM_META_TEXT_WORD_DATAGRAM "/" NM_META_TEXT_WORD_CONNECTED ") [" NM_META_TEXT_WORD_DATAGRAM "]" + +#define NM_META_TEXT_PROMPT_BT_TYPE N_("Bluetooth type") +#define NM_META_TEXT_WORD_PANU "panu" +#define NM_META_TEXT_WORD_DUN_GSM "dun-gsm" +#define NM_META_TEXT_WORD_DUN_CDMA "dun-cdma" +#define NM_META_TEXT_PROMPT_BT_TYPE_CHOICES "(" NM_META_TEXT_WORD_PANU "/" NM_META_TEXT_WORD_DUN_GSM "/" NM_META_TEXT_WORD_DUN_CDMA ") [" NM_META_TEXT_WORD_PANU "]" + +#define NM_META_TEXT_PROMPT_BOND_MODE N_("Bonding mode") + +#define NM_META_TEXT_PROMPT_BOND_MON_MODE N_("Bonding monitoring mode") +#define NM_META_TEXT_WORD_MIIMON "miimon" +#define NM_META_TEXT_WORD_ARP "arp" +#define NM_META_TEXT_PROMPT_BOND_MON_MODE_CHOICES "(" NM_META_TEXT_WORD_MIIMON "/" NM_META_TEXT_WORD_ARP ") [" NM_META_TEXT_WORD_MIIMON "]" + +#define NM_META_TEXT_PROMPT_WIFI_MODE N_("Wi-Fi mode") +#define NM_META_TEXT_WORD_INFRA "infrastructure" +#define NM_META_TEXT_WORD_AP "ap" +#define NM_META_TEXT_WORD_ADHOC "adhoc" +#define NM_META_TEXT_PROMPT_WIFI_MODE_CHOICES "(" NM_META_TEXT_WORD_INFRA "/" NM_META_TEXT_WORD_AP "/" NM_META_TEXT_WORD_ADHOC ") [" NM_META_TEXT_WORD_INFRA "]" + +#define NM_META_TEXT_PROMPT_TUN_MODE N_("Tun mode") +#define NM_META_TEXT_WORD_TUN "tun" +#define NM_META_TEXT_WORD_TAP "tap" +#define NM_META_TEXT_PROMPT_TUN_MODE_CHOICES "(" NM_META_TEXT_WORD_TUN "/" NM_META_TEXT_WORD_TAP ") [" NM_META_TEXT_WORD_TUN "]" + +#define NM_META_TEXT_PROMPT_IP_TUNNEL_MODE N_("IP Tunnel mode") + +#define NM_META_TEXT_PROMPT_MACVLAN_MODE N_("MACVLAN mode") + +#define NM_META_TEXT_PROMPT_MACSEC_MODE N_("MACsec mode") +#define NM_META_TEXT_WORD_PSK "psk" +#define NM_META_TEXT_WORD_EAP "eap" +#define NM_META_TEXT_PROMPT_MACSEC_MODE_CHOICES "(" NM_META_TEXT_WORD_PSK "/" NM_META_TEXT_WORD_EAP ")" + +#define NM_META_TEXT_PROMPT_PROXY_METHOD N_("Proxy method") +#define NM_META_TEXT_WORD_NONE "none" +#define NM_META_TEXT_WORD_AUTO "auto" +#define NM_META_TEXT_PROMPT_PROXY_METHOD_CHOICES "(" NM_META_TEXT_WORD_NONE "/" NM_META_TEXT_WORD_AUTO ") [" NM_META_TEXT_WORD_NONE "]" + typedef enum { NM_META_TERM_COLOR_NORMAL = 0, NM_META_TERM_COLOR_BLACK = 1, @@ -49,13 +105,51 @@ typedef enum { typedef enum { NM_META_ACCESSOR_GET_TYPE_PRETTY, NM_META_ACCESSOR_GET_TYPE_PARSABLE, + NM_META_ACCESSOR_GET_TYPE_TERMFORMAT, } NMMetaAccessorGetType; +typedef enum { + NM_META_ACCESSOR_SETTING_INIT_TYPE_DEFAULT, + NM_META_ACCESSOR_SETTING_INIT_TYPE_CLI, +} NMMetaAccessorSettingInitType; + +static inline void +nm_meta_termformat_unpack (gconstpointer value, NMMetaTermColor *out_color, NMMetaTermFormat *out_format) +{ + /* get_fcn() with NM_META_ACCESSOR_GET_TYPE_TERMFORMAT returns a pointer + * that encodes NMMetaTermColor and NMMetaTermFormat. Unpack it. */ + if (!value) { + /* by default, objects that don't support NM_META_ACCESSOR_GET_TYPE_TERMFORMAT + * return NULL. This allows for an explicit fallback value here... */ + NM_SET_OUT (out_color, NM_META_TERM_COLOR_NORMAL); + NM_SET_OUT (out_format, NM_META_TERM_FORMAT_NORMAL); + } else { + NM_SET_OUT (out_color, GPOINTER_TO_UINT (value) & 0xFF); + NM_SET_OUT (out_format, (GPOINTER_TO_UINT (value) & 0xFF00) >> 8); + } +} + +static inline gconstpointer +nm_meta_termformat_pack (NMMetaTermColor color, NMMetaTermFormat format) +{ + /* get_fcn() with NM_META_ACCESSOR_GET_TYPE_TERMFORMAT returns a pointer + * that encodes NMMetaTermColor and NMMetaTermFormat. Pack it. */ + return GUINT_TO_POINTER (((guint) 0x10000) | (((guint) color) & 0xFFu) | ((((guint) format) & 0xFFu) << 8)); +} + +#define NM_META_TERMFORMAT_DEFAULT() (nm_meta_termformat_pack (NM_META_TERM_COLOR_NORMAL, NM_META_TERM_FORMAT_NORMAL)) + typedef enum { NM_META_ACCESSOR_GET_FLAGS_NONE = 0, - NM_META_ACCESSOR_GET_FLAGS_SHOW_SECRETS = (1LL << 0), + NM_META_ACCESSOR_GET_FLAGS_ACCEPT_STRV = (1LL << 0), + NM_META_ACCESSOR_GET_FLAGS_SHOW_SECRETS = (1LL << 1), } NMMetaAccessorGetFlags; +typedef enum { + NM_META_ACCESSOR_GET_OUT_FLAGS_NONE = 0, + NM_META_ACCESSOR_GET_OUT_FLAGS_STRV = (1LL << 0), +} NMMetaAccessorGetOutFlags; + typedef enum { NM_META_PROPERTY_TYP_FLAG_ENUM_GET_PRETTY_NUMERIC = (1LL << 0), NM_META_PROPERTY_TYP_FLAG_ENUM_GET_PRETTY_NUMERIC_HEX = (1LL << 1), @@ -79,27 +173,36 @@ typedef struct _NMMetaSettingInfoEditor NMMetaSettingInfoEditor; typedef struct _NMMetaPropertyInfo NMMetaPropertyInfo; typedef struct _NMMetaPropertyType NMMetaPropertyType; typedef struct _NMMetaPropertyTypData NMMetaPropertyTypData; +typedef struct _NMMetaOperationContext NMMetaOperationContext; + +/* this gives some context information for virtual functions. + * This command actually violates layering, and should be considered + * a hack. In the future, try to replace it's use. */ +struct _NMMetaOperationContext { + NMConnection *connection; +}; struct _NMMetaPropertyType { const char *(*describe_fcn) (const NMMetaPropertyInfo *property_info, char **out_to_free); - - char *(*get_fcn) (const NMMetaEnvironment *environment, - gpointer environment_user_data, - const NMMetaPropertyInfo *property_info, - NMSetting *setting, - NMMetaAccessorGetType get_type, - NMMetaAccessorGetFlags get_flags); - gboolean (*set_fcn) (const NMMetaEnvironment *environment, + gconstpointer (*get_fcn) (const NMMetaPropertyInfo *property_info, + const NMMetaEnvironment *environment, + gpointer environment_user_data, + NMSetting *setting, + NMMetaAccessorGetType get_type, + NMMetaAccessorGetFlags get_flags, + NMMetaAccessorGetOutFlags *out_flags, + gpointer *out_to_free); + gboolean (*set_fcn) (const NMMetaPropertyInfo *property_info, + const NMMetaEnvironment *environment, gpointer environment_user_data, - const NMMetaPropertyInfo *property_info, NMSetting *setting, const char *value, GError **error); - gboolean (*remove_fcn) (const NMMetaEnvironment *environment, + gboolean (*remove_fcn) (const NMMetaPropertyInfo *property_info, + const NMMetaEnvironment *environment, gpointer environment_user_data, - const NMMetaPropertyInfo *property_info, NMSetting *setting, const char *option, guint32 idx, @@ -107,10 +210,19 @@ struct _NMMetaPropertyType { const char *const*(*values_fcn) (const NMMetaPropertyInfo *property_info, char ***out_to_free); + + const char *const*(*complete_fcn) (const NMMetaPropertyInfo *property_info, + const NMMetaEnvironment *environment, + gpointer environment_user_data, + const NMMetaOperationContext *operation_context, + const char *text, + char ***out_to_free); }; struct _NMUtilsEnumValueInfo; +struct _NMMetaPropertyTypDataNested; + struct _NMMetaPropertyTypData { union { struct { @@ -128,11 +240,29 @@ struct _NMMetaPropertyTypData { struct { NMMetaPropertyTypeMacMode mode; } mac; + struct { + const struct _NMMetaPropertyTypDataNested *data; + } nested; } subtype; const char *const*values_static; NMMetaPropertyTypFlags typ_flags; }; +typedef enum { + NM_META_PROPERTY_INF_FLAG_NONE = 0x00, + NM_META_PROPERTY_INF_FLAG_REQD = 0x01, /* Don't ask to ask. */ + NM_META_PROPERTY_INF_FLAG_DONT_ASK = 0x02, /* Don't ask interactively by default */ + NM_META_PROPERTY_INF_FLAG_MULTI = 0x04, /* Ask multiple times, do an append instead of set. */ +} NMMetaPropertyInfFlags; + +enum { + _NM_META_PROPERTY_TYPE_VPN_SERVICE_TYPE = 0, + _NM_META_PROPERTY_TYPE_CONNECTION_TYPE = 4, +}; + +#define nm_meta_property_info_connection_type (&nm_meta_setting_infos_editor[NM_META_SETTING_TYPE_CONNECTION].properties[_NM_META_PROPERTY_TYPE_CONNECTION_TYPE]) +#define nm_meta_property_info_vpn_service_type (&nm_meta_setting_infos_editor[NM_META_SETTING_TYPE_VPN].properties[_NM_META_PROPERTY_TYPE_VPN_SERVICE_TYPE]) + struct _NMMetaPropertyInfo { const NMMetaType *meta_type; @@ -140,14 +270,17 @@ struct _NMMetaPropertyInfo { const char *property_name; - /* the property list for now must contain as first field the - * "name", which isn't a regular property. This is required by - * NmcOutputField and this first field is ignored for the - * group_list/setting_info. */ - bool is_name:1; + const char *property_alias; + NMMetaPropertyInfFlags inf_flags; bool is_secret:1; + bool is_cli_option:1; + + const char *prompt; + + const char *def_hint; + const char *describe_doc; const char *describe_message; @@ -156,38 +289,63 @@ struct _NMMetaPropertyInfo { const NMMetaPropertyTypData *property_typ_data; }; +typedef struct _NMMetaSettingValidPartItem { + const NMMetaSettingInfoEditor *setting_info; + bool mandatory; +} NMMetaSettingValidPartItem; + struct _NMMetaSettingInfoEditor { const NMMetaType *meta_type; const NMMetaSettingInfo *general; + const char *alias; + const char *pretty_name; /* the order of the properties matter. The first *must* be the * "name", and then the order is as they are listed by default. */ const NMMetaPropertyInfo *properties; guint properties_num; + + /* a NMConnection has a main type (connection.type), which is a + * main NMSetting instance. Depending on the type, a connection + * may have a list of other allowed settings. + * + * For example, a connection of type "vlan" may have settings + * of type "connection", "vlan", and "wired". + * + * Some setting types a not a main type (NMSettingProxy). They + * don't have valid_settings but are usually referenced by other + * settings to be valid for them. */ + const NMMetaSettingValidPartItem *const*valid_parts; + + void (*setting_init_fcn) (const NMMetaSettingInfoEditor *setting_info, + NMSetting *setting, + NMMetaAccessorSettingInitType init_type); }; struct _NMMetaType { const char *type_name; - const char *(*get_name) (const NMMetaAbstractInfo *abstract_info); + const char *(*get_name) (const NMMetaAbstractInfo *abstract_info, + gboolean for_header); const NMMetaAbstractInfo *const*(*get_nested) (const NMMetaAbstractInfo *abstract_info, guint *out_len, gpointer *out_to_free); - gconstpointer (*get_fcn) (const NMMetaEnvironment *environment, + gconstpointer (*get_fcn) (const NMMetaAbstractInfo *info, + const NMMetaEnvironment *environment, gpointer environment_user_data, - const NMMetaAbstractInfo *info, gpointer target, NMMetaAccessorGetType get_type, NMMetaAccessorGetFlags get_flags, + NMMetaAccessorGetOutFlags *out_flags, gpointer *out_to_free); + const char *const*(*complete_fcn) (const NMMetaAbstractInfo *info, + const NMMetaEnvironment *environment, + gpointer environment_user_data, + const NMMetaOperationContext *operation_context, + const char *text, + char ***out_to_free); }; struct _NMMetaAbstractInfo { - union { - const NMMetaType *meta_type; - union { - NMMetaSettingInfoEditor setting_info; - NMMetaPropertyInfo property_info; - } as; - }; + const NMMetaType *meta_type; }; extern const NMMetaType nm_meta_type_setting_info_editor; @@ -195,6 +353,10 @@ extern const NMMetaType nm_meta_type_property_info; extern const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[_NM_META_SETTING_TYPE_NUM]; +extern const NMMetaSettingValidPartItem *const nm_meta_setting_info_valid_parts_default[]; + +const NMMetaSettingValidPartItem *const*nm_meta_setting_info_valid_parts_for_slave_type (const char *slave_type, const char **out_slave_name); + /*****************************************************************************/ typedef enum { @@ -214,8 +376,40 @@ struct _NMMetaEnvironment { const char *fmt_l10n, /* the untranslated format string, but it is marked for translation using N_(). */ va_list ap); + struct _NMDevice *const*(*get_nm_devices) (const NMMetaEnvironment *environment, + gpointer environment_user_data, + guint *out_len); + + struct _NMRemoteConnection *const*(*get_nm_connections) (const NMMetaEnvironment *environment, + gpointer environment_user_data, + guint *out_len); + }; /*****************************************************************************/ +/* NMSettingBond is special in that it has nested properties. + * We will add API to proper handle such types (Bond, VPN, User), + * but for now just expose the type info directly. */ + +extern const NMMetaType nm_meta_type_nested_property_info; + +typedef struct _NMMetaNestedPropertyTypeInfo { + const NMMetaType *meta_type; + const NMMetaPropertyInfo *parent_info; + const char *field_name; + NMMetaPropertyInfFlags inf_flags; + const char *prompt; + const char *def_hint; +} NMMetaNestedPropertyTypeInfo; + +typedef struct _NMMetaPropertyTypDataNested { + const NMMetaNestedPropertyTypeInfo *nested; + guint nested_len; +} NMMetaPropertyTypDataNested; + +const NMMetaPropertyTypDataNested nm_meta_property_typ_data_bond; + +/*****************************************************************************/ + #endif /* __NM_META_SETTING_DESC_H__ */ diff --git a/clients/common/tests/test-general.c b/clients/common/tests/test-general.c index 469dc57a73..058ee26994 100644 --- a/clients/common/tests/test-general.c +++ b/clients/common/tests/test-general.c @@ -34,6 +34,9 @@ test_client_meta_check (void) NMMetaSettingType m; guint p; + G_STATIC_ASSERT (G_STRUCT_OFFSET (NMMetaAbstractInfo, meta_type) == G_STRUCT_OFFSET (NMMetaSettingInfoEditor, meta_type)); + G_STATIC_ASSERT (G_STRUCT_OFFSET (NMMetaAbstractInfo, meta_type) == G_STRUCT_OFFSET (NMMetaPropertyInfo, meta_type)); + for (m = 0; m < _NM_META_SETTING_TYPE_NUM; m++) { const NMMetaSettingInfo *info = &nm_meta_setting_infos[m]; GType gtype; @@ -68,7 +71,8 @@ test_client_meta_check (void) g_assert (info->general); g_assert (info->general == &nm_meta_setting_infos[m]); - g_assert (info->general->setting_name == info->meta_type->get_name ((const NMMetaAbstractInfo *) info)); + g_assert_cmpstr (info->general->setting_name, ==, info->meta_type->get_name ((const NMMetaAbstractInfo *) info, FALSE)); + g_assert_cmpstr ("name", ==, info->meta_type->get_name ((const NMMetaAbstractInfo *) info, TRUE)); if (info->properties_num) { gs_unref_hashtable GHashTable *property_names = g_hash_table_new (g_str_hash, g_str_equal); @@ -83,18 +87,37 @@ test_client_meta_check (void) g_assert (nm_g_hash_table_add (property_names, (gpointer) pi->property_name)); - g_assert (pi->property_name == pi->meta_type->get_name ((const NMMetaAbstractInfo *) pi)); - - if (pi->is_name) - g_assert (p == 0); - else - g_assert (p != 0); + g_assert_cmpstr (pi->property_name, ==, pi->meta_type->get_name ((const NMMetaAbstractInfo *) pi, FALSE)); + g_assert_cmpstr (pi->property_name, ==, pi->meta_type->get_name ((const NMMetaAbstractInfo *) pi, TRUE)); g_assert (pi->property_type); g_assert (pi->property_type->get_fcn); } } else g_assert (!info->properties); + + if (info->valid_parts) { + gsize i, l; + gs_unref_hashtable GHashTable *dup = g_hash_table_new (NULL, NULL); + + l = NM_PTRARRAY_LEN (info->valid_parts); + g_assert (l >= 2); + + for (i = 0; info->valid_parts[i]; i++) { + g_assert (info->valid_parts[i]->setting_info); + g_assert (nm_g_hash_table_add (dup, (gpointer) info->valid_parts[i]->setting_info)); + + if (i == 0) { + g_assert (info->valid_parts[i]->setting_info == &nm_meta_setting_infos_editor[NM_META_SETTING_TYPE_CONNECTION]); + g_assert (info->valid_parts[i]->mandatory); + } + if (i == 1) { + g_assert (info->valid_parts[i]->setting_info == &nm_meta_setting_infos_editor[m]); + g_assert (info->valid_parts[i]->mandatory); + } + } + g_assert (i == l); + } } for (m = 0; m < _NM_META_SETTING_TYPE_NUM; m++) { @@ -112,7 +135,7 @@ test_client_meta_check (void) for (m = 0; m < _NM_META_SETTING_TYPE_NUM; m++) { const NMMetaSettingInfoEditor *info = &nm_meta_setting_infos_editor[m]; - g_assert (nm_meta_setting_info_editor_find_by_name (info->general->setting_name) == info); + g_assert (nm_meta_setting_info_editor_find_by_name (info->general->setting_name, FALSE) == info); g_assert (nm_meta_setting_info_editor_find_by_gtype (info->general->get_setting_gtype ()) == info); for (p = 0; p < info->properties_num; p++) { diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c index 0f65e8f6ae..0d6cb5322d 100644 --- a/libnm-core/tests/test-general.c +++ b/libnm-core/tests/test-general.c @@ -4655,6 +4655,81 @@ test_nm_utils_strstrdictkey (void) /*****************************************************************************/ +static guint +_g_strv_length (gconstpointer arr) +{ + return arr ? g_strv_length ((char **) arr) : 0; +} + +static void +test_nm_ptrarray_len (void) +{ +#define _PTRARRAY_cmp(len, arr) \ + G_STMT_START { \ + g_assert_cmpint (len, ==, NM_PTRARRAY_LEN (arr)); \ + g_assert_cmpint (len, ==, _g_strv_length (arr)); \ + } G_STMT_END +#define _PTRARRAY_LEN0(T) \ + G_STMT_START { \ + T **vnull = NULL; \ + T *const*vnull1 = NULL; \ + T *const*const vnull2 = NULL; \ + T *v0[] = { NULL }; \ + T *const*v01 = v0; \ + T *const*const v02 = v0; \ + T **const v03 = v0; \ + \ + _PTRARRAY_cmp (0, vnull); \ + _PTRARRAY_cmp (0, vnull1); \ + _PTRARRAY_cmp (0, vnull2); \ + _PTRARRAY_cmp (0, v0); \ + _PTRARRAY_cmp (0, v01); \ + _PTRARRAY_cmp (0, v02); \ + _PTRARRAY_cmp (0, v03); \ + } G_STMT_END + + _PTRARRAY_LEN0 (char); + _PTRARRAY_LEN0 (const char); + _PTRARRAY_LEN0 (int); + _PTRARRAY_LEN0 (const int); + _PTRARRAY_LEN0 (void *); + _PTRARRAY_LEN0 (void); + _PTRARRAY_LEN0 (const void); + +#define _PTRARRAY_LENn(T) \ + G_STMT_START { \ + T x[5] = { 0 }; \ + \ + T *v1[] = { &x[0], NULL }; \ + T *const*v11 = v1; \ + T *const*const v12 = v1; \ + T **const v13 = v1; \ + \ + T *v2[] = { &x[0], &x[1], NULL }; \ + T *const*v21 = v2; \ + T *const*const v22 = v2; \ + T **const v23 = v2; \ + \ + _PTRARRAY_cmp (1, v1); \ + _PTRARRAY_cmp (1, v11); \ + _PTRARRAY_cmp (1, v12); \ + _PTRARRAY_cmp (1, v13); \ + \ + _PTRARRAY_cmp (2, v2); \ + _PTRARRAY_cmp (2, v21); \ + _PTRARRAY_cmp (2, v22); \ + _PTRARRAY_cmp (2, v23); \ + } G_STMT_END + + _PTRARRAY_LENn (char); + _PTRARRAY_LENn (const char); + _PTRARRAY_LENn (int); + _PTRARRAY_LENn (const int); + _PTRARRAY_LENn (void *); +} + +/*****************************************************************************/ + static void test_nm_utils_dns_option_validate_do (char *option, gboolean ipv6, const NMUtilsDNSOptionDesc *descs, gboolean exp_result, char *exp_name, gboolean exp_value) @@ -5716,6 +5791,7 @@ int main (int argc, char **argv) g_test_add_func ("/core/general/_glib_compat_g_hash_table_get_keys_as_array", test_g_hash_table_get_keys_as_array); g_test_add_func ("/core/general/_nm_utils_ptrarray_find_binary_search", test_nm_utils_ptrarray_find_binary_search); g_test_add_func ("/core/general/_nm_utils_strstrdictkey", test_nm_utils_strstrdictkey); + g_test_add_func ("/core/general/nm_ptrarray_len", test_nm_ptrarray_len); g_test_add_func ("/core/general/_nm_utils_dns_option_validate", test_nm_utils_dns_option_validate); g_test_add_func ("/core/general/_nm_utils_dns_option_find_idx", test_nm_utils_dns_option_find_idx); diff --git a/shared/nm-meta-setting.c b/shared/nm-meta-setting.c index 58bd3f1004..1294a24d98 100644 --- a/shared/nm-meta-setting.c +++ b/shared/nm-meta-setting.c @@ -190,6 +190,11 @@ const NMMetaSettingInfo nm_meta_setting_infos[] = { .setting_name = N_ (NM_SETTING_DUMMY_SETTING_NAME), .get_setting_gtype = nm_setting_dummy_get_type, }, + [NM_META_SETTING_TYPE_GENERIC] = { + .meta_type = NM_META_SETTING_TYPE_GENERIC, + .setting_name = N_ (NM_SETTING_GENERIC_SETTING_NAME), + .get_setting_gtype = nm_setting_generic_get_type, + }, [NM_META_SETTING_TYPE_GSM] = { .meta_type = NM_META_SETTING_TYPE_GSM, .setting_name = N_ (NM_SETTING_GSM_SETTING_NAME), diff --git a/shared/nm-meta-setting.h b/shared/nm-meta-setting.h index 3d78a85045..949a6920c6 100644 --- a/shared/nm-meta-setting.h +++ b/shared/nm-meta-setting.h @@ -66,6 +66,7 @@ typedef enum { NM_META_SETTING_TYPE_CONNECTION, NM_META_SETTING_TYPE_DCB, NM_META_SETTING_TYPE_DUMMY, + NM_META_SETTING_TYPE_GENERIC, NM_META_SETTING_TYPE_GSM, NM_META_SETTING_TYPE_INFINIBAND, NM_META_SETTING_TYPE_IP4_CONFIG, diff --git a/shared/nm-utils/nm-macros-internal.h b/shared/nm-utils/nm-macros-internal.h index f362968f58..eaf8b9e54d 100644 --- a/shared/nm-utils/nm-macros-internal.h +++ b/shared/nm-utils/nm-macros-internal.h @@ -209,6 +209,23 @@ NM_G_ERROR_MSG (GError *error) /* macro to return strlen() of a compile time string. */ #define NM_STRLEN(str) ( sizeof ("" str) - 1 ) +/* returns the length of a NULL terminated array of pointers, + * like g_strv_length() does. The difference is: + * - it operats on arrays of pointers (of any kind, requiring no cast). + * - it accepts NULL to return zero. */ +#define NM_PTRARRAY_LEN(array) \ + ({ \ + typeof (*(array)) *const _array = (array); \ + gsize _n = 0; \ + \ + if (_array) { \ + _nm_unused typeof (*(_array[0])) *_array_check = _array[0]; \ + while (_array[_n]) \ + _n++; \ + } \ + _n; \ + }) + /* Note: @value is only evaluated when *out_val is present. * Thus, * NM_SET_OUT (out_str, g_strdup ("hallo")); diff --git a/shared/nm-utils/nm-shared-utils.c b/shared/nm-utils/nm-shared-utils.c index 1a83cb9da3..8bd81dafda 100644 --- a/shared/nm-utils/nm-shared-utils.c +++ b/shared/nm-utils/nm-shared-utils.c @@ -27,6 +27,10 @@ /*****************************************************************************/ +const void *const _NM_PTRARRAY_EMPTY[1] = { NULL }; + +/*****************************************************************************/ + void nm_utils_strbuf_append_c (char **buf, gsize *len, char c) { diff --git a/shared/nm-utils/nm-shared-utils.h b/shared/nm-utils/nm-shared-utils.h index 4d8f300c85..3776c1590e 100644 --- a/shared/nm-utils/nm-shared-utils.h +++ b/shared/nm-utils/nm-shared-utils.h @@ -24,6 +24,10 @@ /*****************************************************************************/ +extern const void *const _NM_PTRARRAY_EMPTY[1]; + +#define NM_PTRARRAY_EMPTY(type) ((type const*) _NM_PTRARRAY_EMPTY) + static inline void _nm_utils_strbuf_init (char *buf, gsize len, char **p_buf_ptr, gsize *p_buf_len) {