diff options
| author | Michael Biebl <biebl@debian.org> | 2017-11-07 00:14:39 +0100 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2017-11-07 00:14:39 +0100 |
| commit | 90e8691111889a7b5f3c812f5a41f15a8a058913 (patch) | |
| tree | f101a879eca27c34a9bfa5f3da52266b22539a36 /clients/cli/connections.c | |
| parent | bdb6eeb0670658255c2a4c3c501c0a27fa8cfe55 (diff) | |
New upstream version 1.9.90 upstream/1.9.90
Diffstat (limited to 'clients/cli/connections.c')
| -rw-r--r-- | clients/cli/connections.c | 3051 |
1 files changed, 1413 insertions, 1638 deletions
diff --git a/clients/cli/connections.c b/clients/cli/connections.c index a93dc15f..c05a9e82 100644 --- a/clients/cli/connections.c +++ b/clients/cli/connections.c @@ -19,6 +19,8 @@ #include "nm-default.h" +#include "connections.h" + #include <stdio.h> #include <string.h> #include <stdlib.h> @@ -29,33 +31,35 @@ #include <readline/readline.h> #include <readline/history.h> +#include "nm-utils/nm-hash-utils.h" + +#include "nm-client-utils.h" +#include "nm-vpn-helpers.h" +#include "nm-meta-setting-access.h" +#include "nm-secret-agent-simple.h" + #include "utils.h" #include "common.h" #include "settings.h" -#include "connections.h" #include "devices.h" -#include "nm-secret-agent-simple.h" #include "polkit-agent.h" -#include "nm-vpn-helpers.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 */ @@ -64,59 +68,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)") @@ -125,68 +76,44 @@ struct _OptionInfo { #define BASE_PROMPT "nmcli> " -/* Available fields for 'connection show' */ -NmcOutputField nmc_fields_con_show[] = { - {"NAME", N_("NAME")}, /* 0 */ - {"UUID", N_("UUID")}, /* 1 */ - {"TYPE", N_("TYPE")}, /* 2 */ - {"TIMESTAMP", N_("TIMESTAMP")}, /* 3 */ - {"TIMESTAMP-REAL", N_("TIMESTAMP-REAL")}, /* 4 */ - {"AUTOCONNECT", N_("AUTOCONNECT")}, /* 5 */ - {"AUTOCONNECT-PRIORITY", N_("AUTOCONNECT-PRIORITY")}, /* 6 */ - {"READONLY", N_("READONLY")}, /* 7 */ - {"DBUS-PATH", N_("DBUS-PATH")}, /* 8 */ - {"ACTIVE", N_("ACTIVE")}, /* 9 */ - {"DEVICE", N_("DEVICE")}, /* 10 */ - {"STATE", N_("STATE")}, /* 11 */ - {"ACTIVE-PATH", N_("ACTIVE-PATH")}, /* 12 */ - {"SLAVE", N_("SLAVE")}, /* 13 */ - {NULL, NULL} +/*****************************************************************************/ + +const NmcMetaGenericInfo *const nmc_fields_con_show[] = { + NMC_META_GENERIC ("NAME"), /* 0 */ + NMC_META_GENERIC ("UUID"), /* 1 */ + NMC_META_GENERIC ("TYPE"), /* 2 */ + NMC_META_GENERIC ("TIMESTAMP"), /* 3 */ + NMC_META_GENERIC ("TIMESTAMP-REAL"), /* 4 */ + NMC_META_GENERIC ("AUTOCONNECT"), /* 5 */ + NMC_META_GENERIC ("AUTOCONNECT-PRIORITY"), /* 6 */ + NMC_META_GENERIC ("READONLY"), /* 7 */ + NMC_META_GENERIC ("DBUS-PATH"), /* 8 */ + NMC_META_GENERIC ("ACTIVE"), /* 9 */ + NMC_META_GENERIC ("DEVICE"), /* 10 */ + NMC_META_GENERIC ("STATE"), /* 11 */ + NMC_META_GENERIC ("ACTIVE-PATH"), /* 12 */ + NMC_META_GENERIC ("SLAVE"), /* 13 */ + NULL, }; -#define NMC_FIELDS_CON_SHOW_ALL "NAME,UUID,TYPE,TIMESTAMP,TIMESTAMP-REAL,AUTOCONNECT,AUTOCONNECT-PRIORITY,READONLY,DBUS-PATH,"\ - "ACTIVE,DEVICE,STATE,ACTIVE-PATH,SLAVE" #define NMC_FIELDS_CON_SHOW_COMMON "NAME,UUID,TYPE,DEVICE" -/* Helper macro to define fields */ -#define SETTING_FIELD(setting, props) { setting, N_(setting), 0, props, NULL, FALSE, FALSE, 0 } - -/* Available settings for 'connection show <con>' - profile part */ -NmcOutputField nmc_fields_settings_names[] = { - SETTING_FIELD (NM_SETTING_CONNECTION_SETTING_NAME, nmc_fields_setting_connection + 1), /* 0 */ - SETTING_FIELD (NM_SETTING_WIRED_SETTING_NAME, nmc_fields_setting_wired + 1), /* 1 */ - SETTING_FIELD (NM_SETTING_802_1X_SETTING_NAME, nmc_fields_setting_8021X + 1), /* 2 */ - SETTING_FIELD (NM_SETTING_WIRELESS_SETTING_NAME, nmc_fields_setting_wireless + 1), /* 3 */ - SETTING_FIELD (NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, nmc_fields_setting_wireless_security + 1), /* 4 */ - SETTING_FIELD (NM_SETTING_IP4_CONFIG_SETTING_NAME, nmc_fields_setting_ip4_config + 1), /* 5 */ - SETTING_FIELD (NM_SETTING_IP6_CONFIG_SETTING_NAME, nmc_fields_setting_ip6_config + 1), /* 6 */ - SETTING_FIELD (NM_SETTING_SERIAL_SETTING_NAME, nmc_fields_setting_serial + 1), /* 7 */ - SETTING_FIELD (NM_SETTING_PPP_SETTING_NAME, nmc_fields_setting_ppp + 1), /* 8 */ - SETTING_FIELD (NM_SETTING_PPPOE_SETTING_NAME, nmc_fields_setting_pppoe + 1), /* 9 */ - SETTING_FIELD (NM_SETTING_GSM_SETTING_NAME, nmc_fields_setting_gsm + 1), /* 10 */ - SETTING_FIELD (NM_SETTING_CDMA_SETTING_NAME, nmc_fields_setting_cdma + 1), /* 11 */ - SETTING_FIELD (NM_SETTING_BLUETOOTH_SETTING_NAME, nmc_fields_setting_bluetooth + 1), /* 12 */ - SETTING_FIELD (NM_SETTING_OLPC_MESH_SETTING_NAME, nmc_fields_setting_olpc_mesh + 1), /* 13 */ - SETTING_FIELD (NM_SETTING_VPN_SETTING_NAME, nmc_fields_setting_vpn + 1), /* 14 */ - SETTING_FIELD (NM_SETTING_WIMAX_SETTING_NAME, nmc_fields_setting_wimax + 1), /* 15 */ - SETTING_FIELD (NM_SETTING_INFINIBAND_SETTING_NAME, nmc_fields_setting_infiniband + 1), /* 16 */ - SETTING_FIELD (NM_SETTING_BOND_SETTING_NAME, nmc_fields_setting_bond + 1), /* 17 */ - SETTING_FIELD (NM_SETTING_VLAN_SETTING_NAME, nmc_fields_setting_vlan + 1), /* 18 */ - SETTING_FIELD (NM_SETTING_ADSL_SETTING_NAME, nmc_fields_setting_adsl + 1), /* 19 */ - SETTING_FIELD (NM_SETTING_BRIDGE_SETTING_NAME, nmc_fields_setting_bridge + 1), /* 20 */ - SETTING_FIELD (NM_SETTING_BRIDGE_PORT_SETTING_NAME, nmc_fields_setting_bridge_port + 1), /* 21 */ - SETTING_FIELD (NM_SETTING_TEAM_SETTING_NAME, nmc_fields_setting_team + 1), /* 22 */ - SETTING_FIELD (NM_SETTING_TEAM_PORT_SETTING_NAME, nmc_fields_setting_team_port + 1), /* 23 */ - SETTING_FIELD (NM_SETTING_DCB_SETTING_NAME, nmc_fields_setting_dcb + 1), /* 24 */ - SETTING_FIELD (NM_SETTING_TUN_SETTING_NAME, nmc_fields_setting_tun + 1), /* 25 */ - SETTING_FIELD (NM_SETTING_IP_TUNNEL_SETTING_NAME, nmc_fields_setting_ip_tunnel + 1), /* 26 */ - SETTING_FIELD (NM_SETTING_MACSEC_SETTING_NAME, nmc_fields_setting_macsec + 1), /* 27 */ - SETTING_FIELD (NM_SETTING_MACVLAN_SETTING_NAME, nmc_fields_setting_macvlan + 1), /* 28 */ - SETTING_FIELD (NM_SETTING_VXLAN_SETTING_NAME, nmc_fields_setting_vxlan + 1), /* 29 */ - SETTING_FIELD (NM_SETTING_PROXY_SETTING_NAME, nmc_fields_setting_proxy + 1), /* 30 */ - SETTING_FIELD (NM_SETTING_DUMMY_SETTING_NAME, nmc_fields_setting_dummy + 1), /* 31 */ - {NULL, NULL, 0, NULL, NULL, FALSE, FALSE, 0} +const NmcMetaGenericInfo *const nmc_fields_con_active_details_general[] = { + NMC_META_GENERIC ("GROUP"), /* 0 */ + NMC_META_GENERIC ("NAME"), /* 1 */ + NMC_META_GENERIC ("UUID"), /* 2 */ + NMC_META_GENERIC ("DEVICES"), /* 3 */ + NMC_META_GENERIC ("STATE"), /* 4 */ + NMC_META_GENERIC ("DEFAULT"), /* 5 */ + NMC_META_GENERIC ("DEFAULT6"), /* 6 */ + NMC_META_GENERIC ("SPEC-OBJECT"), /* 7 */ + NMC_META_GENERIC ("VPN"), /* 8 */ + NMC_META_GENERIC ("DBUS-PATH"), /* 9 */ + NMC_META_GENERIC ("CON-PATH"), /* 10 */ + NMC_META_GENERIC ("ZONE"), /* 11 */ + NMC_META_GENERIC ("MASTER-PATH"), /* 12 */ + NULL, }; -#define NMC_FIELDS_SETTINGS_NAMES_ALL_X NM_SETTING_CONNECTION_SETTING_NAME","\ +#define NMC_FIELDS_SETTINGS_NAMES_ALL NM_SETTING_CONNECTION_SETTING_NAME","\ NM_SETTING_WIRED_SETTING_NAME","\ NM_SETTING_802_1X_SETTING_NAME","\ NM_SETTING_WIRELESS_SETTING_NAME","\ @@ -209,6 +136,10 @@ NmcOutputField nmc_fields_settings_names[] = { NM_SETTING_BRIDGE_PORT_SETTING_NAME","\ NM_SETTING_TEAM_SETTING_NAME","\ NM_SETTING_TEAM_PORT_SETTING_NAME"," \ + NM_SETTING_OVS_BRIDGE_SETTING_NAME","\ + NM_SETTING_OVS_INTERFACE_SETTING_NAME","\ + NM_SETTING_OVS_PATCH_SETTING_NAME","\ + NM_SETTING_OVS_PORT_SETTING_NAME","\ NM_SETTING_DCB_SETTING_NAME"," \ NM_SETTING_TUN_SETTING_NAME"," \ NM_SETTING_IP_TUNNEL_SETTING_NAME"," \ @@ -216,61 +147,30 @@ NmcOutputField nmc_fields_settings_names[] = { NM_SETTING_MACVLAN_SETTING_NAME"," \ NM_SETTING_VXLAN_SETTING_NAME"," \ NM_SETTING_PROXY_SETTING_NAME -#define NMC_FIELDS_SETTINGS_NAMES_ALL NMC_FIELDS_SETTINGS_NAMES_ALL_X - -/* Active connection data */ -/* Available fields for GENERAL group */ -NmcOutputField nmc_fields_con_active_details_general[] = { - {"GROUP", N_("GROUP")}, /* 0 */ - {"NAME", N_("NAME")}, /* 1 */ - {"UUID", N_("UUID")}, /* 2 */ - {"DEVICES", N_("DEVICES")}, /* 3 */ - {"STATE", N_("STATE")}, /* 4 */ - {"DEFAULT", N_("DEFAULT")}, /* 5 */ - {"DEFAULT6", N_("DEFAULT6")}, /* 6 */ - {"SPEC-OBJECT", N_("SPEC-OBJECT")}, /* 7 */ - {"VPN", N_("VPN")}, /* 8 */ - {"DBUS-PATH", N_("DBUS-PATH")}, /* 9 */ - {"CON-PATH", N_("CON-PATH")}, /* 10 */ - {"ZONE", N_("ZONE")}, /* 11 */ - {"MASTER-PATH", N_("MASTER-PATH")}, /* 12 */ - {NULL, NULL} -}; -#define NMC_FIELDS_CON_ACTIVE_DETAILS_GENERAL_ALL "GROUP,NAME,UUID,DEVICES,STATE,DEFAULT,DEFAULT6,"\ - "VPN,ZONE,DBUS-PATH,CON-PATH,SPEC-OBJECT,MASTER-PATH" - -/* IP group is handled by common.c */ - -/* Available fields for VPN group */ -NmcOutputField nmc_fields_con_active_details_vpn[] = { - {"GROUP", N_("GROUP")}, /* 0 */ - {"TYPE", N_("TYPE")}, /* 1 */ - {"USERNAME", N_("USERNAME")}, /* 2 */ - {"GATEWAY", N_("GATEWAY")}, /* 3 */ - {"BANNER", N_("BANNER")}, /* 4 */ - {"VPN-STATE", N_("VPN-STATE")}, /* 5 */ - {"CFG", N_("CFG")}, /* 6 */ - {NULL, NULL} + // NM_SETTING_DUMMY_SETTING_NAME + // NM_SETTING_WIMAX_SETTING_NAME + + +const NmcMetaGenericInfo *const nmc_fields_con_active_details_vpn[] = { + NMC_META_GENERIC ("GROUP"), /* 0 */ + NMC_META_GENERIC ("TYPE"), /* 1 */ + NMC_META_GENERIC ("USERNAME"), /* 2 */ + NMC_META_GENERIC ("GATEWAY"), /* 3 */ + NMC_META_GENERIC ("BANNER"), /* 4 */ + NMC_META_GENERIC ("VPN-STATE"), /* 5 */ + NMC_META_GENERIC ("CFG"), /* 6 */ + NULL, }; -#define NMC_FIELDS_CON_ACTIVE_DETAILS_VPN_ALL "GROUP,TYPE,USERNAME,GATEWAY,BANNER,VPN-STATE,CFG" - -/* defined in common.c */ -extern NmcOutputField nmc_fields_ip4_config[]; -extern NmcOutputField nmc_fields_ip6_config[]; -extern NmcOutputField nmc_fields_dhcp4_config[]; -extern NmcOutputField nmc_fields_dhcp6_config[]; - -/* Available fields for 'connection show <con>' - active part */ -NmcOutputField nmc_fields_con_active_details_groups[] = { - {"GENERAL", N_("GENERAL"), 0, nmc_fields_con_active_details_general + 1}, /* 0 */ - {"IP4", N_("IP4"), 0, nmc_fields_ip4_config + 1 }, /* 1 */ - {"DHCP4", N_("DHCP4"), 0, nmc_fields_dhcp4_config + 1 }, /* 2 */ - {"IP6", N_("IP6"), 0, nmc_fields_ip6_config + 1 }, /* 3 */ - {"DHCP6", N_("DHCP6"), 0, nmc_fields_dhcp6_config + 1 }, /* 4 */ - {"VPN", N_("VPN"), 0, nmc_fields_con_active_details_vpn + 1 }, /* 5 */ - {NULL, NULL, 0, NULL} + +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", 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 */ + NMC_META_GENERIC_WITH_NESTED ("VPN", nmc_fields_con_active_details_vpn + 1), /* 5 */ + NULL, }; -#define NMC_FIELDS_CON_ACTIVE_DETAILS_ALL "GENERAL,IP4,DHCP4,IP6,DHCP6,VPN" /* Pseudo group names for 'connection show <con>' */ /* e.g.: nmcli -f profile con show my-eth0 */ @@ -278,9 +178,6 @@ NmcOutputField 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 */ @@ -293,8 +190,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) { @@ -412,7 +307,7 @@ usage_connection_add (void) " [parent <ifname>]\n" " [p-key <IPoIB P_Key>]\n\n" " bluetooth: [addr <bluetooth address>]\n" - " [bt-type panu|dun-gsm|dun-cdma]\n\n" + " [bt-type panu|nap|dun-gsm|dun-cdma]\n\n" " vlan: dev <parent device (connection UUID, ifname, or MAC)>\n" " id <VLAN ID>\n" " [flags <VLAN flags>]\n" @@ -606,7 +501,6 @@ usage_connection_export (void) "The data are directed to standard output or to a file if a name is given.\n\n")); } -/* quit main loop */ static void quit (void) { @@ -616,23 +510,16 @@ quit (void) nmc_terminal_erase_line (); } - g_main_loop_quit (loop); /* quit main loop */ + g_main_loop_quit (loop); } -static const char * +static char * construct_header_name (const char *base, const char *spec) { - static char header_name[128]; - if (spec == NULL) - return base; + return g_strdup (base); - g_strlcpy (header_name, base, sizeof (header_name)); - g_strlcat (header_name, " (", sizeof (header_name)); - g_strlcat (header_name, spec, sizeof (header_name)); - g_strlcat (header_name, ")", sizeof (header_name)); - - return header_name; + return g_strdup_printf ("%s (%s)", base, spec); } static const char * @@ -736,12 +623,12 @@ update_secrets_in_connection (NMRemoteConnection *remote, NMConnection *local) int i; GError *error = NULL; - for (i = 0; nmc_fields_settings_names[i].name; i++) { - secrets = nm_remote_connection_get_secrets (remote, nmc_fields_settings_names[i].name, NULL, NULL); + for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++) { + secrets = nm_remote_connection_get_secrets (remote, nm_meta_setting_infos[i].setting_name, NULL, NULL); if (secrets) { if (!nm_connection_update_secrets (local, NULL, secrets, &error) && error) { g_printerr (_("Error updating secrets for %s: %s\n"), - nmc_fields_settings_names[i].name, + nm_meta_setting_infos[i].setting_name, error->message); g_clear_error (&error); } @@ -751,7 +638,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; @@ -770,7 +657,8 @@ nmc_connection_profile_details (NMConnection *connection, NmCli *nmc, gboolean s else fields_str = nmc->required_fields; - print_settings_array = parse_output_fields (fields_str, nmc_fields_settings_names, TRUE, &prop_array, &error); + print_settings_array = parse_output_fields (fields_str, (const NMMetaAbstractInfo *const*) nm_meta_setting_infos_editor_p (), + TRUE, &prop_array, &error); if (error) { g_string_printf (nmc->return_text, _("Error: 'connection show': %s"), error->message); g_error_free (error); @@ -780,12 +668,24 @@ nmc_connection_profile_details (NMConnection *connection, NmCli *nmc, gboolean s g_assert (print_settings_array); /* Main header */ - nmc->print_fields.header_name = (char *) construct_header_name (base_hdr, nm_connection_get_id (connection)); - nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTINGS_NAMES_ALL, - nmc_fields_settings_names, FALSE, NULL, NULL); + { + gs_free char *header_name = NULL; + gs_free NmcOutputField *row = NULL; + gs_unref_array GArray *out_indices = NULL; + + header_name = construct_header_name (base_hdr, nm_connection_get_id (connection)); + out_indices = parse_output_fields (NMC_FIELDS_SETTINGS_NAMES_ALL, + (const NMMetaAbstractInfo *const*) nm_meta_setting_infos_editor_p (), + FALSE, NULL, NULL); - nmc_fields_settings_names[0].flags = NMC_OF_FLAG_MAIN_HEADER_ONLY; - print_required_fields (nmc, nmc_fields_settings_names); + row = g_new0 (NmcOutputField, _NM_META_SETTING_TYPE_NUM + 1); + for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++) + row[i].info = (const NMMetaAbstractInfo *) &nm_meta_setting_infos_editor[i]; + + print_required_fields (&nmc->nmc_config, NMC_OF_FLAG_MAIN_HEADER_ONLY, + out_indices, header_name, + 0, row); + } /* Loop through the required settings and print them. */ for (i = 0; i < print_settings_array->len; i++) { @@ -793,19 +693,15 @@ nmc_connection_profile_details (NMConnection *connection, NmCli *nmc, gboolean s int section_idx = g_array_index (print_settings_array, int, i); const char *prop_name = (const char *) g_ptr_array_index (prop_array, i); - if (nmc->print_output != NMC_PRINT_TERSE && !nmc->multiline_output && was_output) + if (nmc->nmc_config.print_output != NMC_PRINT_TERSE && !nmc->nmc_config.multiline_output && was_output) g_print ("\n"); /* Empty line */ was_output = FALSE; - /* Remove any previous data */ - nmc_empty_output_fields (nmc); - - setting = nm_connection_get_setting_by_name (connection, nmc_fields_settings_names[section_idx].name); + setting = nm_connection_get_setting_by_name (connection, nm_meta_setting_infos_editor[section_idx].general->setting_name); if (setting) { - setting_details (setting, nmc, prop_name, secrets); + setting_details (&nmc->nmc_config, setting, prop_name); was_output = TRUE; - continue; } } @@ -894,20 +790,45 @@ found: } void -nmc_active_connection_state_to_color (NMActiveConnectionState state, NmcTermColor *color) +nmc_active_connection_state_to_color (NMActiveConnectionState state, NMMetaTermColor *color) { - *color = NMC_TERM_COLOR_NORMAL; + *color = NM_META_TERM_COLOR_NORMAL; if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATING) - *color = NMC_TERM_COLOR_YELLOW; + *color = NM_META_TERM_COLOR_YELLOW; else if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) - *color = NMC_TERM_COLOR_GREEN; + *color = NM_META_TERM_COLOR_GREEN; else if (state > NM_ACTIVE_CONNECTION_STATE_ACTIVATED) - *color = NMC_TERM_COLOR_RED; + *color = NM_META_TERM_COLOR_RED; +} + +/* Essentially a version of nm_setting_connection_get_connection_type() that + * prefers an alias instead of the settings name when in pretty print mode. + * That is so that we print "wifi" instead of "802-11-wireless" in "nmcli c". */ +static const char * +connection_type_pretty (const char *type, NMCPrintOutput print_output) +{ + const NMMetaSettingInfoEditor *editor; + int i; + + if (print_output == NMC_PRINT_TERSE) + return type; + + for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++) { + editor = &nm_meta_setting_infos_editor[i]; + if (strcmp (type, editor->general->setting_name) == 0) { + if (editor->alias) + return editor->alias; + break; + } + } + + return type; } static void -fill_output_connection (NMConnection *connection, NmCli *nmc, gboolean active_only) +fill_output_connection (NMConnection *connection, NMClient *client, NMCPrintOutput print_output, + GPtrArray *output_data, gboolean active_only) { NMSettingConnection *s_con; guint64 timestamp; @@ -921,12 +842,12 @@ fill_output_connection (NMConnection *connection, NmCli *nmc, gboolean active_on const char *ac_state = NULL; NMActiveConnectionState ac_state_int = NM_ACTIVE_CONNECTION_STATE_UNKNOWN; char *ac_dev = NULL; - NmcTermColor color; + NMMetaTermColor color; s_con = nm_connection_get_setting_connection (connection); g_assert (s_con); - ac = get_ac_for_connection (nm_client_get_active_connections (nmc->client), connection); + ac = get_ac_for_connection (nm_client_get_active_connections (client), connection); if (active_only && !ac) return; @@ -947,9 +868,7 @@ fill_output_connection (NMConnection *connection, NmCli *nmc, gboolean active_on } prio_str = g_strdup_printf ("%u", nm_setting_connection_get_autoconnect_priority (s_con)); - arr = nmc_dup_fields_array (nmc_fields_con_show, - sizeof (nmc_fields_con_show), - 0); + arr = nmc_dup_fields_array ((const NMMetaAbstractInfo *const*) nmc_fields_con_show, 0); /* Show active connections in color */ nmc_active_connection_state_to_color (ac_state_int, &color); @@ -957,7 +876,7 @@ fill_output_connection (NMConnection *connection, NmCli *nmc, gboolean active_on set_val_strc (arr, 0, nm_setting_connection_get_id (s_con)); set_val_strc (arr, 1, nm_setting_connection_get_uuid (s_con)); - set_val_strc (arr, 2, nm_setting_connection_get_connection_type (s_con)); + set_val_strc (arr, 2, connection_type_pretty (nm_setting_connection_get_connection_type (s_con), print_output)); set_val_str (arr, 3, timestamp_str); set_val_str (arr, 4, timestamp ? timestamp_real_str : g_strdup (_("never"))); set_val_strc (arr, 5, nm_setting_connection_get_autoconnect (s_con) ? _("yes") : _("no")); @@ -970,11 +889,11 @@ fill_output_connection (NMConnection *connection, NmCli *nmc, gboolean active_on set_val_strc (arr, 12, ac_path); set_val_strc (arr, 13, nm_setting_connection_get_slave_type (s_con)); - g_ptr_array_add (nmc->output_data, arr); + g_ptr_array_add (output_data, arr); } static void -fill_output_connection_for_invisible (NMActiveConnection *ac, NmCli *nmc) +fill_output_connection_for_invisible (NMActiveConnection *ac, NMCPrintOutput print_output, GPtrArray *output_data) { NmcOutputField *arr; const char *ac_path = NULL; @@ -986,13 +905,11 @@ fill_output_connection_for_invisible (NMActiveConnection *ac, NmCli *nmc) ac_state = active_connection_state_to_string (nm_active_connection_get_state (ac)); ac_dev = get_ac_device_string (ac); - arr = nmc_dup_fields_array (nmc_fields_con_show, - sizeof (nmc_fields_con_show), - 0); + arr = nmc_dup_fields_array ((const NMMetaAbstractInfo *const*) nmc_fields_con_show, 0); set_val_str (arr, 0, name); set_val_strc (arr, 1, nm_active_connection_get_uuid (ac)); - set_val_strc (arr, 2, nm_active_connection_get_connection_type (ac)); + set_val_strc (arr, 2, connection_type_pretty (nm_active_connection_get_connection_type (ac), print_output)); set_val_strc (arr, 3, NULL); set_val_strc (arr, 4, NULL); set_val_strc (arr, 5, NULL); @@ -1005,14 +922,14 @@ fill_output_connection_for_invisible (NMActiveConnection *ac, NmCli *nmc) set_val_strc (arr, 12, ac_path); set_val_strc (arr, 13, NULL); - set_val_color_fmt_all (arr, NMC_TERM_FORMAT_DIM); + set_val_color_fmt_all (arr, NM_META_TERM_FORMAT_DIM); - g_ptr_array_add (nmc->output_data, arr); + g_ptr_array_add (output_data, arr); } static void fill_output_active_connection (NMActiveConnection *active, - NmCli *nmc, + GPtrArray *output_data, gboolean with_group, guint32 o_flags) { @@ -1024,8 +941,8 @@ fill_output_active_connection (NMActiveConnection *active, NMDevice *master; const char *con_path = NULL, *con_zone = NULL; int i; - NmcOutputField *tmpl, *arr; - size_t tmpl_len; + const NMMetaAbstractInfo *const*tmpl; + NmcOutputField *arr; int idx_start = with_group ? 0 : 1; con = nm_active_connection_get_connection (active); @@ -1054,17 +971,14 @@ fill_output_active_connection (NMActiveConnection *active, if (dev_str->len > 0) g_string_truncate (dev_str, dev_str->len - 1); /* Cut off last ',' */ - tmpl = nmc_fields_con_active_details_general; - tmpl_len = sizeof (nmc_fields_con_active_details_general); - if (!with_group) { + tmpl = (const NMMetaAbstractInfo *const*) nmc_fields_con_active_details_general; + if (!with_group) tmpl++; - tmpl_len -= sizeof (NmcOutputField); - } /* Fill field values */ - arr = nmc_dup_fields_array (tmpl, tmpl_len, o_flags); + arr = nmc_dup_fields_array (tmpl, o_flags); if (with_group) - set_val_strc (arr, 0, nmc_fields_con_active_details_groups[0].name); + set_val_strc (arr, 0, nmc_fields_con_active_details_groups[0]->name); set_val_strc (arr, 1-idx_start, nm_active_connection_get_id (active)); set_val_strc (arr, 2-idx_start, nm_active_connection_get_uuid (active)); set_val_str (arr, 3-idx_start, dev_str->str); @@ -1079,7 +993,7 @@ fill_output_active_connection (NMActiveConnection *active, set_val_strc (arr, 12-idx_start, master ? nm_object_get_path (NM_OBJECT (master)) : NULL); set_val_strc (arr, 13-idx_start, s_con ? nm_setting_connection_get_slave_type (s_con) : NULL); - g_ptr_array_add (nmc->output_data, arr); + g_ptr_array_add (output_data, arr); g_string_free (dev_str, FALSE); } @@ -1182,22 +1096,19 @@ nmc_active_connection_details (NMActiveConnection *acon, NmCli *nmc) GArray *print_groups; GPtrArray *group_fields = NULL; int i; - char *fields_str; - char *fields_all = NMC_FIELDS_CON_ACTIVE_DETAILS_ALL; - char *fields_common = NMC_FIELDS_CON_ACTIVE_DETAILS_ALL; - NmcOutputField *tmpl, *arr; + const char *fields_str = NULL; + const NMMetaAbstractInfo *const*tmpl; + NmcOutputField *arr; size_t tmpl_len; const char *base_hdr = _("Activate connection details"); gboolean was_output = FALSE; - 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 (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0) { + } else fields_str = nmc->required_fields; - print_groups = parse_output_fields (fields_str, nmc_fields_con_active_details_groups, TRUE, &group_fields, &error); + print_groups = parse_output_fields (fields_str, (const NMMetaAbstractInfo *const*) nmc_fields_con_active_details_groups, TRUE, &group_fields, &error); if (error) { g_string_printf (nmc->return_text, _("Error: 'connection show': %s"), error->message); g_error_free (error); @@ -1207,83 +1118,95 @@ nmc_active_connection_details (NMActiveConnection *acon, NmCli *nmc) g_assert (print_groups); /* Main header */ - nmc->print_fields.header_name = (char *) construct_header_name (base_hdr, nm_active_connection_get_uuid (acon)); - nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_CON_ACTIVE_DETAILS_ALL, - nmc_fields_con_active_details_groups, FALSE, NULL, NULL); + { + gs_free char *header_name = NULL; + gs_free NmcOutputField *row = NULL; + gs_unref_array GArray *out_indices = NULL; + + header_name = construct_header_name (base_hdr, nm_active_connection_get_uuid (acon)); + out_indices = parse_output_fields (NULL, + (const NMMetaAbstractInfo *const*) nmc_fields_con_active_details_groups, + FALSE, NULL, NULL); - nmc_fields_con_active_details_groups[0].flags = NMC_OF_FLAG_MAIN_HEADER_ONLY; - print_required_fields (nmc, nmc_fields_con_active_details_groups); + row = g_new0 (NmcOutputField, G_N_ELEMENTS (nmc_fields_con_active_details_groups) + 1); + for (i = 0; nmc_fields_con_active_details_groups[i]; i++) + row[i].info = (const NMMetaAbstractInfo *) nmc_fields_con_active_details_groups[i]; + + print_required_fields (&nmc->nmc_config, NMC_OF_FLAG_MAIN_HEADER_ONLY, + out_indices, header_name, + 0, row); + } /* Loop through the groups and print them. */ for (i = 0; i < print_groups->len; i++) { int group_idx = g_array_index (print_groups, int, i); char *group_fld = (char *) g_ptr_array_index (group_fields, i); - if (nmc->print_output != NMC_PRINT_TERSE && !nmc->multiline_output && was_output) + if (nmc->nmc_config.print_output != NMC_PRINT_TERSE && !nmc->nmc_config.multiline_output && was_output) g_print ("\n"); /* Empty line */ was_output = FALSE; - /* Remove any previous data */ - nmc_empty_output_fields (nmc); - /* GENERAL */ - if (strcasecmp (nmc_fields_con_active_details_groups[group_idx].name, nmc_fields_con_active_details_groups[0].name) == 0) { + if (strcasecmp (nmc_fields_con_active_details_groups[group_idx]->name, nmc_fields_con_active_details_groups[0]->name) == 0) { + NMC_OUTPUT_DATA_DEFINE_SCOPED (out); + /* Add field names */ - tmpl = nmc_fields_con_active_details_general; + tmpl = (const NMMetaAbstractInfo *const*) nmc_fields_con_active_details_general; tmpl_len = sizeof (nmc_fields_con_active_details_general); - nmc->print_fields.indices = parse_output_fields (group_fld ? group_fld : NMC_FIELDS_CON_ACTIVE_DETAILS_GENERAL_ALL, - tmpl, FALSE, NULL, NULL); - arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_FIELD_NAMES); - g_ptr_array_add (nmc->output_data, arr); + out_indices = parse_output_fields (group_fld, + tmpl, FALSE, NULL, NULL); + arr = nmc_dup_fields_array (tmpl, NMC_OF_FLAG_FIELD_NAMES); + g_ptr_array_add (out.output_data, arr); /* Fill in values */ - fill_output_active_connection (acon, nmc, TRUE, NMC_OF_FLAG_SECTION_PREFIX); + fill_output_active_connection (acon, out.output_data, TRUE, NMC_OF_FLAG_SECTION_PREFIX); - print_data (nmc); /* Print all data */ + print_data_prepare_width (out.output_data); + print_data (&nmc->nmc_config, out_indices, NULL, 0, &out); was_output = TRUE; } /* IP4 */ - if (strcasecmp (nmc_fields_con_active_details_groups[group_idx].name, nmc_fields_con_active_details_groups[1].name) == 0) { + if (strcasecmp (nmc_fields_con_active_details_groups[group_idx]->name, nmc_fields_con_active_details_groups[1]->name) == 0) { gboolean b1 = FALSE; NMIPConfig *cfg4 = nm_active_connection_get_ip4_config (acon); - b1 = print_ip4_config (cfg4, nmc, "IP4", group_fld); + b1 = print_ip4_config (cfg4, &nmc->nmc_config, group_fld); was_output = was_output || b1; } /* DHCP4 */ - if (strcasecmp (nmc_fields_con_active_details_groups[group_idx].name, nmc_fields_con_active_details_groups[2].name) == 0) { + if (strcasecmp (nmc_fields_con_active_details_groups[group_idx]->name, nmc_fields_con_active_details_groups[2]->name) == 0) { gboolean b1 = FALSE; NMDhcpConfig *dhcp4 = nm_active_connection_get_dhcp4_config (acon); - b1 = print_dhcp4_config (dhcp4, nmc, "DHCP4", group_fld); + b1 = print_dhcp4_config (dhcp4, &nmc->nmc_config, "DHCP4", group_fld); was_output = was_output || b1; } /* IP6 */ - if (strcasecmp (nmc_fields_con_active_details_groups[group_idx].name, nmc_fields_con_active_details_groups[3].name) == 0) { + if (strcasecmp (nmc_fields_con_active_details_groups[group_idx]->name, nmc_fields_con_active_details_groups[3]->name) == 0) { gboolean b1 = FALSE; NMIPConfig *cfg6 = nm_active_connection_get_ip6_config (acon); - b1 = print_ip6_config (cfg6, nmc, "IP6", group_fld); + b1 = print_ip6_config (cfg6, &nmc->nmc_config, "IP6", group_fld); was_output = was_output || b1; } /* DHCP6 */ - if (strcasecmp (nmc_fields_con_active_details_groups[group_idx].name, nmc_fields_con_active_details_groups[4].name) == 0) { + if (strcasecmp (nmc_fields_con_active_details_groups[group_idx]->name, nmc_fields_con_active_details_groups[4]->name) == 0) { gboolean b1 = FALSE; NMDhcpConfig *dhcp6 = nm_active_connection_get_dhcp6_config (acon); - b1 = print_dhcp6_config (dhcp6, nmc, "DHCP6", group_fld); + b1 = print_dhcp6_config (dhcp6, &nmc->nmc_config, "DHCP6", group_fld); was_output = was_output || b1; } /* VPN */ if (NM_IS_VPN_CONNECTION (acon) && - strcasecmp (nmc_fields_con_active_details_groups[group_idx].name, nmc_fields_con_active_details_groups[5].name) == 0) { + strcasecmp (nmc_fields_con_active_details_groups[group_idx]->name, nmc_fields_con_active_details_groups[5]->name) == 0) { NMConnection *con; NMSettingConnection *s_con; NMSettingVpn *s_vpn; @@ -1293,18 +1216,18 @@ nmc_active_connection_details (NMActiveConnection *acon, NmCli *nmc) const char *username = NULL; char **vpn_data_array = NULL; guint32 items_num; + NMC_OUTPUT_DATA_DEFINE_SCOPED (out); con = NM_CONNECTION (nm_active_connection_get_connection (acon)); s_con = nm_connection_get_setting_connection (con); g_assert (s_con != NULL); - tmpl = nmc_fields_con_active_details_vpn; - tmpl_len = sizeof (nmc_fields_con_active_details_vpn); - nmc->print_fields.indices = parse_output_fields (group_fld ? group_fld : NMC_FIELDS_CON_ACTIVE_DETAILS_VPN_ALL, - tmpl, FALSE, NULL, NULL); - arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_FIELD_NAMES); - g_ptr_array_add (nmc->output_data, arr); + tmpl = (const NMMetaAbstractInfo *const*) nmc_fields_con_active_details_vpn; + out_indices = parse_output_fields (group_fld, + tmpl, FALSE, NULL, NULL); + arr = nmc_dup_fields_array (tmpl, NMC_OF_FLAG_FIELD_NAMES); + g_ptr_array_add (out.output_data, arr); s_vpn = nm_connection_get_setting_vpn (con); if (s_vpn) { @@ -1329,17 +1252,18 @@ nmc_active_connection_details (NMActiveConnection *acon, NmCli *nmc) vpn_state_str = g_strdup_printf ("%d - %s", vpn_state, vpn_connection_state_to_string (vpn_state)); /* Add values */ - arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX); - set_val_strc (arr, 0, nmc_fields_con_active_details_groups[5].name); + arr = nmc_dup_fields_array (tmpl, NMC_OF_FLAG_SECTION_PREFIX); + set_val_strc (arr, 0, nmc_fields_con_active_details_groups[5]->name); set_val_str (arr, 1, type_str); set_val_strc (arr, 2, username ? username : get_vpn_data_item (con, VPN_DATA_ITEM_USERNAME)); set_val_strc (arr, 3, get_vpn_data_item (con, VPN_DATA_ITEM_GATEWAY)); set_val_str (arr, 4, banner_str); set_val_str (arr, 5, vpn_state_str); set_val_arr (arr, 6, vpn_data_array); - g_ptr_array_add (nmc->output_data, arr); + g_ptr_array_add (out.output_data, arr); - print_data (nmc); /* Print all data */ + print_data_prepare_width (out.output_data); + print_data (&nmc->nmc_config, out_indices, NULL, 0, &out); was_output = TRUE; } } @@ -1389,9 +1313,9 @@ split_required_fields_for_con_show (const char *input, found = FALSE; - for (i = 0; nmc_fields_settings_names[i].name; i++) { + for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++) { if ( is_all || is_common - || !strcasecmp (*iter, nmc_fields_settings_names[i].name)) { + || !strcasecmp (*iter, nm_meta_setting_infos[i].setting_name)) { if (dot) *dot = '.'; g_string_append (str1, *iter); @@ -1402,9 +1326,9 @@ split_required_fields_for_con_show (const char *input, } if (found) continue; - for (i = 0; nmc_fields_con_active_details_groups[i].name; i++) { + for (i = 0; nmc_fields_con_active_details_groups[i]; i++) { if ( is_all || is_common - || !strcasecmp (*iter, nmc_fields_con_active_details_groups[i].name)) { + || !strcasecmp (*iter, nmc_fields_con_active_details_groups[i]->name)) { if (dot) *dot = '.'; g_string_append (str2, *iter); @@ -1421,8 +1345,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 (nmc_fields_settings_names, -1); - char *allowed2 = nmc_get_allowed_fields (nmc_fields_con_active_details_groups, -1); + char *allowed1 = nm_meta_abstract_infos_get_names_str ((const NMMetaAbstractInfo *const*) nm_meta_setting_infos_editor_p (), NULL); + char *allowed2 = nm_meta_abstract_infos_get_names_str ((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); @@ -1775,49 +1699,49 @@ do_connections_show (NmCli *nmc, int argc, char **argv) if (argc == 0) { const GPtrArray *connections; - char *fields_str; - char *fields_all = NMC_FIELDS_CON_SHOW_ALL; + const char *fields_str = NULL; char *fields_common = NMC_FIELDS_CON_SHOW_COMMON; - NmcOutputField *tmpl, *arr; - size_t tmpl_len; + const NMMetaAbstractInfo *const*tmpl; + NmcOutputField *arr; + NMC_OUTPUT_DATA_DEFINE_SCOPED (out); if (nmc->complete) goto finish; 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 + else if (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0) { + } else fields_str = nmc->required_fields; - tmpl = nmc_fields_con_show; - tmpl_len = sizeof (nmc_fields_con_show); - nmc->print_fields.indices = parse_output_fields (fields_str, tmpl, FALSE, NULL, &err); + tmpl = (const NMMetaAbstractInfo *const*) nmc_fields_con_show; + out_indices = parse_output_fields (fields_str, tmpl, FALSE, NULL, &err); if (err) goto finish; /* Add headers */ - nmc->print_fields.header_name = active_only ? _("NetworkManager active profiles") : - _("NetworkManager connection profiles"); - arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_MAIN_HEADER_ADD | NMC_OF_FLAG_FIELD_NAMES); - g_ptr_array_add (nmc->output_data, arr); + 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); /* There might be active connections not present in connection list * (e.g. private connections of a different user). Show them as well. */ invisibles = get_invisible_active_connections (nmc); for (i = 0; i < invisibles->len; i++) - fill_output_connection_for_invisible (invisibles->pdata[i], nmc); + fill_output_connection_for_invisible (invisibles->pdata[i], nmc->nmc_config.print_output, out.output_data); g_ptr_array_free (invisibles, TRUE); /* Sort the connections and fill the output data */ connections = nm_client_get_connections (nmc->client); sorted_cons = sort_connections (connections, nmc, order); for (i = 0; i < sorted_cons->len; i++) - fill_output_connection (sorted_cons->pdata[i], nmc, active_only); + fill_output_connection (sorted_cons->pdata[i], nmc->client, nmc->nmc_config.print_output, out.output_data, active_only); g_ptr_array_free (sorted_cons, TRUE); - print_data (nmc); /* Print all data */ + print_data_prepare_width (out.output_data); + print_data (&nmc->nmc_config, out_indices, + active_only ? _("NetworkManager active profiles") + : _("NetworkManager connection profiles"), + 0, &out); } else { gboolean new_line = FALSE; gboolean without_fields = (nmc->required_fields == NULL); @@ -1826,7 +1750,7 @@ do_connections_show (NmCli *nmc, int argc, char **argv) /* multiline mode is default for 'connection show <ID>' */ if (!nmc->mode_specified) - nmc->multiline_output = TRUE; + nmc->nmc_config_mutable.multiline_output = TRUE; /* Split required fields into the settings and active ones. */ if (!split_required_fields_for_con_show (nmc->required_fields, &profile_flds, &active_flds, &err)) @@ -1836,7 +1760,7 @@ do_connections_show (NmCli *nmc, int argc, char **argv) /* Before printing the connections check if we have a "--show-secret" * option after the connection ids */ - if (!nmc->show_secrets && !nmc->complete) { + if (!nmc->nmc_config.show_secrets && !nmc->complete) { int argc_cp = argc; char **argv_cp = argv; @@ -1886,7 +1810,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; @@ -1920,9 +1844,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; @@ -1940,7 +1864,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. @@ -2132,111 +2056,45 @@ typedef struct { static void activate_connection_info_finish (ActivateConnectionInfo *info); -static const char * -active_connection_state_reason_to_string (NMActiveConnectionStateReason reason) -{ - switch (reason) { - case NM_ACTIVE_CONNECTION_STATE_REASON_UNKNOWN: - return _("Unknown reason"); - case NM_ACTIVE_CONNECTION_STATE_REASON_NONE: - return _("The connection was disconnected"); - case NM_ACTIVE_CONNECTION_STATE_REASON_USER_DISCONNECTED: - return _("Disconnected by user"); - case NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED: - return _("The base network connection was interrupted"); - case NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_STOPPED: - return _("The VPN service stopped unexpectedly"); - case NM_ACTIVE_CONNECTION_STATE_REASON_IP_CONFIG_INVALID: - return _("The VPN service returned invalid configuration"); - case NM_ACTIVE_CONNECTION_STATE_REASON_CONNECT_TIMEOUT: - return _("The connection attempt timed out"); - case NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_START_TIMEOUT: - return _("The VPN service did not start in time"); - case NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_START_FAILED: - return _("The VPN service failed to start"); - case NM_ACTIVE_CONNECTION_STATE_REASON_NO_SECRETS: - return _("No valid secrets"); - case NM_ACTIVE_CONNECTION_STATE_REASON_LOGIN_FAILED: - return _("Invalid secrets"); - case NM_ACTIVE_CONNECTION_STATE_REASON_CONNECTION_REMOVED: - return _("The connection was removed"); - case NM_ACTIVE_CONNECTION_STATE_REASON_DEPENDENCY_FAILED: - return _("Master connection failed"); - case NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_REALIZE_FAILED: - return _("Could not create a software link"); - case NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_REMOVED: - return _("The device disappeared"); - } - - g_return_val_if_reached (_("Invalid reason")); -} - static void check_activated (ActivateConnectionInfo *info) { - NmCli *nmc = info->nmc; - NMDevice *device = info->device; - NMActiveConnection *active = info->active; NMActiveConnectionState ac_state; - NMActiveConnectionStateReason ac_reason; - NMDeviceState dev_state; - NMDeviceStateReason dev_reason; - - ac_state = nm_active_connection_get_state (active); - ac_reason = nm_active_connection_get_state_reason (active); - - if (device) { - dev_state = nm_device_get_state (device); - dev_reason = nm_device_get_state_reason (device); - } + NmCli *nmc = info->nmc; + const char *reason = NULL; - if (ac_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { - if (nmc->print_output == NMC_PRINT_PRETTY) + ac_state = nmc_activation_get_effective_state (info->active, info->device, &reason); + switch (ac_state) { + case NM_ACTIVE_CONNECTION_STATE_ACTIVATED: + if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY) nmc_terminal_erase_line (); - g_print (_("Connection successfully activated (D-Bus active path: %s)\n"), - nm_object_get_path (NM_OBJECT (active))); - activate_connection_info_finish (info); - } else if (ac_state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED) { - if (device && ac_reason == NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED) { - if (dev_state == NM_DEVICE_STATE_FAILED || dev_state == NM_DEVICE_STATE_DISCONNECTED) { - g_string_printf (nmc->return_text, _("Error: Connection activation failed: %s"), - nmc_device_reason_to_string (dev_reason)); - nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION; - activate_connection_info_finish (info); - } else { - /* Just wait for the device to go failed. We'll get a better error message. */ - return; - } + if (reason) { + g_print (_("Connection successfully activated (%s) (D-Bus active path: %s)\n"), + reason, + nm_object_get_path (NM_OBJECT (info->active))); } else { - g_string_printf (nmc->return_text, _("Error: Connection activation failed: %s"), - active_connection_state_reason_to_string (ac_reason)); - nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION; - activate_connection_info_finish (info); + g_print (_("Connection successfully activated (D-Bus active path: %s)\n"), + nm_object_get_path (NM_OBJECT (info->active))); } - } else if (ac_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATING) { - /* activating master connection does not automatically activate any slaves, so their - * active connection state will not progress beyond ACTIVATING state. - * Monitor the device instead. */ - + activate_connection_info_finish (info); + break; + case NM_ACTIVE_CONNECTION_STATE_DEACTIVATED: + nm_assert (reason); + g_string_printf (nmc->return_text, _("Error: Connection activation failed: %s"), + reason); + nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION; + activate_connection_info_finish (info); + break; + case NM_ACTIVE_CONNECTION_STATE_ACTIVATING: if (nmc->secret_agent) { - NMRemoteConnection *connection = nm_active_connection_get_connection (active); + NMRemoteConnection *connection = nm_active_connection_get_connection (info->active); nm_secret_agent_simple_enable (NM_SECRET_AGENT_SIMPLE (nmc->secret_agent), nm_connection_get_path (NM_CONNECTION (connection))); } - - if ( device - && ( NM_IS_DEVICE_BOND (device) - || NM_IS_DEVICE_TEAM (device) - || NM_IS_DEVICE_BRIDGE (device)) - && dev_state >= NM_DEVICE_STATE_IP_CONFIG - && dev_state <= NM_DEVICE_STATE_ACTIVATED) { - if (nmc->print_output == NMC_PRINT_PRETTY) - nmc_terminal_erase_line (); - g_print (_("Connection successfully activated (master waiting for slaves) (D-Bus active path: %s)\n"), - nm_object_get_path (NM_OBJECT (active))); - activate_connection_info_finish (info); - } + break; + default: + break; } } @@ -2350,7 +2208,7 @@ activate_connection_cb (GObject *client, GAsyncResult *result, gpointer user_dat activate_connection_info_finish (info); } else { state = nm_active_connection_get_state (active); - if (!device) { + if (!device && !nm_active_connection_get_vpn (active)) { /* device could be NULL for virtual devices. Fill it here. */ ac_devs = nm_active_connection_get_devices (active); device = ac_devs->len > 0 ? g_ptr_array_index (ac_devs, 0) : NULL; @@ -2361,7 +2219,7 @@ activate_connection_cb (GObject *client, GAsyncResult *result, gpointer user_dat if (nmc->nowait_flag || state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { /* User doesn't want to wait or already activated */ if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { - if (nmc->print_output == NMC_PRINT_PRETTY) + if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY) nmc_terminal_erase_line (); g_print (_("Connection successfully activated (D-Bus active path: %s)\n"), nm_object_get_path (NM_OBJECT (active))); @@ -2380,7 +2238,7 @@ activate_connection_cb (GObject *client, GAsyncResult *result, gpointer user_dat check_activated (info); /* Start progress indication showing VPN states */ - if (nmc->print_output == NMC_PRINT_PRETTY) { + if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY) { if (progress_id) g_source_remove (progress_id); progress_id = g_timeout_add (120, progress_active_connection_cb, active); @@ -2416,7 +2274,7 @@ parse_passwords (const char *passwd_file, GError **error) char *pwd_spec, *pwd, *prop; const char *setting; - pwds_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + pwds_hash = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_free); if (!passwd_file) return pwds_hash; @@ -2539,10 +2397,6 @@ nmc_activate_connection (NmCli *nmc, NM_SECRET_AGENT_SIMPLE_REQUEST_SECRETS, G_CALLBACK (nmc_secrets_requested), nmc); - if (connection) { - nm_secret_agent_simple_enable (NM_SECRET_AGENT_SIMPLE (nmc->secret_agent), - nm_object_get_path (NM_OBJECT (connection))); - } } info = g_malloc0 (sizeof (ActivateConnectionInfo)); @@ -2672,7 +2526,7 @@ do_connection_up (NmCli *nmc, int argc, char **argv) } /* Start progress indication */ - if (nmc->print_output == NMC_PRINT_PRETTY) + if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY) progress_id = g_timeout_add (120, progress_cb, _("preparing")); return nmc->return_value; @@ -2707,7 +2561,7 @@ down_active_connection_state_cb (NMActiveConnection *active, if (nm_active_connection_get_state (active) < NM_ACTIVE_CONNECTION_STATE_DEACTIVATED) return; - if (info->nmc->print_output == NMC_PRINT_PRETTY) + if (info->nmc->nmc_config.print_output == NMC_PRINT_PRETTY) nmc_terminal_erase_line (); g_print (_("Connection '%s' successfully deactivated (D-Bus active path: %s)\n"), nm_active_connection_get_id (active), nm_object_get_path (NM_OBJECT (active))); @@ -2896,254 +2750,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 } -}; - -/* Available connection types */ -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; } @@ -3154,44 +2783,70 @@ 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 (!setting_info->valid_parts) + continue; + + 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); + } + + if (str->len) + g_string_append (str, ", "); + g_string_append (str, "bond-slave, bridge-slave, team-slave"); + + 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; } @@ -3210,14 +2865,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 NmcOutputField *field_iter; + const NMMetaSettingValidPartItem *const*iter = array; const char *prop_name = NULL; GString *str; int i, j; @@ -3228,69 +2882,60 @@ 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 */ - j = 0; - while (!nm_streq0 (iter->name, nmc_fields_settings_names[j].name)) { - g_assert (nmc_fields_settings_names[j].name); - j++; - } - field_iter = nmc_fields_settings_names[j].group; - - j = 0; - while (field_iter[j].name) { + for (j = 0; j < setting_info->properties_num; j++) { gchar *new; - const char *arg_name = field_iter[j].name; + const char *arg_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, - arg_name); + 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); new = g_strdup_printf ("%s.%s\n", - prop_name, - arg_name); + prop_name, + arg_name); g_string_append (str, new); g_free (new); - j++; } - iter++; } } return g_string_free (str, FALSE); @@ -3306,9 +2951,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; @@ -3320,11 +2965,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); @@ -3336,10 +2982,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; @@ -3348,12 +2994,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++; } } @@ -3362,44 +3009,98 @@ check_valid_name (const char *val, const NameItem *array, const NameItem *array_ return NULL; } +static const char * +check_valid_name_toplevel (const char *val, const char **slave_type, GError **error) +{ + gs_unref_ptrarray GPtrArray *tmp_arr = NULL; + const char *str; + GError *tmp_err = NULL; + int i; + const NMMetaSettingInfoEditor *setting_info; + + NM_SET_OUT (slave_type, NULL); + + /* 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, "bond-slave"); + g_ptr_array_add (tmp_arr, "bridge-slave"); + g_ptr_array_add (tmp_arr, "team-slave"); + 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; + } + + if (nm_streq (str, "bond-slave")) { + NM_SET_OUT (slave_type, NM_SETTING_BOND_SETTING_NAME); + return NM_SETTING_WIRED_SETTING_NAME; + } else if (nm_streq (str, "bridge-slave")) { + NM_SET_OUT (slave_type, NM_SETTING_BRIDGE_SETTING_NAME); + return NM_SETTING_WIRED_SETTING_NAME; + } else if (nm_streq (str, "team-slave")) { + NM_SET_OUT (slave_type, NM_SETTING_TEAM_SETTING_NAME); + return NM_SETTING_WIRED_SETTING_NAME; + } + + 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 *)) @@ -3509,8 +3210,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) { @@ -3520,14 +3219,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; @@ -3600,9 +3299,94 @@ 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->nested == &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) +{ + const NMMetaPropertyInfo *info = (const NMMetaPropertyInfo *) abstract_info; + + NM_SET_OUT (out_option, info->property_alias); + 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. @@ -3611,17 +3395,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; + + 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 NMMetaNestedPropertyInfo *bi = &nm_meta_property_typ_data_bond.nested[i]; - 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; + if ( bi->base.inf_flags & NM_META_PROPERTY_INF_FLAG_DONT_ASK + && bi->base.property_alias + && g_strv_contains (opts, bi->base.property_alias)) + _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); } /* @@ -3632,12 +3433,49 @@ 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; + + 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 = setting_info->properties; + if (!property_infos) + return; + } - 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; + 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 NMMetaNestedPropertyInfo *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); + } } } @@ -3649,11 +3487,31 @@ disable_options (const gchar *setting_name, const gchar *property) static void reset_options (void) { - OptionInfo *candidate; + NMMetaSettingType s; + + for (s = 0; s < _NM_META_SETTING_TYPE_NUM; s++) { + const NMMetaPropertyInfo *const*property_infos; + guint p; + + property_infos = nm_meta_setting_infos_editor[s].properties; + if (!property_infos) + continue; + 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 NMMetaNestedPropertyInfo *bi = &nm_meta_property_typ_data_bond.nested[i]; - for (candidate = option_info; candidate->setting_name; candidate++) { - candidate->flags &= ~OPTION_DISABLED; - candidate->flags &= ~OPTION_ENABLED; + _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); + } + } } } @@ -3666,17 +3524,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); } @@ -3735,17 +3588,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; } @@ -3757,10 +3618,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); @@ -3770,23 +3630,14 @@ 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); - if (!con_type) - con_type = NM_SETTING_GENERIC_SETTING_NAME; *type_settings = get_valid_settings_array (con_type); if (!*type_settings) { g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, @@ -3802,67 +3653,34 @@ 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); } static char * gen_func_bt_type (const char *text, int state) { - const char *words[] = { "panu", "dun-gsm", "dun-cdma", NULL }; + const char *words[] = { "panu", "nap", "dun-gsm", "dun-cdma", NULL }; return nmc_rl_gen_func_basic (text, state, words); } @@ -3886,144 +3704,28 @@ 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 }; + const char *slave_type = NULL; - value = check_valid_name (value, nmc_valid_connection_types, NULL, &local); + value = check_valid_name_toplevel (value, &slave_type, &local); if (!value) { g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, - _("Error: bad connection type: %s."), local->message); + _("Error: bad connection type: %s"), local->message); g_clear_error (&local); return FALSE; } - if (g_strcmp0 (value, "bond-slave") == 0) { - value = NM_SETTING_WIRED_SETTING_NAME; - if (!set_property (con, NM_SETTING_CONNECTION_SETTING_NAME, - NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_BOND_SETTING_NAME, - '\0', error)) { - return FALSE; - } - enable_options (NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_MASTER, master); - } else if (g_strcmp0 (value, "bridge-slave") == 0) { - value = NM_SETTING_WIRED_SETTING_NAME; - if (!set_property (con, NM_SETTING_CONNECTION_SETTING_NAME, - NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_BRIDGE_SETTING_NAME, - '\0', error)) { - return FALSE; - } - enable_options (NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_MASTER, master); - } else if (g_strcmp0 (value, "team-slave") == 0) { - value = NM_SETTING_WIRED_SETTING_NAME; + if (slave_type) { if (!set_property (con, NM_SETTING_CONNECTION_SETTING_NAME, - NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_TEAM_SETTING_NAME, + NM_SETTING_CONNECTION_SLAVE_TYPE, slave_type, '\0', error)) { return FALSE; } @@ -4039,7 +3741,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)) @@ -4052,7 +3754,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; @@ -4068,11 +3770,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; @@ -4097,11 +3799,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; @@ -4150,7 +3852,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; @@ -4164,17 +3866,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; } @@ -4182,7 +3884,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; @@ -4193,39 +3895,29 @@ 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; setting = nm_setting_cdma_new (); nm_connection_add_setting (con, setting); - } else if (!strcmp (value, NM_SETTING_BLUETOOTH_TYPE_PANU)) { + } else if (!strcmp (value, NM_SETTING_BLUETOOTH_TYPE_PANU) || !strcmp (value, NM_SETTING_BLUETOOTH_TYPE_NAP)) { /* no op */ } else { g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, - _("Error: 'bt-type': '%s' not valid; use [%s, %s (%s), %s]."), - value, NM_SETTING_BLUETOOTH_TYPE_PANU, NM_SETTING_BLUETOOTH_TYPE_DUN, - NM_SETTING_BLUETOOTH_TYPE_DUN"-gsm", NM_SETTING_BLUETOOTH_TYPE_DUN"-cdma"); + _("Error: 'bt-type': '%s' not valid; use [%s, %s, %s (%s), %s]."), + value, NM_SETTING_BLUETOOTH_TYPE_PANU, NM_SETTING_BLUETOOTH_TYPE_NAP, + NM_SETTING_BLUETOOTH_TYPE_DUN, NM_SETTING_BLUETOOTH_TYPE_DUN"-gsm", + NM_SETTING_BLUETOOTH_TYPE_DUN"-cdma"); return FALSE; } - return set_property (con, option->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); + return set_property (con, option->setting_info->general->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; @@ -4240,12 +3932,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; @@ -4260,187 +3952,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); -} - - -/*----------------------------------------------------------------------------*/ - -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 }, - - { 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 }, -}; + 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; + + _meta_abstract_get (abstract_info, &setting_info, NULL, &property_name, &option, 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) @@ -4449,14 +4051,39 @@ 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)) - continue; - if (!candidate->option) + 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 (!g_str_has_prefix (candidate->option, prefix)) + + property_infos = nm_meta_setting_infos_editor[s].properties; + if (!property_infos) continue; - g_print ("%s\n", candidate->option); + 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 NMMetaNestedPropertyInfo *bi = &nm_meta_property_typ_data_bond.nested[i]; + + if ( !bi->base.property_alias + || !g_str_has_prefix (bi->base.property_alias, prefix)) + continue; + g_print ("%s\n", bi->base.property_alias); + } + } 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); + } + } } } @@ -4474,62 +4101,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) -{ - 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 +complete_property (const gchar *setting_name, const gchar *property, const gchar *prefix, NMConnection *connection) +{ + 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) @@ -4567,10 +4186,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)) @@ -4617,25 +4236,66 @@ 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)) + + property_infos = nm_meta_setting_infos_editor[s].properties; + if (!property_infos) 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; + 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 NMMetaNestedPropertyInfo *bi = &nm_meta_property_typ_data_bond.nested[i]; + + if (!nm_streq0 (bi->base.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 *) 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) { @@ -4644,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 <setting>.<property> '%s'."), option); + _("Error: invalid <setting>.<property> '%s'."), option); return FALSE; } @@ -4657,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; @@ -4682,6 +4342,8 @@ add_connection_cb (GObject *client, NmCli *nmc = info->nmc; NMRemoteConnection *connection; GError *error = NULL; + const GPtrArray *connections; + guint i, found; connection = nm_client_add_connection_finish (NM_CLIENT (client), result, &error); if (error) { @@ -4691,6 +4353,28 @@ add_connection_cb (GObject *client, g_error_free (error); nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION; } else { + connections = nm_client_get_connections (nmc->client); + if (connections) { + found = 0; + for (i = 0; i < connections->len; i++) { + NMConnection *candidate = NM_CONNECTION (connections->pdata[i]); + + if ((NMConnection *) connection == candidate) + continue; + if (nm_streq0 (nm_connection_get_id (candidate), info->con_name)) + found++; + } + if (found > 0) { + g_printerr (g_dngettext (GETTEXT_PACKAGE, + "Warning: There is another connection with the name '%1$s'. Reference the connection by its uuid '%2$s'\n", + "Warning: There are %3$u other connections with the name '%1$s'. Reference the connection by its uuid '%2$s'\n", + found), + info->con_name, + nm_connection_get_uuid (NM_CONNECTION (connection)), + found); + } + } + g_print (_("Connection '%s' (%s) successfully added.\n"), nm_connection_get_id (NM_CONNECTION (connection)), nm_connection_get_uuid (NM_CONNECTION (connection))); @@ -4741,6 +4425,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")); @@ -4755,38 +4440,48 @@ 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_meta_setting_infos_editor[s].properties; + if (!property_infos) + continue; + 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 NMMetaNestedPropertyInfo *bi = &nm_meta_property_typ_data_bond.nested[i]; + + if ( bi->base.prompt + && g_str_has_prefix (rl_prompt, bi->base.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; @@ -4798,20 +4493,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 <Enter> when you're done.\n")); @@ -4820,7 +4520,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; @@ -4830,17 +4530,78 @@ again: goto again; } +static NMMetaSettingType +connection_get_base_meta_setting_type (NMConnection *connection) +{ + const char *connection_type; + NMSetting *base_setting; + const NMMetaSettingInfoEditor *editor; + + connection_type = nm_connection_get_connection_type (connection); + nm_assert (connection_type); + base_setting = nm_connection_get_setting_by_name (connection, connection_type); + nm_assert (base_setting); + editor = nm_meta_setting_info_editor_find_by_setting (base_setting); + nm_assert (editor); + + return editor - nm_meta_setting_infos_editor; +} + +static void +questionnaire_mandatory_ask_setting (NmCli *nmc, NMConnection *connection, NMMetaSettingType type) +{ + const NMMetaSettingInfoEditor *editor; + const NMMetaPropertyInfo *property_info; + guint p; + + editor = &nm_meta_setting_infos_editor[type]; + if (!editor->properties) + return; + + for (p = 0; editor->properties[p]; p++) { + property_info = editor->properties[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 NMMetaNestedPropertyInfo *bi = &nm_meta_property_typ_data_bond.nested[i]; + + if (!option_relevant (connection, (const NMMetaAbstractInfo *) bi)) + continue; + if ( (bi->base.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); + } + } +} + static void questionnaire_mandatory (NmCli *nmc, NMConnection *connection) { - OptionInfo *candidate; + NMMetaSettingType s, base; - /* 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); + /* First ask connection properties */ + questionnaire_mandatory_ask_setting (nmc, connection, NM_META_SETTING_TYPE_CONNECTION); + + /* Ask properties of the base setting */ + base = connection_get_base_meta_setting_type (connection); + questionnaire_mandatory_ask_setting (nmc, connection, base); + + /* Remaining settings */ + for (s = 0; s < _NM_META_SETTING_TYPE_NUM; s++) { + if (!NM_IN_SET (s, NM_META_SETTING_TYPE_CONNECTION, base)) + questionnaire_mandatory_ask_setting (nmc, connection, s); } } @@ -4858,104 +4619,93 @@ 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 base; + gs_unref_ptrarray GPtrArray *infos = NULL; + guint i, j; + gboolean already_confirmed = FALSE; + NMMetaSettingType s_asking = NM_META_SETTING_TYPE_UNKNOWN; + NMMetaSettingType settings[_NM_META_SETTING_TYPE_NUM]; + + base = connection_get_base_meta_setting_type (connection); + + i = 0; + settings[i++] = NM_META_SETTING_TYPE_CONNECTION; + settings[i++] = base; + for (j = 0; j < _NM_META_SETTING_TYPE_NUM; j++) { + if (!NM_IN_SET (j, NM_META_SETTING_TYPE_CONNECTION, base)) + settings[i++] = j; + } - /* 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)) +again: + for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++) { + const NMMetaPropertyInfo *const*property_infos; + guint p; + + if ( s_asking != NM_META_SETTING_TYPE_UNKNOWN + && settings[i] != s_asking) continue; - if (!setting_name) - setting_name = candidate->setting_name; - else if (strcmp (setting_name, candidate->setting_name)) + + property_infos = nm_meta_setting_infos_editor[settings[i]].properties; + if (!property_infos) + continue; + for (p = 0; property_infos[p]; p++) { + const NMMetaPropertyInfo *property_info = property_infos[p]; + + if (_meta_property_needs_bond_hack (property_info)) { + for (j = 0; j < nm_meta_property_typ_data_bond.nested_len; j++) { + const NMMetaNestedPropertyInfo *bi = &nm_meta_property_typ_data_bond.nested[j]; + + 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 = settings[i]; break; - count++; + } } - if (!setting_name) - return FALSE; - /* 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 (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; } } - /* Make sure we won't ask again. */ - disable_options (setting_name, NULL); + 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; } @@ -4967,8 +4717,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); @@ -5052,8 +4802,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); @@ -5075,13 +4826,41 @@ 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)) + for (s = 0; s < _NM_META_SETTING_TYPE_NUM; s++) { + const NMMetaPropertyInfo *const*property_infos; + guint p; + + property_infos = nm_meta_setting_infos_editor[s].properties; + if (!property_infos) 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 (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 NMMetaNestedPropertyInfo *bi = &nm_meta_property_typ_data_bond.nested[i]; + + if (!option_relevant (connection, (const NMMetaAbstractInfo *) bi)) + continue; + if (bi->base.inf_flags & NM_META_PROPERTY_INF_FLAG_REQD) { + g_string_printf (nmc->return_text, _("Error: '%s' argument is required."), bi->base.property_alias); + 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; + } + } } } @@ -5106,7 +4885,7 @@ finish: return nmc->return_value; } -/*----------------------------------------------------------------------------*/ +/*****************************************************************************/ /* Functions for readline TAB completion in editor */ static void @@ -5226,28 +5005,33 @@ 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_free char **values = NULL; + const NMMetaSettingInfoEditor *editor; + GPtrArray *array; + int i; - if (!state) { - list_idx = 0; - len = strlen (text); - } + array = g_ptr_array_new (); - 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); + for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++) { + editor = &nm_meta_setting_infos_editor[i]; + if (!editor->valid_parts) + continue; + g_ptr_array_add (array, (gpointer) nm_meta_setting_infos[i].setting_name); + if (editor->alias) + g_ptr_array_add (array, (gpointer) editor->alias); } - return NULL; + g_ptr_array_add (array, "bond-slave"); + g_ptr_array_add (array, "bridge-slave"); + g_ptr_array_add (array, "team-slave"); + g_ptr_array_add (array, NULL); + + values = (char **) g_ptr_array_free (array, FALSE); + + return nmc_rl_compentry_func_wrap ((const char *const*) values); } static char * @@ -5255,10 +5039,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; @@ -5268,11 +5051,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); @@ -5291,20 +5076,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); - - 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); + valid_settings_arr = nm_meta_setting_info_valid_parts_for_slave_type (s_type, NULL); + + 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; @@ -5319,8 +5106,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; @@ -5330,7 +5117,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); @@ -5338,19 +5125,24 @@ 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); - } else { + if (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); + } + } + + if (!setting) { /* Else take the current setting, if any */ setting = nmc_tab_completion.setting ? g_object_ref (nmc_tab_completion.setting) : NULL; } @@ -5628,15 +5420,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) { @@ -5644,15 +5435,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; @@ -5723,27 +5513,24 @@ should_complete_vpn_uuids (const char *prompt, const char *line) return _get_and_check_property (prompt, line, uuid_properties, NULL, NULL); } -static const char ** -get_allowed_property_values (void) +static const char *const* +get_allowed_property_values (char ***out_to_free) { - NMSetting *setting; - char *property; - const char **avals = NULL; + gs_unref_object NMSetting *setting = NULL; + gs_free char *property = NULL; + const char *const*avals = NULL; get_setting_and_property (rl_prompt, rl_line_buffer, &setting, &property); if (setting && property) - avals = nmc_setting_get_property_allowed_values (setting, property); - - if (setting) - g_object_unref (setting); - g_free (property); - + avals = nmc_setting_get_property_allowed_values (setting, property, out_to_free); return avals; } static gboolean should_complete_property_values (const char *prompt, const char *line, gboolean *multi) { + gs_strfreev char **to_free = NULL; + /* properties allowing multiple values */ const char *multi_props[] = { /* '802-1x' properties */ @@ -5759,10 +5546,9 @@ should_complete_property_values (const char *prompt, const char *line, gboolean NULL }; _get_and_check_property (prompt, line, NULL, multi_props, multi); - return get_allowed_property_values () != NULL; + return !!get_allowed_property_values (&to_free); } -//FIXME: this helper should go to libnm later static gboolean _setting_property_is_boolean (NMSetting *setting, const char *property_name) { @@ -5798,13 +5584,13 @@ should_complete_boolean (const char *prompt, const char *line) static char * gen_property_values (const char *text, int state) { - char *ret = NULL; - const char **avals; + gs_strfreev char **to_free = NULL; + const char *const*avals; - avals = get_allowed_property_values (); - if (avals) - ret = nmc_rl_gen_func_basic (text, state, avals); - return ret; + avals = get_allowed_property_values (&to_free); + if (!avals) + return NULL; + return nmc_rl_gen_func_basic (text, state, avals); } /* from readline */ @@ -5847,7 +5633,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) @@ -6033,19 +5819,16 @@ save_history_cmds (const char *uuid) } } -/*----------------------------------------------------------------------------*/ +/*****************************************************************************/ static void editor_show_connection (NMConnection *connection, NmCli *nmc) { - nmc->print_output = NMC_PRINT_PRETTY; - nmc->multiline_output = TRUE; - nmc->escape_values = 0; - - /* Remove any previous data */ - nmc_empty_output_fields (nmc); + nmc->nmc_config_mutable.print_output = NMC_PRINT_PRETTY; + 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 @@ -6054,14 +5837,11 @@ editor_show_setting (NMSetting *setting, NmCli *nmc) g_print (_("['%s' setting values]\n"), nm_setting_get_name (setting)); - nmc->print_output = NMC_PRINT_NORMAL; - nmc->multiline_output = TRUE; - nmc->escape_values = 0; + nmc->nmc_config_mutable.print_output = NMC_PRINT_NORMAL; + nmc->nmc_config_mutable.multiline_output = TRUE; + nmc->nmc_config_mutable.escape_values = 0; - /* Remove any previous data */ - nmc_empty_output_fields (nmc); - - setting_details (setting, nmc, NULL, nmc->editor_show_secrets); + setting_details (&nmc->nmc_config, setting, NULL); } typedef enum { @@ -6392,12 +6172,13 @@ editor_sub_usage (const char *command) } } -/*----------------------------------------------------------------------------*/ +/*****************************************************************************/ typedef struct { NMDevice *device; NMActiveConnection *ac; guint monitor_id; + NmCli *nmc; } MonitorACInfo; static gboolean nmc_editor_cb_called; @@ -6475,6 +6256,14 @@ progress_activation_editor_cb (gpointer user_data) goto finish; /* we are done */ } + if (info->nmc->secret_agent) { + NMRemoteConnection *connection; + + connection = nm_active_connection_get_connection (ac); + nm_secret_agent_simple_enable (NM_SECRET_AGENT_SIMPLE (info->nmc->secret_agent), + nm_object_get_path (NM_OBJECT (connection))); + } + return TRUE; finish: @@ -6510,6 +6299,7 @@ activate_connection_editor_cb (GObject *client, monitor_ac_info->device = g_object_ref (device); monitor_ac_info->ac = active; monitor_ac_info->monitor_id = g_timeout_add (120, progress_activation_editor_cb, monitor_ac_info); + monitor_ac_info->nmc = info->nmc; } else g_object_unref (active); } @@ -6517,7 +6307,7 @@ activate_connection_editor_cb (GObject *client, g_clear_error (&error); } -/*----------------------------------------------------------------------------*/ +/*****************************************************************************/ static void print_property_description (NMSetting *setting, const char *prop_name) @@ -6525,8 +6315,10 @@ print_property_description (NMSetting *setting, const char *prop_name) char *desc; desc = nmc_setting_get_property_desc (setting, prop_name); - g_print ("\n=== [%s] ===\n%s\n", prop_name, desc); - g_free (desc); + if (desc) { + g_print ("\n=== [%s] ===\n%s\n", prop_name, desc); + g_free (desc); + } } static void @@ -6613,7 +6405,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); @@ -6647,7 +6439,7 @@ property_edit_submenu (NmCli *nmc, /* Set global variable for use in TAB completion */ nmc_tab_completion.property = prop_name; - prompt = nmc_colorize (nmc, nmc->editor_prompt_color, NMC_TERM_FORMAT_NORMAL, + prompt = nmc_colorize (nmc->nmc_config.use_colors, nmc->editor_prompt_color, NM_META_TERM_FORMAT_NORMAL, "nmcli %s.%s> ", nm_setting_get_name (curr_setting), prop_name); @@ -6680,12 +6472,16 @@ property_edit_submenu (NmCli *nmc, * single values: : both SET and ADD sets the new value */ if (!cmd_property_arg) { - const char **avals = nmc_setting_get_property_allowed_values (curr_setting, prop_name); + gs_strfreev char **to_free = NULL; + const char *const*avals; + + avals = nmc_setting_get_property_allowed_values (curr_setting, prop_name, &to_free); if (avals) { - char *avals_str = nmc_util_strv_for_display (avals, FALSE); + gs_free char *avals_str = NULL; + + avals_str = nmc_util_strv_for_display (avals, FALSE); g_print (_("Allowed values for '%s' property: %s\n"), prop_name, avals_str); - g_free (avals_str); } prop_val_user = nmc_readline (_("Enter '%s' value: "), prop_name); } else @@ -6851,7 +6647,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; @@ -6860,18 +6656,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; @@ -6961,7 +6755,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; @@ -6979,14 +6773,14 @@ typedef struct { } NmcEditorMenuContext; static void -menu_switch_to_level0 (NmCli *nmc, +menu_switch_to_level0 (NmcColorOption color_option, NmcEditorMenuContext *menu_ctx, const char *prompt, - NmcTermColor prompt_color) + NMMetaTermColor prompt_color) { menu_ctx->level = 0; g_free (menu_ctx->main_prompt); - menu_ctx->main_prompt = nmc_colorize (nmc, prompt_color, NMC_TERM_FORMAT_NORMAL, "%s", prompt); + menu_ctx->main_prompt = nmc_colorize (color_option, prompt_color, NM_META_TERM_FORMAT_NORMAL, "%s", prompt); menu_ctx->curr_setting = NULL; g_strfreev (menu_ctx->valid_props); menu_ctx->valid_props = NULL; @@ -6995,15 +6789,15 @@ menu_switch_to_level0 (NmCli *nmc, } static void -menu_switch_to_level1 (NmCli *nmc, +menu_switch_to_level1 (NmcColorOption color_option, NmcEditorMenuContext *menu_ctx, NMSetting *setting, const char *setting_name, - NmcTermColor prompt_color) + NMMetaTermColor prompt_color) { menu_ctx->level = 1; g_free (menu_ctx->main_prompt); - menu_ctx->main_prompt = nmc_colorize (nmc, prompt_color, NMC_TERM_FORMAT_NORMAL, + menu_ctx->main_prompt = nmc_colorize (color_option, prompt_color, NM_META_TERM_FORMAT_NORMAL, "nmcli %s> ", setting_name); menu_ctx->curr_setting = setting; g_strfreev (menu_ctx->valid_props); @@ -7013,47 +6807,37 @@ menu_switch_to_level1 (NmCli *nmc, } static gboolean -editor_menu_main (NmCli *nmc, NMConnection *connection) +editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_type) { + gs_unref_object NMRemoteConnection *rem_con = NULL; NMSettingConnection *s_con; - NMRemoteConnection *rem_con; NMRemoteConnection *con_tmp; GWeakRef weak = { { NULL } }; gboolean removed; NmcEditorMainCmd cmd; - char *cmd_user; 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; - char *valid_settings_str = NULL; + const NMMetaSettingValidPartItem *const*valid_settings_main; + const NMMetaSettingValidPartItem *const*valid_settings_slave; + gs_free char *valid_settings_str = NULL; const char *s_type = NULL; - char *slv_type; AddConnectionInfo *info = NULL; gboolean dirty; gboolean temp_changes; GError *err1 = NULL; - NmcEditorMenuContext menu_ctx; + NmcEditorMenuContext menu_ctx = { 0 }; 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 (nm_connection_get_connection_type (connection)); - valid_settings_slave = get_valid_settings_array (slv_type); - g_free (slv_type); + valid_settings_main = get_valid_settings_array (connection_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); g_print (_("You may edit the following settings: %s\n"), valid_settings_str); - menu_ctx.level = 0; - menu_ctx.main_prompt = nmc_colorize (nmc, nmc->editor_prompt_color, NMC_TERM_FORMAT_NORMAL, + menu_ctx.main_prompt = nmc_colorize (nmc->nmc_config.use_colors, nmc->editor_prompt_color, NM_META_TERM_FORMAT_NORMAL, BASE_PROMPT); - menu_ctx.curr_setting = NULL; - menu_ctx.valid_props = NULL; - menu_ctx.valid_props_str = NULL; /* Get remote connection */ con_tmp = nm_client_get_connection_by_uuid (nmc->client, @@ -7062,6 +6846,12 @@ editor_menu_main (NmCli *nmc, NMConnection *connection) rem_con = g_weak_ref_get (&weak); while (cmd_loop) { + gs_free char *cmd_user = NULL; + gs_free char *cmd_arg = NULL; + gs_free char *cmd_arg_s = NULL; + gs_free char *cmd_arg_p = NULL; + gs_free char *cmd_arg_v = NULL; + /* Connection is dirty? (not saved or differs from the saved) */ dirty = is_connection_dirty (connection, rem_con); temp_changes = rem_con ? nm_remote_connection_get_unsaved (rem_con) : TRUE; @@ -7081,18 +6871,16 @@ editor_menu_main (NmCli *nmc, NMConnection *connection) continue; cmd = parse_editor_main_cmd (g_strstrip (cmd_user), &cmd_arg); - cmd_arg_s = NULL; - cmd_arg_p = NULL; - cmd_arg_v = NULL; split_editor_main_cmd_args (cmd_arg, &cmd_arg_s, &cmd_arg_p, &cmd_arg_v); switch (cmd) { case NMC_EDITOR_MAIN_CMD_SET: /* Set property value */ if (!cmd_arg) { if (menu_ctx.level == 1) { + gs_strfreev char **avals_to_free = NULL; + gs_free char *prop_val_user = NULL; const char *prop_name; - char *prop_val_user = NULL; - const char **avals; + const char *const*avals; GError *tmp_err = NULL; prop_name = ask_check_property (cmd_arg, @@ -7101,12 +6889,13 @@ editor_menu_main (NmCli *nmc, NMConnection *connection) if (!prop_name) break; - avals = nmc_setting_get_property_allowed_values (menu_ctx.curr_setting, prop_name); + avals = nmc_setting_get_property_allowed_values (menu_ctx.curr_setting, prop_name, &avals_to_free); if (avals) { - char *avals_str = nmc_util_strv_for_display (avals, FALSE); + gs_free char *avals_str = NULL; + + avals_str = nmc_util_strv_for_display (avals, FALSE); g_print (_("Allowed values for '%s' property: %s\n"), prop_name, avals_str); - g_free (avals_str); } prop_val_user = nmc_readline (_("Enter '%s' value: "), prop_name); @@ -7120,22 +6909,22 @@ editor_menu_main (NmCli *nmc, NMConnection *connection) g_print (_("use 'goto <setting>' first, or 'set <setting>.<property>'\n")); } } else { + gs_free char *prop_name = NULL; + gs_unref_object NMSetting *ss_created = NULL; NMSetting *ss = NULL; - gboolean created_ss = FALSE; - char *prop_name; GError *tmp_err = NULL; if (cmd_arg_s) { /* setting provided as "setting.property" */ ss = is_setting_valid (connection, valid_settings_main, valid_settings_slave, cmd_arg_s); if (!ss) { - ss = create_setting_by_name (cmd_arg_s, valid_settings_main, valid_settings_slave); + ss_created = create_setting_by_name (cmd_arg_s, valid_settings_main, valid_settings_slave); + ss = ss_created; if (!ss) { g_print (_("Error: invalid setting argument '%s'; valid are [%s]\n"), cmd_arg_s, valid_settings_str); break; } - created_ss = TRUE; } } else { if (menu_ctx.curr_setting) @@ -7150,21 +6939,21 @@ editor_menu_main (NmCli *nmc, NMConnection *connection) if (!prop_name) { g_print (_("Error: invalid property: %s\n"), tmp_err->message); g_clear_error (&tmp_err); - if (created_ss) - g_object_unref (ss); break; } - - /* Ask for value */ if (!cmd_arg_v) { - const char **avals = nmc_setting_get_property_allowed_values (ss, prop_name); + gs_strfreev char **avals_to_free = NULL; + const char *const*avals; + + avals = nmc_setting_get_property_allowed_values (ss, prop_name, &avals_to_free); if (avals) { - char *avals_str = nmc_util_strv_for_display (avals, FALSE); + gs_free char *avals_str = NULL; + + avals_str = nmc_util_strv_for_display (avals, FALSE); g_print (_("Allowed values for '%s' property: %s\n"), prop_name, avals_str); - g_free (avals_str); } cmd_arg_v = nmc_readline (_("Enter '%s' value: "), prop_name); } @@ -7176,9 +6965,8 @@ editor_menu_main (NmCli *nmc, NMConnection *connection) g_clear_error (&tmp_err); } - if (created_ss) - nm_connection_add_setting (connection, ss); - g_free (prop_name); + if (ss_created) + nm_connection_add_setting (connection, g_steal_pointer (&ss_created)); } break; @@ -7191,20 +6979,24 @@ editor_menu_main (NmCli *nmc, NMConnection *connection) 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)); @@ -7221,7 +7013,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection) nmc_tab_completion.setting = setting; /* Switch to level 1 */ - menu_switch_to_level1 (nmc, &menu_ctx, setting, setting_name, nmc->editor_prompt_color); + menu_switch_to_level1 (nmc->nmc_config.use_colors, &menu_ctx, setting, setting_name, nmc->editor_prompt_color); if (!cmd_arg_s) { g_print (_("You may edit the following properties: %s\n"), menu_ctx.valid_props_str); @@ -7279,19 +7071,20 @@ editor_menu_main (NmCli *nmc, NMConnection *connection) 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 @@ -7302,12 +7095,14 @@ editor_menu_main (NmCli *nmc, NMConnection *connection) connection_remove_setting (connection, ss); if (ss == menu_ctx.curr_setting) { /* If we removed the setting we are in, go up */ - menu_switch_to_level0 (nmc, &menu_ctx, BASE_PROMPT, nmc->editor_prompt_color); + menu_switch_to_level0 (nmc->nmc_config.use_colors, &menu_ctx, BASE_PROMPT, nmc->editor_prompt_color); nmc_tab_completion.setting = NULL; /* for TAB completion */ } } else { + gs_free char *prop_name = NULL; GError *tmp_err = NULL; - char *prop_name = is_property_valid (ss, cmd_arg_p, &tmp_err); + + prop_name = is_property_valid (ss, cmd_arg_p, &tmp_err); if (prop_name) { /* Delete property value */ if (!nmc_setting_reset_property (ss, prop_name, &tmp_err)) { @@ -7319,16 +7114,16 @@ editor_menu_main (NmCli *nmc, NMConnection *connection) /* 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); /* coverity[copy_paste_error] - suppress Coverity COPY_PASTE_ERROR defect */ if (ss == menu_ctx.curr_setting) { /* If we removed the setting we are in, go up */ - menu_switch_to_level0 (nmc, &menu_ctx, BASE_PROMPT, nmc->editor_prompt_color); + menu_switch_to_level0 (nmc->nmc_config.use_colors, &menu_ctx, BASE_PROMPT, nmc->editor_prompt_color); nmc_tab_completion.setting = NULL; /* for TAB completion */ } } else @@ -7336,7 +7131,6 @@ editor_menu_main (NmCli *nmc, NMConnection *connection) tmp_err->message); g_clear_error (&tmp_err); } - g_free (prop_name); } } break; @@ -7360,8 +7154,8 @@ editor_menu_main (NmCli *nmc, NMConnection *connection) g_print (_("use 'goto <setting>' first, or 'describe <setting>.<property>'\n")); } } else { + gs_unref_object NMSetting *ss_free = NULL; NMSetting *ss = NULL; - gboolean unref_ss = FALSE; gboolean descr_all; char *user_s; @@ -7370,39 +7164,45 @@ editor_menu_main (NmCli *nmc, NMConnection *connection) 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); break; } - unref_ss = TRUE; + ss_free = ss; } } else ss = menu_ctx.curr_setting; - if (descr_all) { + if (!ss) { + g_print (_("Error: no setting selected; valid are [%s]\n"), valid_settings_str); + g_print (_("use 'goto <setting>' first, or 'describe <setting>.<property>'\n")); + } else if (descr_all) { /* Show description for all properties */ print_setting_description (ss); } else { GError *tmp_err = NULL; - char *prop_name = is_property_valid (ss, cmd_arg_p, &tmp_err); + gs_free char *prop_name = NULL; + + prop_name = is_property_valid (ss, cmd_arg_p, &tmp_err); if (prop_name) { /* Show property description */ print_property_description (ss, prop_name); } else { /* 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 @@ -7411,10 +7211,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection) tmp_err->message); g_clear_error (&tmp_err); } - g_free (prop_name); } - if (unref_ss) - g_object_unref (ss); } break; @@ -7433,6 +7230,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection) 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, @@ -7453,20 +7251,23 @@ editor_menu_main (NmCli *nmc, NMConnection *connection) /* Print the whole setting */ editor_show_setting (ss, nmc); } else { + gs_free char *prop_name = NULL; GError *err = NULL; - char *prop_name = is_property_valid (ss, cmd_arg_p, &err); + + prop_name = is_property_valid (ss, cmd_arg_p, &err); if (prop_name) { /* Print one property */ - char *prop_val = nmc_setting_get_property (ss, prop_name, NULL); + gs_free char *prop_val = NULL; + + prop_val = nmc_setting_get_property (ss, prop_name, NULL); g_print ("%s.%s: %s\n", nm_setting_get_name (ss),prop_name , prop_val); - g_free (prop_val); } else { /* 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); @@ -7476,7 +7277,6 @@ editor_menu_main (NmCli *nmc, NMConnection *connection) cmd_arg_s ? "" : _(", neither a valid setting name")); g_clear_error (&err); } - g_free (prop_name); } } } else { @@ -7587,7 +7387,8 @@ editor_menu_main (NmCli *nmc, NMConnection *connection) * adding ipv{4,6} settings when not present. */ if (con_tmp) { - char *s_name = NULL; + gs_free char *s_name = NULL; + if (menu_ctx.curr_setting) s_name = g_strdup (nm_setting_get_name (menu_ctx.curr_setting)); @@ -7598,7 +7399,6 @@ editor_menu_main (NmCli *nmc, NMConnection *connection) /* Also update setting for menu context and TAB-completion */ menu_ctx.curr_setting = s_name ? nm_connection_get_setting_by_name (connection, s_name) : NULL; nmc_tab_completion.setting = menu_ctx.curr_setting; - g_free (s_name); } } @@ -7640,7 +7440,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection) nmc->nowait_flag = FALSE; nmc->should_wait++; - nmc->print_output = NMC_PRINT_PRETTY; + nmc->nmc_config_mutable.print_output = NMC_PRINT_PRETTY; if (!nmc_activate_connection (nmc, NM_CONNECTION (rem_con), ifname, ap_nsp, ap_nsp, NULL, activate_connection_editor_cb, &tmp_err)) { g_print (_("Error: Cannot activate connection: %s.\n"), tmp_err->message); @@ -7679,7 +7479,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection) case NMC_EDITOR_MAIN_CMD_BACK: /* Go back (up) an the menu */ if (menu_ctx.level == 1) { - menu_switch_to_level0 (nmc, &menu_ctx, BASE_PROMPT, nmc->editor_prompt_color); + menu_switch_to_level0 (nmc->nmc_config.use_colors, &menu_ctx, BASE_PROMPT, nmc->editor_prompt_color); nmc_tab_completion.setting = NULL; /* for TAB completion */ } break; @@ -7713,24 +7513,25 @@ editor_menu_main (NmCli *nmc, NMConnection *connection) 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; - NmcTermColor color; + NMMetaTermColor color; color = nmc_term_color_parse_string (cmd_arg_v ? g_strstrip (cmd_arg_v) : " ", &tmp_err); if (tmp_err) { g_print (_("Error: bad color: %s\n"), tmp_err->message); g_clear_error (&tmp_err); } else { nmc->editor_prompt_color = color; - g_free (menu_ctx.main_prompt); - if (menu_ctx.level == 0) - menu_ctx.main_prompt = nmc_colorize (nmc, nmc->editor_prompt_color, NMC_TERM_FORMAT_NORMAL, + nm_clear_g_free (&menu_ctx.main_prompt); + if (menu_ctx.level == 0) { + menu_ctx.main_prompt = nmc_colorize (nmc->nmc_config.use_colors, nmc->editor_prompt_color, NM_META_TERM_FORMAT_NORMAL, BASE_PROMPT); - else - menu_ctx.main_prompt = nmc_colorize (nmc, nmc->editor_prompt_color, NMC_TERM_FORMAT_NORMAL, + } else { + menu_ctx.main_prompt = nmc_colorize (nmc->nmc_config.use_colors, nmc->editor_prompt_color, NM_META_TERM_FORMAT_NORMAL, "nmcli %s> ", nm_setting_get_name (menu_ctx.curr_setting)); + } } } else if (!cmd_arg_p) { g_print (_("Current nmcli configuration:\n")); @@ -7740,7 +7541,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection) "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"), @@ -7761,19 +7562,11 @@ editor_menu_main (NmCli *nmc, NMConnection *connection) g_print (_("Unknown command: '%s'\n"), cmd_user); break; } - - g_free (cmd_user); - g_free (cmd_arg); - g_free (cmd_arg_s); - g_free (cmd_arg_p); - g_free (cmd_arg_v); } - g_free (valid_settings_str); + g_free (menu_ctx.main_prompt); g_strfreev (menu_ctx.valid_props); g_free (menu_ctx.valid_props_str); - if (rem_con) - g_object_unref (rem_con); g_weak_ref_clear (&weak); /* Save history file */ @@ -7798,12 +7591,11 @@ get_ethernet_device_name (NmCli *nmc) } static void -editor_init_new_connection (NmCli *nmc, NMConnection *connection) +editor_init_new_connection (NmCli *nmc, NMConnection *connection, const char *slave_type) { NMSetting *setting, *base_setting; NMSettingConnection *s_con; const char *con_type; - const char *slave_type = NULL; s_con = nm_connection_get_setting_connection (connection); g_assert (s_con); @@ -7813,13 +7605,6 @@ editor_init_new_connection (NmCli *nmc, NMConnection *connection) nmc_setting_connection_connect_handlers (s_con, connection); - if (g_strcmp0 (con_type, "bond-slave") == 0) - slave_type = NM_SETTING_BOND_SETTING_NAME; - if (g_strcmp0 (con_type, "team-slave") == 0) - slave_type = NM_SETTING_TEAM_SETTING_NAME; - if (g_strcmp0 (con_type, "bridge-slave") == 0) - slave_type = NM_SETTING_BRIDGE_SETTING_NAME; - if (slave_type) { const char *dev_ifname = get_ethernet_device_name (nmc); @@ -7833,11 +7618,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); @@ -7852,18 +7640,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); } } @@ -7895,14 +7681,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); } } @@ -8016,15 +7806,17 @@ do_connection_edit (NmCli *nmc, int argc, char **argv) editor_init_existing_connection (connection); } else { + const char *slave_type = NULL; + /* 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, &slave_type, &err1); + tmp_str = get_valid_options_string_toplevel (); while (!connection_type) { if (!type) @@ -8035,7 +7827,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, &slave_type, &err1); g_free (type_ask); } g_free (tmp_str); @@ -8048,9 +7840,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, @@ -8062,11 +7855,11 @@ do_connection_edit (NmCli *nmc, int argc, char **argv) nm_connection_add_setting (connection, NM_SETTING (s_con)); /* Initialize the new connection so that it is valid from the start */ - editor_init_new_connection (nmc, connection); + editor_init_new_connection (nmc, connection, slave_type); } /* nmcli runs the editor */ - nmc->in_editor = TRUE; + nmc->nmc_config_mutable.in_editor = TRUE; g_print ("\n"); g_print (_("===| nmcli interactive connection editor |===")); @@ -8083,11 +7876,11 @@ do_connection_edit (NmCli *nmc, int argc, char **argv) /* Set global variables for use in TAB completion */ nmc_tab_completion.nmc = nmc; - nmc_tab_completion.con_type = g_strdup (nm_connection_get_connection_type (connection)); + nmc_tab_completion.con_type = g_strdup (connection_type); nmc_tab_completion.connection = connection; /* Run menu loop */ - editor_menu_main (nmc, connection); + editor_menu_main (nmc, connection, connection_type); if (connection) g_object_unref (connection); @@ -8119,7 +7912,7 @@ modify_connection_cb (GObject *connection, g_error_free (error); nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; } else { - if (nmc->print_output == NMC_PRINT_PRETTY) + if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY) g_print (_("Connection '%s' (%s) successfully modified.\n"), nm_connection_get_id (NM_CONNECTION (connection)), nm_connection_get_uuid (NM_CONNECTION (connection))); @@ -8590,26 +8383,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) { @@ -8634,7 +8409,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; @@ -8659,7 +8434,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; @@ -8934,8 +8709,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; |