cli: implement TAB completion for inputs in questionnaire mode

and also
- accept yes/no options as localized strings
- simplify some questionnaire code
This commit is contained in:
Jiří Klimeš 2014-05-14 16:42:26 +02:00
parent 480f69e23f
commit bfb1200b4f

View file

@ -65,6 +65,17 @@
#define EDITOR_PROMPT_PROPERTY _("Property name? ")
#define EDITOR_PROMPT_CON_TYPE _("Enter connection type: ")
/* define some other prompts */
#define PROMPT_CON_TYPE _("Connection type: ")
#define PROMPT_VPN_TYPE _("VPN type: ")
#define PROMPT_BOND_MASTER _("Bond master: ")
#define PROMPT_TEAM_MASTER _("Team master: ")
#define PROMPT_BRIDGE_MASTER _("Bridge master: ")
static const char *nmc_known_vpns[] =
{ "openvpn", "vpnc", "pptp", "openconnect", "openswan", "libreswan",
"ssh", "l2tp", "iodine", NULL };
/* Available fields for 'connection show' */
static NmcOutputField nmc_fields_con_show[] = {
{"NAME", N_("NAME"), 25}, /* 0 */
@ -256,6 +267,11 @@ typedef struct {
} TabCompletionInfo;
static TabCompletionInfo nmc_tab_completion = {NULL, NULL, NULL, NULL};
/* Global variable defined in nmcli.c - used for TAB completion */
extern NmCli nm_cli;
static char *gen_connection_types (char *text, int state);
static void
usage (void)
{
@ -2564,18 +2580,29 @@ check_infiniband_p_key (const char *p_key, guint32 *p_key_int, GError **error)
return TRUE;
}
/* Checks InfiniBand mode.
* It accepts shortcuts and normalizes them ('mode' argument is modified on success).
*/
static gboolean
check_infiniband_mode (const char *mode, GError **error)
check_infiniband_mode (char *mode, GError **error)
{
char *tmp;
const char *checked_mode;
const char *modes[] = { "datagram", "connected", NULL };
if (!mode)
return TRUE;
if (strcmp (mode, "datagram") && strcmp (mode, "connected")) {
tmp = g_strstrip (g_strdup (mode));
checked_mode = nmc_string_is_valid (tmp, modes, NULL);
g_free (tmp);
if (checked_mode) {
g_free (mode);
mode = g_strdup (checked_mode);
} else
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
_("Error: 'mode': '%s' is not a valid InfiniBand transport mode [datagram, connected]."), mode);
return FALSE;
}
return TRUE;
return !!checked_mode;
}
static gboolean
@ -2810,22 +2837,75 @@ bridge_prop_string_to_uint (const char *str,
return TRUE;
}
#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)
{
static char prompt[128] = { 0 };
if (!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);
return prompt;
}
static void
normalize_yes_no (char *yes_no)
{
const char *tmp;
const char *strv[] = { WORD_LOC_YES, WORD_LOC_NO, NULL };
if (!yes_no)
return;
g_strstrip (yes_no);
tmp = nmc_string_is_valid (yes_no, strv, NULL);
if (g_strcmp0 (tmp, WORD_LOC_YES) == 0) {
g_free (yes_no);
yes_no = g_strdup (WORD_YES);
} else if (g_strcmp0 (tmp, WORD_LOC_NO) == 0) {
g_free (yes_no);
yes_no = g_strdup (WORD_NO);
}
}
static gboolean
want_provide_opt_args (const char *type, int num)
{
char *answer;
gboolean ret = TRUE;
/* Ask for optional arguments. */
printf (ngettext ("There is %d optional argument for '%s' connection type.\n",
"There are %d optional arguments for '%s' connection type.\n", num),
num, type);
answer = nmc_readline (ngettext ("Do you want to provide it? %s",
"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) != 0)
ret = FALSE;
g_free (answer);
return ret;
}
static void
do_questionnaire_ethernet (gboolean ethernet, char **mtu, char **mac, char **cloned_mac)
{
char *answer;
gboolean answer_bool;
gboolean once_more;
GError *error = NULL;
const char *type = ethernet ? _("ethernet") : _("Wi-Fi");
/* Ask for optional arguments */
printf (_("There are 3 optional arguments for '%s' connection type.\n"), type);;
answer = nmc_readline (_("Do you want to provide them? (yes/no) [yes] "));
if (answer && (!nmc_string_to_bool (answer, &answer_bool, NULL) || !answer_bool)) {
g_free (answer);
if (!want_provide_opt_args (type, 3))
return;
}
if (!*mtu) {
do {
@ -2860,26 +2940,20 @@ do_questionnaire_ethernet (gboolean ethernet, char **mtu, char **mac, char **clo
}
} while (once_more);
}
g_free (answer);
return;
}
#define WORD_DATAGRAM "datagram"
#define WORD_CONNECTED "connected"
#define PROMPT_IB_MODE "(" WORD_DATAGRAM "/" WORD_CONNECTED ") [" WORD_DATAGRAM "]: "
static void
do_questionnaire_infiniband (char **mtu, char **mac, char **mode, char **parent, char **p_key)
{
char *answer;
gboolean answer_bool;
gboolean once_more;
GError *error = NULL;
/* Ask for optional arguments */
printf (_("There are 5 optional arguments for 'InfiniBand' connection type.\n"));
answer = nmc_readline (_("Do you want to provide them? (yes/no) [yes] "));
if (answer && (!nmc_string_to_bool (answer, &answer_bool, NULL) || !answer_bool)) {
g_free (answer);
if (!want_provide_opt_args (_("InfiniBand"), 5))
return;
}
if (!*mtu) {
do {
@ -2905,7 +2979,7 @@ do_questionnaire_infiniband (char **mtu, char **mac, char **mode, char **parent,
}
if (!*mode) {
do {
*mode = nmc_readline (_("Transport mode (datagram or connected) [datagram]: "));
*mode = nmc_readline (_("Transport mode %s"), PROMPT_IB_MODE);
if (!*mode)
*mode = g_strdup ("datagram");
once_more = !check_infiniband_mode (*mode, &error);
@ -2943,9 +3017,6 @@ do_questionnaire_infiniband (char **mtu, char **mac, char **mode, char **parent,
}
} while (once_more);
}
g_free (answer);
return;
}
static void
@ -2958,18 +3029,12 @@ do_questionnaire_wifi (char **mtu, char **mac, char **cloned_mac)
static void
do_questionnaire_wimax (char **mac)
{
char *answer;
gboolean answer_bool;
gboolean once_more;
GError *error = NULL;
/* Ask for optional 'wimax' arguments. */
printf (_("There is 1 optional argument for 'WiMax' connection type.\n"));
answer = nmc_readline (_("Do you want to provide it? (yes/no) [yes] "));
if (answer && (!nmc_string_to_bool (answer, &answer_bool, NULL) || !answer_bool)) {
g_free (answer);
if (!want_provide_opt_args (_("WiMAX"), 1))
return;
}
if (!*mac) {
do {
@ -2982,26 +3047,17 @@ do_questionnaire_wimax (char **mac)
}
} while (once_more);
}
g_free (answer);
return;
}
static void
do_questionnaire_pppoe (char **password, char **service, char **mtu, char **mac)
{
char *answer;
gboolean answer_bool;
gboolean once_more;
GError *error = NULL;
/* Ask for optional 'pppoe' arguments. */
printf (_("There are 4 optional arguments for 'PPPoE' connection type.\n"));
answer = nmc_readline (_("Do you want to provide them? (yes/no) [yes] "));
if (answer && (!nmc_string_to_bool (answer, &answer_bool, NULL) || !answer_bool)) {
g_free (answer);
if (!want_provide_opt_args (_("PPPoE"), 4))
return;
}
if (!*password)
*password = nmc_readline (_("Password [none]: "));
@ -3030,84 +3086,62 @@ do_questionnaire_pppoe (char **password, char **service, char **mtu, char **mac)
}
} while (once_more);
}
g_free (answer);
return;
}
static void
do_questionnaire_mobile (char **user, char **password)
{
char *answer;
gboolean answer_bool;
/* Ask for optional 'gsm' or 'cdma' arguments. */
printf (_("There are 2 optional arguments for 'mobile broadband' connection type.\n"));
answer = nmc_readline (_("Do you want to provide them? (yes/no) [yes] "));
if (answer && (!nmc_string_to_bool (answer, &answer_bool, NULL) || !answer_bool)) {
g_free (answer);
if (!want_provide_opt_args (_("mobile broadband"), 2))
return;
}
if (!*user)
*user = nmc_readline (_("Username [none]: "));
if (!*password)
*password = nmc_readline (_("Password [none]: "));
g_free (answer);
return;
}
#define WORD_PANU "panu"
#define WORD_DUN_GSM "dun-gsm"
#define WORD_DUN_CDMA "dun-cdma"
#define PROMPT_BT_TYPE "(" WORD_PANU "/" WORD_DUN_GSM "/" WORD_DUN_CDMA ") [" WORD_PANU "]: "
static void
do_questionnaire_bluetooth (char **bt_type)
{
char *answer;
gboolean answer_bool;
gboolean once_more;
/* Ask for optional 'bluetooth' arguments. */
printf (_("There is 1 optional argument for 'bluetooth' connection type.\n"));
answer = nmc_readline (_("Do you want to provide it? (yes/no) [yes] "));
if (answer && (!nmc_string_to_bool (answer, &answer_bool, NULL) || !answer_bool)) {
g_free (answer);
if (!want_provide_opt_args (_("bluetooth"), 1))
return;
}
if (!*bt_type) {
const char *types[] = { "dun", "dun-gsm", "dun-cdma", "panu", NULL };
const char *tmp;
do {
*bt_type = nmc_readline (_("Bluetooth type (panu, dun-gsm or dun-cdma) [panu]: "));
*bt_type = nmc_readline (_("Bluetooth type %s"), PROMPT_BT_TYPE);
if (!*bt_type)
*bt_type = g_strdup ("panu");
once_more = strcmp (*bt_type, NM_SETTING_BLUETOOTH_TYPE_DUN)
&& strcmp (*bt_type, NM_SETTING_BLUETOOTH_TYPE_DUN"-gsm")
&& strcmp (*bt_type, NM_SETTING_BLUETOOTH_TYPE_DUN"-cdma")
&& strcmp (*bt_type, NM_SETTING_BLUETOOTH_TYPE_PANU);
tmp = nmc_string_is_valid (*bt_type, types, NULL);
once_more = !tmp;
if (once_more) {
printf (_("Error: 'bt-type': '%s' is not a valid bluetooth type.\n"), *bt_type);
g_free (*bt_type);
}
} while (once_more);
g_free (*bt_type);
*bt_type = g_strdup (tmp);
}
g_free (answer);
return;
}
static void
do_questionnaire_vlan (char **mtu, char **flags, char **ingress, char **egress)
{
char *answer;
gboolean answer_bool;
gboolean once_more;
GError *error = NULL;
/* Ask for optional 'vlan' arguments. */
printf (_("There are 4 optional arguments for 'VLAN' connection type.\n"));
answer = nmc_readline (_("Do you want to provide them? (yes/no) [yes] "));
if (answer && (!nmc_string_to_bool (answer, &answer_bool, NULL) || !answer_bool)) {
g_free (answer);
if (!want_provide_opt_args (_("VLAN"), 4))
return;
}
if (!*mtu) {
do {
@ -3153,34 +3187,30 @@ do_questionnaire_vlan (char **mtu, char **flags, char **ingress, char **egress)
}
} while (once_more);
}
g_free (answer);
return;
}
#define PROMPT_BOND_MODE _("Bonding mode [balance-rr]: ")
#define WORD_MIIMON "miimon"
#define WORD_ARP "arp"
#define PROMPT_BOND_MON_MODE "(" WORD_MIIMON "/" WORD_ARP ") [" WORD_MIIMON "]: "
static void
do_questionnaire_bond (char **mode, char **primary, char **miimon,
char **downdelay, char **updelay,
char **arpinterval, char **arpiptarget)
{
char *answer, *monitor_mode;
gboolean answer_bool;
char *monitor_mode;
unsigned long tmp;
gboolean once_more;
GError *error = NULL;
/* Ask for optional 'bond' arguments. */
printf (_("There are optional arguments for 'bond' connection type.\n"));
answer = nmc_readline (_("Do you want to provide them? (yes/no) [yes] "));
if (answer && (!nmc_string_to_bool (answer, &answer_bool, NULL) || !answer_bool)) {
g_free (answer);
if (!want_provide_opt_args (_("bond"), 7))
return;
}
if (!*mode) {
const char *mode_tmp;
do {
*mode = nmc_readline (_("Bonding mode [balance-rr]: "));
*mode = nmc_readline (PROMPT_BOND_MODE);
if (!*mode)
*mode = g_strdup ("balance-rr");
mode_tmp = nmc_bond_validate_mode (*mode, &error);
@ -3207,18 +3237,19 @@ do_questionnaire_bond (char **mode, char **primary, char **miimon,
}
do {
monitor_mode = nmc_readline (_("Bonding monitoring mode (miimon or arp) [miimon]: "));
monitor_mode = nmc_readline (_("Bonding monitoring mode %s"), PROMPT_BOND_MON_MODE);
if (!monitor_mode)
monitor_mode = g_strdup ("miimon");
once_more = strcmp (monitor_mode, "miimon") && strcmp (monitor_mode, "arp");
monitor_mode = g_strdup (WORD_MIIMON);
g_strstrip (monitor_mode);
once_more = matches (monitor_mode, WORD_MIIMON) != 0 && matches (monitor_mode, WORD_ARP) != 0;
if (once_more) {
printf (_("Error: '%s' is not a valid monitoring mode; use '%s' or '%s'.\n"),
monitor_mode, "miimon", "arp");
monitor_mode, WORD_MIIMON, WORD_ARP);
g_free (monitor_mode);
}
} while (once_more);
if (strcmp (monitor_mode, "miimon") == 0) {
if (matches (monitor_mode, WORD_MIIMON) == 0) {
if (!*miimon) {
do {
*miimon = nmc_readline (_("Bonding miimon [100]: "));
@ -3270,27 +3301,19 @@ do_questionnaire_bond (char **mode, char **primary, char **miimon,
}
}
g_free (answer);
g_free (monitor_mode);
return;
}
static void
do_questionnaire_team_common (const char *type_name, char **config)
{
char *answer;
gboolean answer_bool;
gboolean once_more;
char *json = NULL;
GError *error = NULL;
/* Ask for optional 'team' arguments. */
printf (_("There is 1 optional argument for '%s' connection type.\n"), type_name);
answer = nmc_readline (_("Do you want to provide it? (yes/no) [yes] "));
if (answer && (!nmc_string_to_bool (answer, &answer_bool, NULL) || !answer_bool)) {
g_free (answer);
/* Ask for optional arguments. */
if (!want_provide_opt_args (type_name, 1))
return;
}
if (!*config) {
do {
@ -3305,8 +3328,6 @@ do_questionnaire_team_common (const char *type_name, char **config)
}
*config = json;
g_free (answer);
return;
}
/* Both team and team-slave curently have just ithe same one optional argument */
@ -3326,28 +3347,23 @@ static void
do_questionnaire_bridge (char **stp, char **priority, char **fwd_delay, char **hello_time,
char **max_age, char **ageing_time, char **mac)
{
char *answer;
gboolean answer_bool;
unsigned long tmp;
gboolean once_more;
GError *error = NULL;
/* Ask for optional 'bridge' arguments. */
printf (_("There are 7 optional arguments for 'bridge' connection type.\n"));
answer = nmc_readline (_("Do you want to provide them? (yes/no) [yes] "));
if (answer && (!nmc_string_to_bool (answer, &answer_bool, NULL) || !answer_bool)) {
g_free (answer);
if (!want_provide_opt_args (_("bridge"), 7))
return;
}
if (!*stp) {
gboolean stp_bool;
do {
*stp = nmc_readline (_("Enable STP (yes/no) [yes]: "));
*stp = nmc_readline (_("Enable STP %s"), prompt_yes_no (TRUE, ":"));
*stp = *stp ? *stp : g_strdup ("yes");
normalize_yes_no (*stp);
once_more = !nmc_string_to_bool (*stp, &stp_bool, &error);
if (once_more) {
printf (_("Error: 'stp': '%s'.\n"), error->message);
printf (_("Error: 'stp': %s.\n"), error->message);
g_clear_error (&error);
g_free (*stp);
}
@ -3425,27 +3441,18 @@ do_questionnaire_bridge (char **stp, char **priority, char **fwd_delay, char **h
}
} while (once_more);
}
g_free (answer);
return;
}
static void
do_questionnaire_bridge_slave (char **priority, char **path_cost, char **hairpin)
{
char *answer;
gboolean answer_bool;
unsigned long tmp;
gboolean once_more;
GError *error = NULL;
/* Ask for optional 'bridge-slave' arguments. */
printf (_("There are 3 optional arguments for 'bridge-slave' connection type.\n"));
answer = nmc_readline (_("Do you want to provide them? (yes/no) [yes] "));
if (answer && (!nmc_string_to_bool (answer, &answer_bool, NULL) || !answer_bool)) {
g_free (answer);
if (!want_provide_opt_args (_("bridge-slave"), 3))
return;
}
if (!*priority) {
do {
@ -3476,58 +3483,40 @@ do_questionnaire_bridge_slave (char **priority, char **path_cost, char **hairpin
if (!*hairpin) {
gboolean hairpin_bool;
do {
*hairpin = nmc_readline (_("Hairpin (yes/no) [yes]: "));
*hairpin = nmc_readline (_("Hairpin %s"), prompt_yes_no (TRUE, ":"));
*hairpin = *hairpin ? *hairpin : g_strdup ("yes");
normalize_yes_no (*hairpin);
once_more = !nmc_string_to_bool (*hairpin, &hairpin_bool, &error);
if (once_more) {
printf (_("Error: 'hairpin': '%s'.\n"), error->message);
printf (_("Error: 'hairpin': %s.\n"), error->message);
g_clear_error (&error);
g_free (*hairpin);
}
} while (once_more);
}
g_free (answer);
return;
}
static void
do_questionnaire_vpn (char **user)
{
char *answer;
gboolean answer_bool;
/* Ask for optional 'vpn' arguments. */
printf (_("There is 1 optional argument for 'VPN' connection type.\n"));
answer = nmc_readline (_("Do you want to provide it? (yes/no) [yes] "));
if (answer && (!nmc_string_to_bool (answer, &answer_bool, NULL) || !answer_bool)) {
g_free (answer);
if (!want_provide_opt_args (_("VPN"), 1))
return;
}
if (!*user)
*user = nmc_readline (_("Username [none]: "));
g_free (answer);
return;
}
static void
do_questionnaire_olpc (char **channel, char **dhcp_anycast)
{
char *answer;
gboolean answer_bool;
unsigned long tmp;
gboolean once_more;
GError *error = NULL;
/* Ask for optional 'olpc' arguments. */
printf (_("There are 2 optional arguments for 'OLPC Mesh' connection type.\n"));
answer = nmc_readline (_("Do you want to provide them? (yes/no) [yes] "));
if (answer && (!nmc_string_to_bool (answer, &answer_bool, NULL) || !answer_bool)) {
g_free (answer);
if (!want_provide_opt_args (_("OLPC Mesh"), 2))
return;
}
if (!*channel) {
do {
@ -3551,9 +3540,6 @@ do_questionnaire_olpc (char **channel, char **dhcp_anycast)
}
} while (once_more);
}
g_free (answer);
return;
}
static gboolean
@ -3631,11 +3617,11 @@ static void
do_questionnaire_ip (NMConnection *connection)
{
char *answer;
gboolean answer_bool;
/* Ask for IP addresses */
answer = nmc_readline (_("Do you want to add IP addresses? (yes/no) [yes] "));
if (answer && (!nmc_string_to_bool (answer, &answer_bool, NULL) || !answer_bool)) {
answer = nmc_readline (_("Do you want to add IP addresses? %s"), prompt_yes_no (TRUE, NULL));
answer = answer ? g_strstrip (answer) : NULL;
if (answer && matches (answer, WORD_LOC_YES) != 0) {
g_free (answer);
return;
}
@ -4404,11 +4390,14 @@ cleanup_bond:
{"type", TRUE, &type, FALSE},
{NULL} };
/* Set global variables for use in TAB completion */
nmc_tab_completion.con_type = NM_SETTING_BOND_SETTING_NAME;
if (!nmc_parse_args (exp_args, TRUE, &argc, &argv, error))
return FALSE;
if (!master && ask)
master = master_ask = nmc_readline (_("Bond master: "));
master = master_ask = nmc_readline (PROMPT_BOND_MASTER);
if (!master) {
g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
_("Error: 'master' is required."));
@ -4501,11 +4490,14 @@ cleanup_team:
{"config", TRUE, &config_c, FALSE},
{NULL} };
/* Set global variables for use in TAB completion */
nmc_tab_completion.con_type = NM_SETTING_TEAM_SETTING_NAME;
if (!nmc_parse_args (exp_args, TRUE, &argc, &argv, error))
return FALSE;
if (!master && ask)
master = master_ask = nmc_readline (_("Team master: "));
master = master_ask = nmc_readline (PROMPT_TEAM_MASTER);
if (!master) {
g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
_("Error: 'master' is required."));
@ -4705,11 +4697,14 @@ cleanup_bridge:
{"hairpin", TRUE, &hairpin_c, FALSE},
{NULL} };
/* Set global variables for use in TAB completion */
nmc_tab_completion.con_type = NM_SETTING_BRIDGE_SETTING_NAME;
if (!nmc_parse_args (exp_args, TRUE, &argc, &argv, error))
return FALSE;
if (!master && ask)
master = master_ask = nmc_readline (_("Bridge master: "));
master = master_ask = nmc_readline (PROMPT_BRIDGE_MASTER);
if (!master) {
g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
_("Error: 'master' is required."));
@ -4784,8 +4779,6 @@ cleanup_bridge_slave:
} else if (!strcmp (con_type, NM_SETTING_VPN_SETTING_NAME)) {
/* Build up the settings required for 'vpn' */
gboolean success = FALSE;
const char *known_vpns[] = { "openvpn", "vpnc", "pptp", "openconnect", "openswan", "libreswan",
"ssh", "l2tp", "iodine", NULL };
const char *vpn_type = NULL;
char *vpn_type_ask = NULL;
const char *user_c = NULL;
@ -4800,14 +4793,15 @@ cleanup_bridge_slave:
return FALSE;
if (!vpn_type && ask)
vpn_type = vpn_type_ask = nmc_readline (_("VPN type: "));
vpn_type = vpn_type_ask = nmc_readline (PROMPT_VPN_TYPE);
if (!vpn_type) {
g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
_("Error: 'vpn-type' is required."));
goto cleanup_vpn;
}
vpn_type = g_strstrip (vpn_type_ask);
if (!(st = nmc_string_is_valid (vpn_type, known_vpns, NULL))) {
if (!(st = nmc_string_is_valid (vpn_type, nmc_known_vpns, NULL))) {
printf (_("Warning: 'vpn-type': %s not known.\n"), vpn_type);
st = vpn_type;
}
@ -5042,12 +5036,138 @@ update_connection (gboolean persistent,
nm_remote_connection_commit_changes_unsaved (connection, callback, user_data);
}
static char *
gen_func_vpn_types (char *text, int state)
{
return nmc_rl_gen_func_basic (text, state, nmc_known_vpns);
}
static char *
gen_func_bool_values_l10n (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_ib_type (char *text, int state)
{
const char *words[] = { "datagram", "connected", NULL };
return nmc_rl_gen_func_basic (text, state, words);
}
static char *
gen_func_bt_type (char *text, int state)
{
const char *words[] = { "panu", "dun-gsm", "dun-cdma", NULL };
return nmc_rl_gen_func_basic (text, state, words);
}
static char *
gen_func_bond_mode (char *text, int state)
{
const char *words[] = { "balance-rr", "active-backup", "balance-xor", "broadcast",
"802.3ad", "balance-tlb", "balance-alb", NULL };
return nmc_rl_gen_func_basic (text, state, words);
}
static char *
gen_func_bond_mon_mode (char *text, int state)
{
const char *words[] = { "miimon", "arp", NULL };
return nmc_rl_gen_func_basic (text, state, words);
}
static char *
gen_func_master_ifnames (char *text, int state)
{
GSList *iter;
GPtrArray *ifnames;
char *ret;
NMConnection *con;
NMSettingConnection *s_con;
const char *con_type, *ifname;
if (!nm_cli.system_connections)
return NULL;
/* Disable appending space after completion */
rl_completion_append_character = '\0';
ifnames = g_ptr_array_sized_new (20);
for (iter = nm_cli.system_connections; iter; iter = g_slist_next (iter)) {
con = NM_CONNECTION (iter->data);
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_virtual_iface_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
is_single_word (const char* line)
{
size_t n1, n2, n3;
n1 = strspn (line, " \t");
n2 = strcspn (line+n1, " \t\0") + n1;
n3 = strspn (line+n2, " \t");
if (n3 == 0)
return TRUE;
else
return FALSE;
}
static char **
nmcli_con_add_tab_completion (char *text, int start, int end)
{
char **match_array = NULL;
CPFunction *generator_func = NULL;
/* Disable readline's default filename completion */
rl_attempted_completion_over = 1;
return NULL;
/* Restore standard append character to space */
rl_completion_append_character = ' ';
if (!is_single_word (rl_line_buffer))
return NULL;
if (g_strcmp0 (rl_prompt, PROMPT_CON_TYPE) == 0)
generator_func = gen_connection_types;
else if (g_strcmp0 (rl_prompt, PROMPT_VPN_TYPE) == 0)
generator_func = gen_func_vpn_types;
else if ( g_strcmp0 (rl_prompt, PROMPT_BOND_MASTER) == 0
|| g_strcmp0 (rl_prompt, PROMPT_TEAM_MASTER) == 0
|| g_strcmp0 (rl_prompt, PROMPT_BRIDGE_MASTER) == 0)
generator_func = gen_func_master_ifnames;
else if ( g_str_has_suffix (rl_prompt, prompt_yes_no (TRUE, NULL))
|| g_str_has_suffix (rl_prompt, prompt_yes_no (TRUE, ":"))
|| g_str_has_suffix (rl_prompt, prompt_yes_no (FALSE, NULL))
|| g_str_has_suffix (rl_prompt, prompt_yes_no (FALSE, ":")))
generator_func = gen_func_bool_values_l10n;
else if (g_str_has_suffix (rl_prompt, PROMPT_IB_MODE))
generator_func = gen_func_ib_type;
else if (g_str_has_suffix (rl_prompt, PROMPT_BT_TYPE))
generator_func = gen_func_bt_type;
else if (g_str_has_prefix (rl_prompt, PROMPT_BOND_MODE))
generator_func = gen_func_bond_mode;
else if (g_str_has_suffix (rl_prompt, PROMPT_BOND_MON_MODE))
generator_func = gen_func_bond_mon_mode;
if (generator_func)
match_array = rl_completion_matches (text, generator_func);
return match_array;
}
static NMCResultCode
@ -5091,7 +5211,7 @@ do_connection_add (NmCli *nmc, int argc, char **argv)
if (!type && nmc->ask) {
char *types_tmp = get_valid_options_string (nmc_valid_connection_types);
printf ("Valid types: [%s]\n", types_tmp);
type = type_ask = nmc_readline (_("Connection type: "));
type = type_ask = nmc_readline (PROMPT_CON_TYPE);
g_free (types_tmp);
}
if (!type) {
@ -5099,6 +5219,7 @@ do_connection_add (NmCli *nmc, int argc, char **argv)
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
goto error;
}
type = g_strstrip (type_ask);
if (!(setting_name = check_valid_name (type, nmc_valid_connection_types, &error))) {
g_string_printf (nmc->return_text, _("Error: invalid connection type; %s."),
@ -6777,10 +6898,11 @@ confirm_connection_saving (NMConnection *local, NMConnection *remote)
if (ac_local && !ac_remote) {
char *answer;
answer = nmc_get_user_input (_("Saving the connection with 'autoconnect=yes'. "
"That might result in an immediate activation of the connection.\n"
"Do you still want to save? [yes] "));
if (!answer || matches (answer, "yes") == 0)
answer = nmc_readline (_("Saving the connection with 'autoconnect=yes'. "
"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) == 0)
confirmed = TRUE;
else
confirmed = FALSE;