about summary refs log tree commit diff
path: root/cli/src
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2014-07-06 02:16:10 +0200
committerMichael Biebl <biebl@debian.org>2014-07-06 02:16:10 +0200
commit33491bc4279481db8ae47213e34a6d695a0e8830 (patch)
tree097d2b0fdff3fae6885381ae5e57a182cd8cbbba /cli/src
parent59c3714a494c3b3765657c0551ad82842d98a7d2 (diff)
Imported Upstream version 0.9.10.0 upstream/0.9.10.0
Diffstat (limited to 'cli/src')
-rw-r--r--cli/src/Makefile.am5
-rw-r--r--cli/src/Makefile.in147
-rw-r--r--cli/src/common.c785
-rw-r--r--cli/src/common.h33
-rw-r--r--cli/src/connections.c8455
-rw-r--r--cli/src/connections.h2
-rw-r--r--cli/src/devices.c2095
-rw-r--r--cli/src/network-manager.c920
-rw-r--r--cli/src/network-manager.h6
-rw-r--r--cli/src/nmcli.c149
-rw-r--r--cli/src/nmcli.h56
-rw-r--r--cli/src/settings.c7434
-rw-r--r--cli/src/settings.h63
-rw-r--r--cli/src/utils.c799
-rw-r--r--cli/src/utils.h67
15 files changed, 17579 insertions, 3437 deletions
diff --git a/cli/src/Makefile.am b/cli/src/Makefile.am
index 1cd2a006..e61c0368 100644
--- a/cli/src/Makefile.am
+++ b/cli/src/Makefile.am
@@ -1,7 +1,7 @@
 bin_PROGRAMS = \
 	nmcli
 
-nmcli_CPPFLAGS = \
+AM_CPPFLAGS = \
 	-I${top_srcdir} \
 	-I${top_srcdir}/include \
 	-I${top_builddir}/include \
@@ -10,6 +10,8 @@ nmcli_CPPFLAGS = \
 	-I${top_srcdir}/libnm-glib \
 	$(DBUS_CFLAGS) \
 	$(GLIB_CFLAGS) \
+	-DG_LOG_DOMAIN=\""nmcli"\" \
+	-DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \
 	-DNMCLI_LOCALEDIR=\"$(datadir)/locale\"
 
 nmcli_SOURCES = \
@@ -31,6 +33,7 @@ nmcli_SOURCES = \
 nmcli_LDADD = \
 	$(DBUS_LIBS) \
 	$(GLIB_LIBS) \
+	$(READLINE_LIBS) \
 	$(top_builddir)/libnm-util/libnm-util.la \
 	$(top_builddir)/libnm-glib/libnm-glib.la
 
diff --git a/cli/src/Makefile.in b/cli/src/Makefile.in
index 46846571..8f3129c7 100644
--- a/cli/src/Makefile.in
+++ b/cli/src/Makefile.in
@@ -83,7 +83,8 @@ subdir = cli/src
 DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
 	$(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
+	$(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/gettext.m4 \
 	$(top_srcdir)/m4/gnome-code-coverage.m4 \
 	$(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/iconv.m4 \
@@ -103,14 +104,13 @@ CONFIG_CLEAN_FILES =
 CONFIG_CLEAN_VPATH_FILES =
 am__installdirs = "$(DESTDIR)$(bindir)"
 PROGRAMS = $(bin_PROGRAMS)
-am_nmcli_OBJECTS = nmcli-common.$(OBJEXT) nmcli-connections.$(OBJEXT) \
-	nmcli-devices.$(OBJEXT) nmcli-network-manager.$(OBJEXT) \
-	nmcli-settings.$(OBJEXT) nmcli-nmcli.$(OBJEXT) \
-	nmcli-utils.$(OBJEXT)
+am_nmcli_OBJECTS = common.$(OBJEXT) connections.$(OBJEXT) \
+	devices.$(OBJEXT) network-manager.$(OBJEXT) settings.$(OBJEXT) \
+	nmcli.$(OBJEXT) utils.$(OBJEXT)
 nmcli_OBJECTS = $(am_nmcli_OBJECTS)
 am__DEPENDENCIES_1 =
 nmcli_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
-	$(top_builddir)/libnm-util/libnm-util.la \
+	$(am__DEPENDENCIES_1) $(top_builddir)/libnm-util/libnm-util.la \
 	$(top_builddir)/libnm-glib/libnm-glib.la
 AM_V_lt = $(am__v_lt_@AM_V@)
 am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
@@ -202,12 +202,15 @@ CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
 DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
+DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
 DBUS_LIBS = @DBUS_LIBS@
 DBUS_SYS_DIR = @DBUS_SYS_DIR@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
 DHCLIENT_PATH = @DHCLIENT_PATH@
 DHCPCD_PATH = @DHCPCD_PATH@
+DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@
 DLLTOOL = @DLLTOOL@
 DNSMASQ_PATH = @DNSMASQ_PATH@
 DSYMUTIL = @DSYMUTIL@
@@ -232,7 +235,6 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
-GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -277,12 +279,16 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
+LIBNDP_CFLAGS = @LIBNDP_CFLAGS@
+LIBNDP_LIBS = @LIBNDP_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
 LIBSOUP_LIBS = @LIBSOUP_LIBS@
+LIBTEAMDCTL_CFLAGS = @LIBTEAMDCTL_CFLAGS@
+LIBTEAMDCTL_LIBS = @LIBTEAMDCTL_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -299,6 +305,8 @@ MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
+NEWT_CFLAGS = @NEWT_CFLAGS@
+NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
@@ -326,11 +334,16 @@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
 POLKIT_CFLAGS = @POLKIT_CFLAGS@
 POLKIT_LIBS = @POLKIT_LIBS@
 POSUB = @POSUB@
+PPPD_PATH = @PPPD_PATH@
 PPPD_PLUGIN_DIR = @PPPD_PLUGIN_DIR@
+PPPOE_PATH = @PPPOE_PATH@
 QT_CFLAGS = @QT_CFLAGS@
 QT_LIBS = @QT_LIBS@
 RANLIB = @RANLIB@
+READLINE_LIBS = @READLINE_LIBS@
 SED = @SED@
+SELINUX_CFLAGS = @SELINUX_CFLAGS@
+SELINUX_LIBS = @SELINUX_LIBS@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
@@ -345,6 +358,7 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VALGRIND_RULES = @VALGRIND_RULES@
 VAPIGEN = @VAPIGEN@
 VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
 VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
@@ -407,6 +421,7 @@ psdir = @psdir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
+subdirs = @subdirs@
 sysconfdir = @sysconfdir@
 systemdsystemunitdir = @systemdsystemunitdir@
 target_alias = @target_alias@
@@ -417,7 +432,8 @@ with_dhclient = @with_dhclient@
 with_dhcpcd = @with_dhcpcd@
 with_netconfig = @with_netconfig@
 with_resolvconf = @with_resolvconf@
-nmcli_CPPFLAGS = \
+with_valgrind = @with_valgrind@
+AM_CPPFLAGS = \
 	-I${top_srcdir} \
 	-I${top_srcdir}/include \
 	-I${top_builddir}/include \
@@ -426,6 +442,8 @@ nmcli_CPPFLAGS = \
 	-I${top_srcdir}/libnm-glib \
 	$(DBUS_CFLAGS) \
 	$(GLIB_CFLAGS) \
+	-DG_LOG_DOMAIN=\""nmcli"\" \
+	-DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \
 	-DNMCLI_LOCALEDIR=\"$(datadir)/locale\"
 
 nmcli_SOURCES = \
@@ -447,6 +465,7 @@ nmcli_SOURCES = \
 nmcli_LDADD = \
 	$(DBUS_LIBS) \
 	$(GLIB_LIBS) \
+	$(READLINE_LIBS) \
 	$(top_builddir)/libnm-util/libnm-util.la \
 	$(top_builddir)/libnm-glib/libnm-glib.la
 
@@ -544,13 +563,13 @@ mostlyclean-compile:
 distclean-compile:
 	-rm -f *.tab.c
 
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmcli-common.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmcli-connections.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmcli-devices.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmcli-network-manager.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmcli-nmcli.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmcli-settings.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmcli-utils.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/connections.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/devices.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/network-manager.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmcli.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/settings.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utils.Po@am__quote@
 
 .c.o:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -573,104 +592,6 @@ distclean-compile:
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
 
-nmcli-common.o: common.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nmcli_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nmcli-common.o -MD -MP -MF $(DEPDIR)/nmcli-common.Tpo -c -o nmcli-common.o `test -f 'common.c' || echo '$(srcdir)/'`common.c
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/nmcli-common.Tpo $(DEPDIR)/nmcli-common.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='common.c' object='nmcli-common.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nmcli_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nmcli-common.o `test -f 'common.c' || echo '$(srcdir)/'`common.c
-
-nmcli-common.obj: common.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nmcli_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nmcli-common.obj -MD -MP -MF $(DEPDIR)/nmcli-common.Tpo -c -o nmcli-common.obj `if test -f 'common.c'; then $(CYGPATH_W) 'common.c'; else $(CYGPATH_W) '$(srcdir)/common.c'; fi`
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/nmcli-common.Tpo $(DEPDIR)/nmcli-common.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='common.c' object='nmcli-common.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nmcli_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nmcli-common.obj `if test -f 'common.c'; then $(CYGPATH_W) 'common.c'; else $(CYGPATH_W) '$(srcdir)/common.c'; fi`
-
-nmcli-connections.o: connections.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nmcli_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nmcli-connections.o -MD -MP -MF $(DEPDIR)/nmcli-connections.Tpo -c -o nmcli-connections.o `test -f 'connections.c' || echo '$(srcdir)/'`connections.c
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/nmcli-connections.Tpo $(DEPDIR)/nmcli-connections.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='connections.c' object='nmcli-connections.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nmcli_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nmcli-connections.o `test -f 'connections.c' || echo '$(srcdir)/'`connections.c
-
-nmcli-connections.obj: connections.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nmcli_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nmcli-connections.obj -MD -MP -MF $(DEPDIR)/nmcli-connections.Tpo -c -o nmcli-connections.obj `if test -f 'connections.c'; then $(CYGPATH_W) 'connections.c'; else $(CYGPATH_W) '$(srcdir)/connections.c'; fi`
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/nmcli-connections.Tpo $(DEPDIR)/nmcli-connections.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='connections.c' object='nmcli-connections.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nmcli_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nmcli-connections.obj `if test -f 'connections.c'; then $(CYGPATH_W) 'connections.c'; else $(CYGPATH_W) '$(srcdir)/connections.c'; fi`
-
-nmcli-devices.o: devices.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nmcli_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nmcli-devices.o -MD -MP -MF $(DEPDIR)/nmcli-devices.Tpo -c -o nmcli-devices.o `test -f 'devices.c' || echo '$(srcdir)/'`devices.c
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/nmcli-devices.Tpo $(DEPDIR)/nmcli-devices.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='devices.c' object='nmcli-devices.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nmcli_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nmcli-devices.o `test -f 'devices.c' || echo '$(srcdir)/'`devices.c
-
-nmcli-devices.obj: devices.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nmcli_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nmcli-devices.obj -MD -MP -MF $(DEPDIR)/nmcli-devices.Tpo -c -o nmcli-devices.obj `if test -f 'devices.c'; then $(CYGPATH_W) 'devices.c'; else $(CYGPATH_W) '$(srcdir)/devices.c'; fi`
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/nmcli-devices.Tpo $(DEPDIR)/nmcli-devices.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='devices.c' object='nmcli-devices.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nmcli_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nmcli-devices.obj `if test -f 'devices.c'; then $(CYGPATH_W) 'devices.c'; else $(CYGPATH_W) '$(srcdir)/devices.c'; fi`
-
-nmcli-network-manager.o: network-manager.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nmcli_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nmcli-network-manager.o -MD -MP -MF $(DEPDIR)/nmcli-network-manager.Tpo -c -o nmcli-network-manager.o `test -f 'network-manager.c' || echo '$(srcdir)/'`network-manager.c
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/nmcli-network-manager.Tpo $(DEPDIR)/nmcli-network-manager.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='network-manager.c' object='nmcli-network-manager.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nmcli_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nmcli-network-manager.o `test -f 'network-manager.c' || echo '$(srcdir)/'`network-manager.c
-
-nmcli-network-manager.obj: network-manager.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nmcli_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nmcli-network-manager.obj -MD -MP -MF $(DEPDIR)/nmcli-network-manager.Tpo -c -o nmcli-network-manager.obj `if test -f 'network-manager.c'; then $(CYGPATH_W) 'network-manager.c'; else $(CYGPATH_W) '$(srcdir)/network-manager.c'; fi`
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/nmcli-network-manager.Tpo $(DEPDIR)/nmcli-network-manager.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='network-manager.c' object='nmcli-network-manager.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nmcli_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nmcli-network-manager.obj `if test -f 'network-manager.c'; then $(CYGPATH_W) 'network-manager.c'; else $(CYGPATH_W) '$(srcdir)/network-manager.c'; fi`
-
-nmcli-settings.o: settings.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nmcli_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nmcli-settings.o -MD -MP -MF $(DEPDIR)/nmcli-settings.Tpo -c -o nmcli-settings.o `test -f 'settings.c' || echo '$(srcdir)/'`settings.c
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/nmcli-settings.Tpo $(DEPDIR)/nmcli-settings.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='settings.c' object='nmcli-settings.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nmcli_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nmcli-settings.o `test -f 'settings.c' || echo '$(srcdir)/'`settings.c
-
-nmcli-settings.obj: settings.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nmcli_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nmcli-settings.obj -MD -MP -MF $(DEPDIR)/nmcli-settings.Tpo -c -o nmcli-settings.obj `if test -f 'settings.c'; then $(CYGPATH_W) 'settings.c'; else $(CYGPATH_W) '$(srcdir)/settings.c'; fi`
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/nmcli-settings.Tpo $(DEPDIR)/nmcli-settings.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='settings.c' object='nmcli-settings.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nmcli_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nmcli-settings.obj `if test -f 'settings.c'; then $(CYGPATH_W) 'settings.c'; else $(CYGPATH_W) '$(srcdir)/settings.c'; fi`
-
-nmcli-nmcli.o: nmcli.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nmcli_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nmcli-nmcli.o -MD -MP -MF $(DEPDIR)/nmcli-nmcli.Tpo -c -o nmcli-nmcli.o `test -f 'nmcli.c' || echo '$(srcdir)/'`nmcli.c
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/nmcli-nmcli.Tpo $(DEPDIR)/nmcli-nmcli.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='nmcli.c' object='nmcli-nmcli.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nmcli_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nmcli-nmcli.o `test -f 'nmcli.c' || echo '$(srcdir)/'`nmcli.c
-
-nmcli-nmcli.obj: nmcli.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nmcli_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nmcli-nmcli.obj -MD -MP -MF $(DEPDIR)/nmcli-nmcli.Tpo -c -o nmcli-nmcli.obj `if test -f 'nmcli.c'; then $(CYGPATH_W) 'nmcli.c'; else $(CYGPATH_W) '$(srcdir)/nmcli.c'; fi`
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/nmcli-nmcli.Tpo $(DEPDIR)/nmcli-nmcli.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='nmcli.c' object='nmcli-nmcli.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nmcli_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nmcli-nmcli.obj `if test -f 'nmcli.c'; then $(CYGPATH_W) 'nmcli.c'; else $(CYGPATH_W) '$(srcdir)/nmcli.c'; fi`
-
-nmcli-utils.o: utils.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nmcli_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nmcli-utils.o -MD -MP -MF $(DEPDIR)/nmcli-utils.Tpo -c -o nmcli-utils.o `test -f 'utils.c' || echo '$(srcdir)/'`utils.c
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/nmcli-utils.Tpo $(DEPDIR)/nmcli-utils.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='utils.c' object='nmcli-utils.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nmcli_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nmcli-utils.o `test -f 'utils.c' || echo '$(srcdir)/'`utils.c
-
-nmcli-utils.obj: utils.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nmcli_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nmcli-utils.obj -MD -MP -MF $(DEPDIR)/nmcli-utils.Tpo -c -o nmcli-utils.obj `if test -f 'utils.c'; then $(CYGPATH_W) 'utils.c'; else $(CYGPATH_W) '$(srcdir)/utils.c'; fi`
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/nmcli-utils.Tpo $(DEPDIR)/nmcli-utils.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='utils.c' object='nmcli-utils.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nmcli_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nmcli-utils.obj `if test -f 'utils.c'; then $(CYGPATH_W) 'utils.c'; else $(CYGPATH_W) '$(srcdir)/utils.c'; fi`
-
 mostlyclean-libtool:
 	-rm -f *.lo
 
diff --git a/cli/src/common.c b/cli/src/common.c
index 15ddcada..e6712a8d 100644
--- a/cli/src/common.c
+++ b/cli/src/common.c
@@ -16,59 +16,68 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * (C) Copyright 2012 Red Hat, Inc.
+ * (C) Copyright 2012 - 2014 Red Hat, Inc.
  */
 
 #include "config.h"
 
 #include <glib.h>
 #include <glib/gi18n.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <readline/readline.h>
+#include <readline/history.h>
 
 #include "common.h"
 #include "utils.h"
 
 /* Available fields for IPv4 group */
-static NmcOutputField nmc_fields_ip4_config[] = {
-	{"GROUP",      N_("GROUP"),       15, NULL, 0},  /* 0 */
-	{"ADDRESS",    N_("ADDRESS"),     68, NULL, 0},  /* 1 */
-	{"ROUTE",      N_("ROUTE"),       68, NULL, 0},  /* 2 */
-	{"DNS",        N_("DNS"),         35, NULL, 0},  /* 3 */
-	{"DOMAIN",     N_("DOMAIN"),      35, NULL, 0},  /* 4 */
-	{"WINS",       N_("WINS"),        20, NULL, 0},  /* 5 */
-	{NULL,         NULL,               0, NULL, 0}
+NmcOutputField nmc_fields_ip4_config[] = {
+	{"GROUP",      N_("GROUP"),       15},  /* 0 */
+	{"ADDRESS",    N_("ADDRESS"),     68},  /* 1 */
+	{"ROUTE",      N_("ROUTE"),       68},  /* 2 */
+	{"DNS",        N_("DNS"),         35},  /* 3 */
+	{"DOMAIN",     N_("DOMAIN"),      35},  /* 4 */
+	{"WINS",       N_("WINS"),        20},  /* 5 */
+	{NULL,         NULL,               0}
 };
 #define NMC_FIELDS_IP4_CONFIG_ALL     "GROUP,ADDRESS,ROUTE,DNS,DOMAIN,WINS"
 
 /* Available fields for DHCPv4 group */
-static NmcOutputField nmc_fields_dhcp4_config[] = {
-	{"GROUP",      N_("GROUP"),       15, NULL, 0},  /* 0 */
-	{"OPTION",     N_("OPTION"),      80, NULL, 0},  /* 1 */
-	{NULL,         NULL,               0, NULL, 0}
+NmcOutputField nmc_fields_dhcp4_config[] = {
+	{"GROUP",      N_("GROUP"),       15},  /* 0 */
+	{"OPTION",     N_("OPTION"),      80},  /* 1 */
+	{NULL,         NULL,               0}
 };
 #define NMC_FIELDS_DHCP4_CONFIG_ALL     "GROUP,OPTION"
 
 /* Available fields for IPv6 group */
-static NmcOutputField nmc_fields_ip6_config[] = {
-	{"GROUP",      N_("GROUP"),       15, NULL, 0},  /* 0 */
-	{"ADDRESS",    N_("ADDRESS"),     95, NULL, 0},  /* 1 */
-	{"ROUTE",      N_("ROUTE"),       95, NULL, 0},  /* 2 */
-	{"DNS",        N_("DNS"),         60, NULL, 0},  /* 3 */
-	{"DOMAIN",     N_("DOMAIN"),      35, NULL, 0},  /* 4 */
-	{NULL,         NULL,               0, NULL, 0}
+NmcOutputField nmc_fields_ip6_config[] = {
+	{"GROUP",      N_("GROUP"),       15},  /* 0 */
+	{"ADDRESS",    N_("ADDRESS"),     95},  /* 1 */
+	{"ROUTE",      N_("ROUTE"),       95},  /* 2 */
+	{"DNS",        N_("DNS"),         60},  /* 3 */
+	{"DOMAIN",     N_("DOMAIN"),      35},  /* 4 */
+	{NULL,         NULL,               0}
 };
 #define NMC_FIELDS_IP6_CONFIG_ALL     "GROUP,ADDRESS,ROUTE,DNS,DOMAIN"
 
 /* Available fields for DHCPv6 group */
-static NmcOutputField nmc_fields_dhcp6_config[] = {
-	{"GROUP",      N_("GROUP"),       15, NULL, 0},  /* 0 */
-	{"OPTION",     N_("OPTION"),      80, NULL, 0},  /* 1 */
-	{NULL,         NULL,               0, NULL, 0}
+NmcOutputField nmc_fields_dhcp6_config[] = {
+	{"GROUP",      N_("GROUP"),       15},  /* 0 */
+	{"OPTION",     N_("OPTION"),      80},  /* 1 */
+	{NULL,         NULL,               0}
 };
 #define NMC_FIELDS_DHCP6_CONFIG_ALL     "GROUP,OPTION"
 
 
 gboolean
-print_ip4_config (NMIP4Config *cfg4, NmCli *nmc, const char *group_prefix)
+print_ip4_config (NMIP4Config *cfg4,
+                  NmCli *nmc,
+                  const char *group_prefix,
+                  const char *one_field)
 {
 	GSList *list, *iter;
 	const GArray *array;
@@ -79,17 +88,18 @@ print_ip4_config (NMIP4Config *cfg4, NmCli *nmc, const char *group_prefix)
 	char **domain_arr = NULL;
 	char **wins_arr = NULL;
 	int i = 0;
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
 
 	if (cfg4 == NULL)
 		return FALSE;
 
-	nmc->allowed_fields = nmc_fields_ip4_config;
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_IP4_CONFIG_ALL, nmc->allowed_fields, NULL);
-	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
+	tmpl = nmc_fields_ip4_config;
+	tmpl_len = sizeof (nmc_fields_ip4_config);
+	nmc->print_fields.indices = parse_output_fields (one_field ? one_field : NMC_FIELDS_IP4_CONFIG_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);
 
 	/* addresses */
 	list = (GSList *) nm_ip4_config_get_addresses (cfg4);
@@ -144,7 +154,7 @@ print_ip4_config (NMIP4Config *cfg4, NmCli *nmc, const char *group_prefix)
 	if (ptr_array) {
 		domain_arr = g_new (char *, ptr_array->len + 1);
 		for (i = 0; i < ptr_array->len; i++)
-			domain_arr[i] = g_ptr_array_index (ptr_array, i);
+			domain_arr[i] = g_strdup (g_ptr_array_index (ptr_array, i));
 
 		domain_arr[i] = NULL;
 	}
@@ -159,27 +169,28 @@ print_ip4_config (NMIP4Config *cfg4, NmCli *nmc, const char *group_prefix)
 		wins_arr[i] = NULL;
 	}
 
-	set_val_str (nmc->allowed_fields, 0, group_prefix);
-	set_val_arr (nmc->allowed_fields, 1, (const char **) addr_arr);
-	set_val_arr (nmc->allowed_fields, 2, (const char **) route_arr);
-	set_val_arr (nmc->allowed_fields, 3, (const char **) dns_arr);
-	set_val_arr (nmc->allowed_fields, 4, (const char **) domain_arr);
-	set_val_arr (nmc->allowed_fields, 5, (const char **) wins_arr);
+	arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+	set_val_strc (arr, 0, group_prefix);
+	set_val_arr  (arr, 1, addr_arr);
+	set_val_arr  (arr, 2, route_arr);
+	set_val_arr  (arr, 3, dns_arr);
+	set_val_arr  (arr, 4, domain_arr);
+	set_val_arr  (arr, 5, wins_arr);
+	g_ptr_array_add (nmc->output_data, arr);
 
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+	print_data (nmc); /* Print all data */
 
-	g_strfreev (addr_arr);
-	g_strfreev (route_arr);
-	g_strfreev (dns_arr);
-	g_free (domain_arr);
-	g_strfreev (wins_arr);
+	/* Remove any previous data */
+	nmc_empty_output_fields (nmc);
 
 	return TRUE;
 }
 
 gboolean
-print_ip6_config (NMIP6Config *cfg6, NmCli *nmc, const char *group_prefix)
+print_ip6_config (NMIP6Config *cfg6,
+                  NmCli *nmc,
+                  const char *group_prefix,
+                  const char *one_field)
 {
 	GSList *list, *iter;
 	const GPtrArray *ptr_array;
@@ -188,17 +199,18 @@ print_ip6_config (NMIP6Config *cfg6, NmCli *nmc, const char *group_prefix)
 	char **dns_arr = NULL;
 	char **domain_arr = NULL;
 	int i = 0;
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
 
 	if (cfg6 == NULL)
 		return FALSE;
 
-	nmc->allowed_fields = nmc_fields_ip6_config;
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_IP6_CONFIG_ALL, nmc->allowed_fields, NULL);
-	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
+	tmpl = nmc_fields_ip6_config;
+	tmpl_len = sizeof (nmc_fields_ip6_config);
+	nmc->print_fields.indices = parse_output_fields (one_field ? one_field : NMC_FIELDS_IP6_CONFIG_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);
 
 	/* addresses */
 	list = (GSList *) nm_ip6_config_get_addresses (cfg6);
@@ -252,35 +264,36 @@ print_ip6_config (NMIP6Config *cfg6, NmCli *nmc, const char *group_prefix)
 	if (ptr_array) {
 		domain_arr = g_new (char *, ptr_array->len + 1);
 		for (i = 0; i < ptr_array->len; i++)
-			domain_arr[i] = g_ptr_array_index (ptr_array, i);
+			domain_arr[i] = g_strdup (g_ptr_array_index (ptr_array, i));
 
 		domain_arr[i] = NULL;
 	}
 
-	set_val_str (nmc->allowed_fields, 0, group_prefix);
-	set_val_arr (nmc->allowed_fields, 1, (const char **) addr_arr);
-	set_val_arr (nmc->allowed_fields, 2, (const char **) route_arr);
-	set_val_arr (nmc->allowed_fields, 3, (const char **) dns_arr);
-	set_val_arr (nmc->allowed_fields, 4, (const char **) domain_arr);
+	arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+	set_val_strc (arr, 0, group_prefix);
+	set_val_arr  (arr, 1, addr_arr);
+	set_val_arr  (arr, 2, route_arr);
+	set_val_arr  (arr, 3, dns_arr);
+	set_val_arr  (arr, 4, domain_arr);
+	g_ptr_array_add (nmc->output_data, arr);
 
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+	print_data (nmc); /* Print all data */
 
-	g_strfreev (addr_arr);
-	g_strfreev (route_arr);
-	g_strfreev (dns_arr);
-	g_free (domain_arr);
+	/* Remove any previous data */
+	nmc_empty_output_fields (nmc);
 
 	return TRUE;
 }
 
 gboolean
-print_dhcp4_config (NMDHCP4Config *dhcp4, NmCli *nmc, const char *group_prefix)
+print_dhcp4_config (NMDHCP4Config *dhcp4,
+                    NmCli *nmc,
+                    const char *group_prefix,
+                    const char *one_field)
 {
 	GHashTable *table;
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
 
 	if (dhcp4 == NULL)
 		return FALSE;
@@ -292,10 +305,12 @@ print_dhcp4_config (NMDHCP4Config *dhcp4, NmCli *nmc, const char *group_prefix)
 		char **options_arr = NULL;
 		int i = 0;
 
-		nmc->allowed_fields = nmc_fields_dhcp4_config;
-		nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-		nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_DHCP4_CONFIG_ALL, nmc->allowed_fields, NULL);
-		print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
+		tmpl = nmc_fields_dhcp4_config;
+		tmpl_len = sizeof (nmc_fields_dhcp4_config);
+		nmc->print_fields.indices = parse_output_fields (one_field ? one_field : NMC_FIELDS_DHCP4_CONFIG_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);
 
 		options_arr = g_new (char *, g_hash_table_size (table) + 1);
 		g_hash_table_iter_init (&table_iter, table);
@@ -303,13 +318,15 @@ print_dhcp4_config (NMDHCP4Config *dhcp4, NmCli *nmc, const char *group_prefix)
 			options_arr[i++] = g_strdup_printf ("%s = %s", (char *) key, (char *) value);
 		options_arr[i] = NULL;
 
-		set_val_str (nmc->allowed_fields, 0, group_prefix);
-		set_val_arr (nmc->allowed_fields, 1, (const char **) options_arr);
+		arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+		set_val_strc (arr, 0, group_prefix);
+		set_val_arr  (arr, 1, options_arr);
+		g_ptr_array_add (nmc->output_data, arr);
 
-		nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-		print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+		print_data (nmc); /* Print all data */
 
-		g_strfreev (options_arr);
+		/* Remove any previous data */
+		nmc_empty_output_fields (nmc);
 
 		return TRUE;
 	}
@@ -317,12 +334,14 @@ print_dhcp4_config (NMDHCP4Config *dhcp4, NmCli *nmc, const char *group_prefix)
 }
 
 gboolean
-print_dhcp6_config (NMDHCP6Config *dhcp6, NmCli *nmc, const char *group_prefix)
+print_dhcp6_config (NMDHCP6Config *dhcp6,
+                    NmCli *nmc,
+                    const char *group_prefix,
+                    const char *one_field)
 {
 	GHashTable *table;
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
 
 	if (dhcp6 == NULL)
 		return FALSE;
@@ -334,10 +353,12 @@ print_dhcp6_config (NMDHCP6Config *dhcp6, NmCli *nmc, const char *group_prefix)
 		char **options_arr = NULL;
 		int i = 0;
 
-		nmc->allowed_fields = nmc_fields_dhcp6_config;
-		nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-		nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_DHCP6_CONFIG_ALL, nmc->allowed_fields, NULL);
-		print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
+		tmpl = nmc_fields_dhcp6_config;
+		tmpl_len = sizeof (nmc_fields_dhcp6_config);
+		nmc->print_fields.indices = parse_output_fields (one_field ? one_field : NMC_FIELDS_DHCP6_CONFIG_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);
 
 		options_arr = g_new (char *, g_hash_table_size (table) + 1);
 		g_hash_table_iter_init (&table_iter, table);
@@ -345,19 +366,313 @@ print_dhcp6_config (NMDHCP6Config *dhcp6, NmCli *nmc, const char *group_prefix)
 			options_arr[i++] = g_strdup_printf ("%s = %s", (char *) key, (char *) value);
 		options_arr[i] = NULL;
 
-		set_val_str (nmc->allowed_fields, 0, group_prefix);
-		set_val_arr (nmc->allowed_fields, 1, (const char **) options_arr);
+		arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+		set_val_strc (arr, 0, group_prefix);
+		set_val_arr  (arr, 1, options_arr);
+		g_ptr_array_add (nmc->output_data, arr);
 
-		nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-		print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+		print_data (nmc); /* Print all data */
 
-		g_strfreev (options_arr);
+		/* Remove any previous data */
+		nmc_empty_output_fields (nmc);
 
 		return TRUE;
 	}
 	return FALSE;
 }
 
+/*
+ * Parse IPv4 address from string to NMIP4Address stucture.
+ * ip_str is the IPv4 address in the form address/prefix
+ * gw_str is the gateway address (it is optional)
+ */
+NMIP4Address *
+nmc_parse_and_build_ip4_address (const char *ip_str, const char *gw_str, GError **error)
+{
+	NMIP4Address *addr = NULL;
+	guint32 ip4_addr, gw_addr;
+	char *tmp;
+	char *plen;
+	long int prefix;
+
+	g_return_val_if_fail (ip_str != NULL, NULL);
+	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+	tmp = g_strdup (ip_str);
+	plen = strchr (tmp, '/');  /* prefix delimiter */
+	if (plen)
+		*plen++ = '\0';
+
+	if (inet_pton (AF_INET, tmp, &ip4_addr) < 1) {
+		g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+		             _("invalid IPv4 address '%s'"), tmp);
+		goto finish;
+	}
+
+	prefix = 32;
+	if (plen) {
+		if (!nmc_string_to_int (plen, TRUE, 1, 32, &prefix)) {
+			g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+			             _("invalid prefix '%s'; <1-32> allowed"), plen);
+			goto finish;
+		}
+	}
+
+	if (inet_pton (AF_INET, gw_str ? gw_str : "0.0.0.0", &gw_addr) < 1) {
+		g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+		             _("invalid gateway '%s'"), gw_str);
+		goto finish;
+	}
+
+	addr = nm_ip4_address_new ();
+	nm_ip4_address_set_address (addr, ip4_addr);
+	nm_ip4_address_set_prefix (addr, (guint32) prefix);
+	nm_ip4_address_set_gateway (addr, gw_addr);
+
+finish:
+	g_free (tmp);
+	return addr;
+}
+
+/*
+ * Parse IPv6 address from string to NMIP6Address stucture.
+ * ip_str is the IPv6 address in the form address/prefix
+ * gw_str is the gateway address (it is optional)
+ */
+NMIP6Address *
+nmc_parse_and_build_ip6_address (const char *ip_str, const char *gw_str, GError **error)
+{
+	NMIP6Address *addr = NULL;
+	struct in6_addr ip_addr, gw_addr;
+	char *tmp;
+	char *plen;
+	long int prefix;
+
+	g_return_val_if_fail (ip_str != NULL, NULL);
+	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+	tmp = g_strdup (ip_str);
+	plen = strchr (tmp, '/');  /* prefix delimiter */
+	if (plen)
+		*plen++ = '\0';
+
+	if (inet_pton (AF_INET6, tmp, &ip_addr) < 1) {
+		g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+		             _("invalid IPv6 address '%s'"), tmp);
+		goto finish;
+	}
+
+	prefix = 128;
+	if (plen) {
+		if (!nmc_string_to_int (plen, TRUE, 1, 128, &prefix)) {
+			g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+			             _("invalid prefix '%s'; <1-128> allowed"), plen);
+			goto finish;
+		}
+	}
+
+	if (inet_pton (AF_INET6, gw_str ? gw_str : "::", &gw_addr) < 1) {
+		g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+		             _("invalid gateway '%s'"), gw_str);
+		goto finish;
+	}
+
+	addr = nm_ip6_address_new ();
+	nm_ip6_address_set_address (addr, &ip_addr);
+	nm_ip6_address_set_prefix (addr, (guint32) prefix);
+	nm_ip6_address_set_gateway (addr, &gw_addr);
+
+finish:
+	g_free (tmp);
+	return addr;
+}
+
+typedef struct {
+	long int prefix;
+	long int metric;
+	union _IpDest {
+		guint32 ip4_dst;
+		struct in6_addr ip6_dst;
+	} dst;
+	union _IpNextHop {
+		guint32 ip4_nh;
+		struct in6_addr ip6_nh;
+	} nh;
+} ParsedRoute;
+
+/*
+ * _parse_and_build_route:
+ * @family: AF_INET or AF_INET6
+ * @first: the route destination in the form of "address/prefix"
+     (/prefix is optional)
+ * @second: (allow-none): next hop address, if third is not NULL. Otherwise it could be
+     either next hop address or metric. (It can be NULL when @third is NULL).
+ * @third: (allow-none): route metric
+ * @out: (out): route struct to fill
+ * @error: location to store GError
+ *
+ * Parse route from strings and fill @out parameter.
+ *
+ * Returns: %TRUE on success, %FALSE on failure
+ */
+static gboolean
+_parse_and_build_route (int family,
+                        const char *first,
+                        const char *second,
+                        const char *third,
+                        ParsedRoute *out,
+                        GError **error)
+{
+	int max_prefix;
+	char *tmp, *plen;
+	gboolean success = FALSE;
+
+	g_return_val_if_fail (family == AF_INET || family == AF_INET6, FALSE);
+	g_return_val_if_fail (first != NULL, FALSE);
+	g_return_val_if_fail (second || !third, FALSE);
+	g_return_val_if_fail (out, FALSE);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	max_prefix = (family == AF_INET) ? 32 : 128;
+	/* initialize default values */
+	out->prefix = max_prefix;
+	out->metric = 0;
+	if (family == AF_INET)
+		out->nh.ip4_nh = 0;
+	else
+		out->nh.ip6_nh = in6addr_any;
+
+	tmp = g_strdup (first);
+	plen = strchr (tmp, '/');  /* prefix delimiter */
+	if (plen)
+		*plen++ = '\0';
+
+	if (inet_pton (family, tmp, family == AF_INET ? (void *) &out->dst.ip4_dst : (void *) &out->dst.ip6_dst) < 1) {
+		g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+		             _("invalid route destination address '%s'"), tmp);
+		goto finish;
+	}
+
+	if (plen) {
+		if (!nmc_string_to_int (plen, TRUE, 1, max_prefix, &out->prefix)) {
+			g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+			             _("invalid prefix '%s'; <1-%d> allowed"),
+			             plen, max_prefix);
+			goto finish;
+		}
+	}
+
+	if (second) {
+		if (inet_pton (family, second, family == AF_INET ? (void *) &out->nh.ip4_nh : (void *) &out->nh.ip6_nh) < 1) {
+			if (third) {
+				g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+				             _("invalid next hop address '%s'"), second);
+				goto finish;
+			} else {
+				/* 'second' can be a metric */
+				if (!nmc_string_to_int (second, TRUE, 0, G_MAXUINT32, &out->metric)) {
+					g_set_error (error, 1, 0, _("the second component of route ('%s') is neither "
+					                            "a next hop address nor a metric"), second);
+					goto finish;
+				}
+			}
+		}
+	}
+
+	if (third) {
+		if (!nmc_string_to_int (third, TRUE, 0, G_MAXUINT32, &out->metric)) {
+			g_set_error (error, 1, 0, _("invalid metric '%s'"), third);
+			goto finish;
+		}
+	}
+
+	/* We don't accept default routes as NetworkManager handles it itself */
+	if (   (family == AF_INET && out->dst.ip4_dst == 0)
+	    || (family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED (&out->dst.ip6_dst))) {
+		g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+		                     _("default route cannot be added (NetworkManager handles it by itself)"));
+		goto finish;
+	}
+
+	success = TRUE;
+
+finish:
+	g_free (tmp);
+	return success;
+}
+
+/*
+ * nmc_parse_and_build_ip4_route:
+ * @first: the IPv4 route destination in the form of "address/prefix"
+     (/prefix is optional)
+ * @second: (allow-none): next hop address, if third is not NULL. Otherwise it could be
+     either next hop address or metric. (It can be NULL when @third is NULL).
+ * @third: (allow-none): route metric
+ * @error: location to store GError
+ *
+ * Parse IPv4 route from strings to NMIP4Route stucture.
+ *
+ * Returns: route as a NMIP4Route object, or %NULL on failure
+ */
+NMIP4Route *
+nmc_parse_and_build_ip4_route (const char *first,
+                               const char *second,
+                               const char *third,
+                               GError **error)
+{
+	ParsedRoute tmp_route;
+	NMIP4Route *route = NULL;
+
+	g_return_val_if_fail (first != NULL, NULL);
+	g_return_val_if_fail (second || !third, NULL);
+	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+	if (_parse_and_build_route (AF_INET, first, second, third, &tmp_route, error)) {
+		route = nm_ip4_route_new ();
+		nm_ip4_route_set_dest (route, tmp_route.dst.ip4_dst);
+		nm_ip4_route_set_prefix (route, (guint32) tmp_route.prefix);
+		nm_ip4_route_set_next_hop (route, tmp_route.nh.ip4_nh);
+		nm_ip4_route_set_metric (route, (guint32) tmp_route.metric);
+	}
+	return route;
+}
+
+/*
+ * nmc_parse_and_build_ip6_route:
+ * @first: the IPv6 route destination in the form of "address/prefix"
+     (/prefix is optional)
+ * @second: (allow-none): next hop address, if third is not NULL. Otherwise it could be
+     either next hop address or metric. (It can be NULL when @third is NULL).
+ * @third: (allow-none): route metric
+ * @error: location to store GError
+ *
+ * Parse IPv6 route from strings to NMIP6Route stucture.
+ *
+ * Returns: route as a NMIP6Route object, or %NULL on failure
+ */
+NMIP6Route *
+nmc_parse_and_build_ip6_route (const char *first,
+                               const char *second,
+                               const char *third,
+                               GError **error)
+{
+	ParsedRoute tmp_route;
+	NMIP6Route *route = NULL;
+
+	g_return_val_if_fail (first != NULL, NULL);
+	g_return_val_if_fail (second || !third, NULL);
+	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+	if (_parse_and_build_route (AF_INET6, first, second, third, &tmp_route, error)) {
+		route = nm_ip6_route_new ();
+		nm_ip6_route_set_dest (route, &tmp_route.dst.ip6_dst);
+		nm_ip6_route_set_prefix (route, (guint32) tmp_route.prefix);
+		nm_ip6_route_set_next_hop (route, &tmp_route.nh.ip6_nh);
+		nm_ip6_route_set_metric (route, (guint32) tmp_route.metric);
+	}
+	return route;
+}
+
 const char *
 nmc_device_state_to_string (NMDeviceState state)
 {
@@ -560,8 +875,294 @@ nmc_device_reason_to_string (NMDeviceStateReason reason)
 	case NM_DEVICE_STATE_REASON_SECONDARY_CONNECTION_FAILED:
 		return _("A secondary connection of the base connection failed");
 
+	case NM_DEVICE_STATE_REASON_DCB_FCOE_FAILED:
+		return _("DCB or FCoE setup failed");
+
+	case NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED:
+		return _("teamd control failed");
+
+	case NM_DEVICE_STATE_REASON_MODEM_FAILED:
+		return _("Modem failed or no longer available");
+
+	case NM_DEVICE_STATE_REASON_MODEM_AVAILABLE:
+		return _("Modem now ready and available");
+
+	case NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT:
+		return _("SIM PIN was incorrect");
+
 	default:
+		/* TRANSLATORS: Unknown reason for a device state change (NMDeviceStateReason) */
 		return _("Unknown");
 	}
 }
 
+
+/* Max priority values from libnm-util/nm-setting-vlan.c */
+#define MAX_SKB_PRIO   G_MAXUINT32
+#define MAX_8021P_PRIO 7  /* Max 802.1p priority */
+
+/*
+ * Parse VLAN priority mappings from the following format: 2:1,3:4,7:3
+ * and verify if the priority numbers are valid
+ *
+ * Return: string array with split maps, or NULL on error
+ * Caller is responsible for freeing the array.
+ */
+char **
+nmc_vlan_parse_priority_maps (const char *priority_map,
+                              NMVlanPriorityMap map_type,
+                              GError **error)
+{
+	char **mapping = NULL, **iter;
+	unsigned long from, to, from_max, to_max;
+
+	g_return_val_if_fail (priority_map != NULL, NULL);
+	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+	if (map_type == NM_VLAN_INGRESS_MAP) {
+		from_max = MAX_8021P_PRIO;
+		to_max = MAX_SKB_PRIO;
+	} else {
+		from_max = MAX_SKB_PRIO;
+		to_max = MAX_8021P_PRIO;
+	}
+
+	mapping = g_strsplit (priority_map, ",", 0);
+	for (iter = mapping; iter && *iter; iter++) {
+		char *left, *right;
+
+		left = g_strstrip (*iter);
+		right = strchr (left, ':');
+		if (!right) {
+			g_set_error (error, 1, 0, _("invalid priority map '%s'"), *iter);
+			g_strfreev (mapping);
+			return NULL;
+		}
+		*right++ = '\0';
+
+		if (!nmc_string_to_uint (left, TRUE, 0, from_max, &from)) {
+			g_set_error (error, 1, 0, _("priority '%s' is not valid (<0-%ld>)"),
+			             left, from_max);
+			g_strfreev (mapping);
+			return NULL;
+		}
+		if (!nmc_string_to_uint (right, TRUE, 0, to_max, &to)) {
+			g_set_error (error, 1, 0, _("priority '%s' is not valid (<0-%ld>)"),
+			             right, to_max);
+			g_strfreev (mapping);
+			return NULL;
+		}
+		*(right-1) = ':'; /* Put back ':' */
+	}
+	return mapping;
+}
+
+const char *
+nmc_bond_validate_mode (const char *mode, GError **error)
+{
+	unsigned long mode_int;
+	static const char *valid_modes[] = { "balance-rr",
+	                                     "active-backup",
+	                                     "balance-xor",
+	                                     "broadcast",
+	                                     "802.3ad",
+	                                     "balance-tlb",
+	                                     "balance-alb",
+	                                     NULL };
+	if (nmc_string_to_uint (mode, TRUE, 0, 6, &mode_int)) {
+		/* Translate bonding mode numbers to mode names:
+		 * https://www.kernel.org/doc/Documentation/networking/bonding.txt
+		 */
+		return valid_modes[mode_int];
+	} else
+		return nmc_string_is_valid (mode, valid_modes, error);
+}
+
+/*
+ * nmc_team_check_config:
+ * @config: file name with team config, or raw team JSON config data
+ * @out_config: raw team JSON config data (with removed new-line characters)
+ * @error: location to store error, or %NUL
+ *
+ * Check team config from @config parameter and return the checked/sanitized
+ * config in @out_config.
+ *
+ * Returns: %TRUE if the config is valid, %FALSE if it is invalid
+ */
+gboolean
+nmc_team_check_config (const char *config, char **out_config, GError **error)
+{
+	char *contents = NULL;
+	size_t c_len = 0;
+
+	*out_config = NULL;
+
+	if (!config || strlen (config) == strspn (config, " \t"))
+		return TRUE;
+
+	/* 'config' can be either a file name or raw JSON config data */
+	if (g_file_test (config, G_FILE_TEST_EXISTS))
+		(void) g_file_get_contents (config, &contents, NULL, NULL);
+	else
+		contents = g_strdup (config);
+
+	if (contents) {
+		g_strstrip (contents);
+		c_len = strlen (contents);
+	}
+
+	/* Do a simple validity check */
+	if (!contents || !contents[0] || c_len > 100000 || contents[0] != '{' || contents[c_len-1] != '}') {
+		g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+		             _("'%s' is not a valid team configuration or file name."), config);
+		g_free (contents);
+		return FALSE;
+	}
+	*out_config = g_strdelimit (contents, "\r\n", ' ');
+	return TRUE;
+}
+
+/*
+ * nmc_find_connection:
+ * @list: list of NMConnections to search in
+ * @filter_type: "id", "uuid", "path" or %NULL
+ * @filter_val: connection to find (connection name, UUID or path)
+ * @start: where to start in @list. The location is updated so that the function
+ *   can be called multiple times (for connections with the same name).
+ *
+ * Find a connection in @list according to @filter_val. @filter_type determines
+ * what property is used for comparison. When @filter_type is NULL, compare
+ * @filter_val against all types. Otherwise, only compare against the specified
+ * type. If 'path' filter type is specified, comparison against numeric index
+ * (in addition to the whole path) is allowed.
+ *
+ * Returns: found connection, or %NULL
+ */
+NMConnection *
+nmc_find_connection (GSList *list,
+                     const char *filter_type,
+                     const char *filter_val,
+                     GSList **start)
+{
+	NMConnection *connection;
+	NMConnection *found = NULL;
+	GSList *iterator;
+	const char *id;
+	const char *uuid;
+	const char *path, *path_num;
+
+	iterator = (start && *start) ? *start : list;
+	while (iterator) {
+		connection = NM_CONNECTION (iterator->data);
+
+		id = nm_connection_get_id (connection);
+		uuid = nm_connection_get_uuid (connection);
+		path = nm_connection_get_path (connection);
+		path_num = path ? strrchr (path, '/') + 1 : NULL;
+
+		/* When filter_type is NULL, compare connection ID (filter_val)
+		 * against all types. Otherwise, only compare against the specific
+		 * type. If 'path' filter type is specified, comparison against
+		 * numeric index (in addition to the whole path) is allowed.
+		 */
+		if (   (   (!filter_type || strcmp (filter_type, "id")  == 0)
+		        && strcmp (filter_val, id) == 0)
+		    || (   (!filter_type || strcmp (filter_type, "uuid") == 0)
+		        && strcmp (filter_val, uuid) == 0)
+		    || (   (!filter_type || strcmp (filter_type, "path") == 0)
+		        && (g_strcmp0 (filter_val, path) == 0 || (filter_type && g_strcmp0 (filter_val, path_num) == 0)))) {
+			if (!start)
+				return connection;
+			if (found) {
+				*start = iterator;
+				return found;
+			}
+			found = connection;
+		}
+
+		iterator = g_slist_next (iterator);
+	}
+
+	if (start)
+		*start = NULL;
+	return found;
+}
+
+/**
+ * nmc_cleanup_readline:
+ *
+ * Cleanup readline when nmcli is terminated with a signal.
+ * It makes sure the terminal is not garbled.
+ */
+void
+nmc_cleanup_readline (void)
+{
+	rl_free_line_state ();
+	rl_cleanup_after_signal ();
+}
+
+/**
+ * nmc_readline:
+ * @prompt_fmt: prompt to print (telling user what to enter). It is standard
+ *   printf() format string
+ * @...: a list of arguments according to the @prompt_fmt format string
+ *
+ * Wrapper around libreadline's readline() function.
+ *
+ * Returns: the user provided string. In case the user entered empty string,
+ * this function returns NULL.
+ */
+char *
+nmc_readline (const char *prompt_fmt, ...)
+{
+	va_list args;
+	char *prompt, *str;
+
+	va_start (args, prompt_fmt);
+	prompt = g_strdup_vprintf (prompt_fmt, args);
+	va_end (args);
+
+	str = readline (prompt);
+	/* Return NULL, not empty string */
+	if (str && *str == '\0') {
+		g_free (str);
+		str = NULL;
+	}
+
+	if (str && *str)
+		add_history (str);
+
+	g_free (prompt);
+	return str;
+}
+
+/**
+ * nmc_rl_gen_func_basic:
+ * @text: text to complete
+ * @state: readline state; says whether start from scratch (state == 0)
+ * @words: strings for completion
+ *
+ * Basic function generating list of completion strings for readline.
+ * See e.g. http://cnswww.cns.cwru.edu/php/chet/readline/readline.html#SEC49
+ */
+char *
+nmc_rl_gen_func_basic (const char *text, int state, const char **words)
+{
+	static int list_idx, len;
+	const char *name;
+
+	if (!state) {
+		list_idx = 0;
+		len = strlen (text);
+	}
+
+	/* Return the next name which partially matches one from the 'words' list. */
+	while ((name = words[list_idx])) {
+		list_idx++;
+
+		if (strncmp (name, text, len) == 0)
+			return g_strdup (name);
+	}
+	return NULL;
+}
+
diff --git a/cli/src/common.h b/cli/src/common.h
index 89412d28..228375b9 100644
--- a/cli/src/common.h
+++ b/cli/src/common.h
@@ -16,7 +16,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * (C) Copyright 2012 Red Hat, Inc.
+ * (C) Copyright 2012 - 2014 Red Hat, Inc.
  */
 
 #ifndef NMC_COMMON_H
@@ -32,12 +32,35 @@
 
 #include "nmcli.h"
 
-gboolean print_ip4_config (NMIP4Config *cfg4, NmCli *nmc, const char *group_prefix);
-gboolean print_ip6_config (NMIP6Config *cfg6, NmCli *nmc, const char *group_prefix);
-gboolean print_dhcp4_config (NMDHCP4Config *dhcp4, NmCli *nmc, const char *group_prefix);
-gboolean print_dhcp6_config (NMDHCP6Config *dhcp6, NmCli *nmc, const char *group_prefix);
+gboolean print_ip4_config (NMIP4Config *cfg4, NmCli *nmc, const char *group_prefix, const char *one_field);
+gboolean print_ip6_config (NMIP6Config *cfg6, NmCli *nmc, const char *group_prefix, const char *one_field);
+gboolean print_dhcp4_config (NMDHCP4Config *dhcp4, NmCli *nmc, const char *group_prefix, const char *one_field);
+gboolean print_dhcp6_config (NMDHCP6Config *dhcp6, NmCli *nmc, const char *group_prefix, const char *one_field);
+
+NMIP4Address *nmc_parse_and_build_ip4_address (const char *ip_str, const char *gw_str, GError **error);
+NMIP6Address *nmc_parse_and_build_ip6_address (const char *ip_str, const char *gw_str, GError **error);
+
+NMIP4Route *nmc_parse_and_build_ip4_route (const char *first, const char *second, const char *third, GError **error);
+NMIP6Route *nmc_parse_and_build_ip6_route (const char *first, const char *second, const char *third, GError **error);
 
 const char * nmc_device_state_to_string (NMDeviceState state);
 const char * nmc_device_reason_to_string (NMDeviceStateReason reason);
 
+char **
+nmc_vlan_parse_priority_maps (const char *priority_map,
+                              NMVlanPriorityMap map_type,
+                              GError **error);
+
+const char *nmc_bond_validate_mode (const char *mode, GError **error);
+gboolean nmc_team_check_config (const char *config, char **out_config, GError **error);
+
+NMConnection *nmc_find_connection (GSList *list,
+                                   const char *filter_type,
+                                   const char *filter_val,
+                                   GSList **start);
+
+void nmc_cleanup_readline (void);
+char *nmc_readline (const char *prompt_fmt, ...) G_GNUC_PRINTF (1, 2);
+char *nmc_rl_gen_func_basic (const char *text, int state, const char **words);
+
 #endif /* NMC_COMMON_H */
diff --git a/cli/src/connections.c b/cli/src/connections.c
index b39b447e..d17f7f12 100644
--- a/cli/src/connections.c
+++ b/cli/src/connections.c
@@ -14,7 +14,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * (C) Copyright 2010 - 2012 Red Hat, Inc.
+ * (C) Copyright 2010 - 2014 Red Hat, Inc.
  */
 
 #include "config.h"
@@ -30,6 +30,8 @@
 #include <errno.h>
 #include <signal.h>
 #include <netinet/ether.h>
+#include <readline/readline.h>
+#include <readline/history.h>
 
 #include <nm-client.h>
 #include <nm-device-ethernet.h>
@@ -43,6 +45,7 @@
 #include <nm-device-olpc-mesh.h>
 #include <nm-device-infiniband.h>
 #include <nm-device-bond.h>
+#include <nm-device-team.h>
 #include <nm-device-bridge.h>
 #include <nm-device-vlan.h>
 #include <nm-remote-settings.h>
@@ -54,50 +57,104 @@
 #include "settings.h"
 #include "connections.h"
 
-
-/* Available fields for 'con list' */
-static NmcOutputField nmc_fields_con_list[] = {
-	{"NAME",            N_("NAME"),           25, NULL, 0},  /* 0 */
-	{"UUID",            N_("UUID"),           38, NULL, 0},  /* 1 */
-	{"TYPE",            N_("TYPE"),           17, NULL, 0},  /* 2 */
-	{"TIMESTAMP",       N_("TIMESTAMP"),      12, NULL, 0},  /* 3 */
-	{"TIMESTAMP-REAL",  N_("TIMESTAMP-REAL"), 34, NULL, 0},  /* 4 */
-	{"AUTOCONNECT",     N_("AUTOCONNECT"),    13, NULL, 0},  /* 5 */
-	{"READONLY",        N_("READONLY"),       10, NULL, 0},  /* 6 */
-	{"DBUS-PATH",       N_("DBUS-PATH"),      42, NULL, 0},  /* 7 */
-	{NULL,              NULL,                  0, NULL, 0}
+/* Activation timeout waiting for bond/team/bridge slaves (in seconds) */
+#define SLAVES_UP_TIMEOUT 10
+
+/* define some prompts for connection editor */
+#define EDITOR_PROMPT_SETTING  _("Setting name? ")
+#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: ")
+#define PROMPT_CONNECTION _("Connection (name, UUID, or path): ")
+
+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 */
+	{"UUID",            N_("UUID"),           38},  /* 1 */
+	{"TYPE",            N_("TYPE"),           17},  /* 2 */
+	{"TIMESTAMP",       N_("TIMESTAMP"),      12},  /* 3 */
+	{"TIMESTAMP-REAL",  N_("TIMESTAMP-REAL"), 34},  /* 4 */
+	{"AUTOCONNECT",     N_("AUTOCONNECT"),    13},  /* 5 */
+	{"READONLY",        N_("READONLY"),       10},  /* 6 */
+	{"DBUS-PATH",       N_("DBUS-PATH"),      42},  /* 7 */
+	{"ACTIVE",          N_("ACTIVE"),         10},  /* 8 */
+	{"DEVICE",          N_("DEVICE"),         10},  /* 9 */
+	{"STATE",           N_("STATE"),          12},  /* 10 */
+	{"ACTIVE-PATH",     N_("ACTIVE-PATH"),    51},  /* 11 */
+	{NULL,              NULL,                  0}
 };
-#define NMC_FIELDS_CON_LIST_ALL     "NAME,UUID,TYPE,TIMESTAMP,TIMESTAMP-REAL,AUTOCONNECT,READONLY,DBUS-PATH"
-#define NMC_FIELDS_CON_LIST_COMMON  "NAME,UUID,TYPE,TIMESTAMP-REAL"
+#define NMC_FIELDS_CON_SHOW_ALL     "NAME,UUID,TYPE,TIMESTAMP,TIMESTAMP-REAL,AUTOCONNECT,READONLY,DBUS-PATH,"\
+                                    "ACTIVE,DEVICE,STATE,ACTIVE-PATH"
+#define NMC_FIELDS_CON_SHOW_COMMON  "NAME,UUID,TYPE,DEVICE"
 
 /* Helper macro to define fields */
-#define SETTING_FIELD(setting, width) { setting, N_(setting), width, NULL, 0 }
-
-/* Available settings for 'con list id/uuid <con>' */
+#define SETTING_FIELD(setting, props) { setting, N_(setting), 0, props, NULL, FALSE, FALSE, 0 }
+
+/* defined in settings.c */
+extern NmcOutputField nmc_fields_setting_connection[];
+extern NmcOutputField nmc_fields_setting_wired[];
+extern NmcOutputField nmc_fields_setting_8021X[];
+extern NmcOutputField nmc_fields_setting_wireless[];
+extern NmcOutputField nmc_fields_setting_wireless_security[];
+extern NmcOutputField nmc_fields_setting_ip4_config[];
+extern NmcOutputField nmc_fields_setting_ip6_config[];
+extern NmcOutputField nmc_fields_setting_serial[];
+extern NmcOutputField nmc_fields_setting_ppp[];
+extern NmcOutputField nmc_fields_setting_pppoe[];
+extern NmcOutputField nmc_fields_setting_adsl[];
+extern NmcOutputField nmc_fields_setting_gsm[];
+extern NmcOutputField nmc_fields_setting_cdma[];
+extern NmcOutputField nmc_fields_setting_bluetooth[];
+extern NmcOutputField nmc_fields_setting_olpc_mesh[];
+extern NmcOutputField nmc_fields_setting_vpn[];
+extern NmcOutputField nmc_fields_setting_wimax[];
+extern NmcOutputField nmc_fields_setting_infiniband[];
+extern NmcOutputField nmc_fields_setting_bond[];
+extern NmcOutputField nmc_fields_setting_vlan[];
+extern NmcOutputField nmc_fields_setting_bridge[];
+extern NmcOutputField nmc_fields_setting_bridge_port[];
+extern NmcOutputField nmc_fields_setting_team[];
+extern NmcOutputField nmc_fields_setting_team_port[];
+extern NmcOutputField nmc_fields_setting_dcb[];
+
+/* Available settings for 'connection show <con>' - profile part */
 static NmcOutputField nmc_fields_settings_names[] = {
-	SETTING_FIELD (NM_SETTING_CONNECTION_SETTING_NAME, 0),            /* 0 */
-	SETTING_FIELD (NM_SETTING_WIRED_SETTING_NAME, 0),                 /* 1 */
-	SETTING_FIELD (NM_SETTING_802_1X_SETTING_NAME, 0),                /* 2 */
-	SETTING_FIELD (NM_SETTING_WIRELESS_SETTING_NAME, 0),              /* 3 */
-	SETTING_FIELD (NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, 0),     /* 4 */
-	SETTING_FIELD (NM_SETTING_IP4_CONFIG_SETTING_NAME, 0),            /* 5 */
-	SETTING_FIELD (NM_SETTING_IP6_CONFIG_SETTING_NAME, 0),            /* 6 */
-	SETTING_FIELD (NM_SETTING_SERIAL_SETTING_NAME, 0),                /* 7 */
-	SETTING_FIELD (NM_SETTING_PPP_SETTING_NAME, 0),                   /* 8 */
-	SETTING_FIELD (NM_SETTING_PPPOE_SETTING_NAME, 0),                 /* 9 */
-	SETTING_FIELD (NM_SETTING_GSM_SETTING_NAME, 0),                   /* 10 */
-	SETTING_FIELD (NM_SETTING_CDMA_SETTING_NAME, 0),                  /* 11 */
-	SETTING_FIELD (NM_SETTING_BLUETOOTH_SETTING_NAME, 0),             /* 12 */
-	SETTING_FIELD (NM_SETTING_OLPC_MESH_SETTING_NAME, 0),             /* 13 */
-	SETTING_FIELD (NM_SETTING_VPN_SETTING_NAME, 0),                   /* 14 */
-	SETTING_FIELD (NM_SETTING_WIMAX_SETTING_NAME, 0),                 /* 15 */
-	SETTING_FIELD (NM_SETTING_INFINIBAND_SETTING_NAME, 0),            /* 16 */
-	SETTING_FIELD (NM_SETTING_BOND_SETTING_NAME, 0),                  /* 17 */
-	SETTING_FIELD (NM_SETTING_VLAN_SETTING_NAME, 0),                  /* 18 */
-	SETTING_FIELD (NM_SETTING_ADSL_SETTING_NAME, 0),                  /* 19 */
-	SETTING_FIELD (NM_SETTING_BRIDGE_SETTING_NAME, 0),                /* 20 */
-	SETTING_FIELD (NM_SETTING_BRIDGE_PORT_SETTING_NAME, 0),           /* 21 */
-	{NULL, NULL, 0, NULL, 0}
+	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 */
+	{NULL, NULL, 0, NULL, NULL, FALSE, FALSE, 0}
 };
 #define NMC_FIELDS_SETTINGS_NAMES_ALL_X  NM_SETTING_CONNECTION_SETTING_NAME","\
                                          NM_SETTING_WIRED_SETTING_NAME","\
@@ -119,7 +176,10 @@ static NmcOutputField nmc_fields_settings_names[] = {
                                          NM_SETTING_BOND_SETTING_NAME","\
                                          NM_SETTING_VLAN_SETTING_NAME","\
                                          NM_SETTING_BRIDGE_SETTING_NAME","\
-                                         NM_SETTING_BRIDGE_PORT_SETTING_NAME
+                                         NM_SETTING_BRIDGE_PORT_SETTING_NAME","\
+                                         NM_SETTING_TEAM_SETTING_NAME","\
+                                         NM_SETTING_TEAM_PORT_SETTING_NAME"," \
+                                         NM_SETTING_DCB_SETTING_NAME
 #if WITH_WIMAX
 #define NMC_FIELDS_SETTINGS_NAMES_ALL    NMC_FIELDS_SETTINGS_NAMES_ALL_X","\
                                          NM_SETTING_WIMAX_SETTING_NAME
@@ -127,54 +187,65 @@ static NmcOutputField nmc_fields_settings_names[] = {
 #define NMC_FIELDS_SETTINGS_NAMES_ALL    NMC_FIELDS_SETTINGS_NAMES_ALL_X
 #endif
 
-
-/* Available fields for 'con status' */
-static NmcOutputField nmc_fields_con_status[] = {
-	{"GROUP",         N_("GROUP"),         9, NULL, 0},  /* 0 */  /* used only for 'GENERAL' group listing */
-	{"NAME",          N_("NAME"),         25, NULL, 0},  /* 1 */
-	{"UUID",          N_("UUID"),         38, NULL, 0},  /* 2 */
-	{"DEVICES",       N_("DEVICES"),      10, NULL, 0},  /* 3 */
-	{"STATE",         N_("STATE"),        12, NULL, 0},  /* 4 */
-	{"DEFAULT",       N_("DEFAULT"),       8, NULL, 0},  /* 5 */
-	{"DEFAULT6",      N_("DEFAULT6"),      9, NULL, 0},  /* 6 */
-	{"SPEC-OBJECT",   N_("SPEC-OBJECT"),  10, NULL, 0},  /* 7 */
-	{"VPN",           N_("VPN"),           5, NULL, 0},  /* 8 */
-	{"DBUS-PATH",     N_("DBUS-PATH"),    51, NULL, 0},  /* 9 */
-	{"CON-PATH",      N_("CON-PATH"),     44, NULL, 0},  /* 10 */
-	{"ZONE",          N_("ZONE"),         15, NULL, 0},  /* 11 */
-	{"MASTER-PATH",   N_("MASTER-PATH"),  44, NULL, 0},  /* 12 */
-	{NULL,            NULL,                0, NULL, 0}
+/* Active connection data */
+/* Available fields for GENERAL group */
+static NmcOutputField nmc_fields_con_active_details_general[] = {
+	{"GROUP",         N_("GROUP"),         9},  /* 0 */
+	{"NAME",          N_("NAME"),         25},  /* 1 */
+	{"UUID",          N_("UUID"),         38},  /* 2 */
+	{"DEVICES",       N_("DEVICES"),      10},  /* 3 */
+	{"STATE",         N_("STATE"),        12},  /* 4 */
+	{"DEFAULT",       N_("DEFAULT"),       8},  /* 5 */
+	{"DEFAULT6",      N_("DEFAULT6"),      9},  /* 6 */
+	{"SPEC-OBJECT",   N_("SPEC-OBJECT"),  10},  /* 7 */
+	{"VPN",           N_("VPN"),           5},  /* 8 */
+	{"DBUS-PATH",     N_("DBUS-PATH"),    51},  /* 9 */
+	{"CON-PATH",      N_("CON-PATH"),     44},  /* 10 */
+	{"ZONE",          N_("ZONE"),         15},  /* 11 */
+	{"MASTER-PATH",   N_("MASTER-PATH"),  44},  /* 12 */
+	{NULL,            NULL,                0}
 };
-#define NMC_FIELDS_CON_STATUS_ALL     "NAME,UUID,DEVICES,STATE,DEFAULT,DEFAULT6,VPN,ZONE,DBUS-PATH,CON-PATH,SPEC-OBJECT,MASTER-PATH"
-#define NMC_FIELDS_CON_STATUS_COMMON  "NAME,UUID,DEVICES,DEFAULT,VPN,MASTER-PATH"
-
-/* Available fields for 'con status id/uuid/path <con>' */
-static NmcOutputField nmc_fields_status_details_groups[] = {
-	{"GENERAL",  N_("GENERAL"), 9, NULL, 0},  /* 0 */
-	{"IP",       N_("IP"),      5, NULL, 0},  /* 1 */
-	{"VPN",      N_("VPN"),     5, NULL, 0},  /* 2 */
-	{NULL, NULL, 0, NULL, 0}
-};
-#define NMC_FIELDS_CON_STATUS_DETAILS_ALL  "GENERAL,IP,VPN"
-
-/* GENERAL group is the same as nmc_fields_con_status */
-#define NMC_FIELDS_CON_STATUS_DETAILS_GENERAL_ALL  "GROUP,"NMC_FIELDS_CON_STATUS_ALL
+#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 */
-static NmcOutputField nmc_fields_status_details_vpn[] = {
-	{"GROUP",     N_("GROUP"),       9, NULL, 0},  /* 0 */
-	{"TYPE",      N_("TYPE"),       15, NULL, 0},  /* 1 */
-	{"USERNAME",  N_("USERNAME"),   15, NULL, 0},  /* 2 */
-	{"GATEWAY",   N_("GATEWAY"),    25, NULL, 0},  /* 3 */
-	{"BANNER",    N_("BANNER"),    120, NULL, 0},  /* 4 */
-	{"VPN-STATE", N_("VPN-STATE"),  40, NULL, 0},  /* 5 */
-	{"CFG",       N_("CFG"),       120, NULL, 0},  /* 6 */
-	{NULL, NULL, 0, NULL, 0}
+static NmcOutputField nmc_fields_con_active_details_vpn[] = {
+	{"GROUP",     N_("GROUP"),       9},  /* 0 */
+	{"TYPE",      N_("TYPE"),       15},  /* 1 */
+	{"USERNAME",  N_("USERNAME"),   15},  /* 2 */
+	{"GATEWAY",   N_("GATEWAY"),    25},  /* 3 */
+	{"BANNER",    N_("BANNER"),    120},  /* 4 */
+	{"VPN-STATE", N_("VPN-STATE"),  40},  /* 5 */
+	{"CFG",       N_("CFG"),       120},  /* 6 */
+	{NULL, NULL, 0}
 };
-#define NMC_FIELDS_CON_STATUS_DETAILS_VPN_ALL  "GROUP,TYPE,USERNAME,GATEWAY,BANNER,VPN-STATE,CFG"
+#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 */
+static 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}
+};
+#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 */
+/* e.g.: nmcli -f active con show my-eth0 */
+#define CON_SHOW_DETAIL_GROUP_PROFILE "profile"
+#define CON_SHOW_DETAIL_GROUP_ACTIVE  "active"
 
 typedef struct {
 	NmCli *nmc;
@@ -188,270 +259,293 @@ extern GMainLoop *loop;
 static ArgsInfo args_info;
 static guint progress_id = 0;  /* ID of event source for displaying progress */
 
+/* for readline TAB completion in editor */
+typedef struct {
+	NmCli *nmc;
+	char *con_type;
+	NMConnection *connection;
+	NMSetting *setting;
+} 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 (const char *text, int state);
+
 static void
 usage (void)
 {
 	fprintf (stderr,
-	         _("Usage: nmcli connection { COMMAND | help }\n"
-	         "  COMMAND := { list | status | up | down | delete }\n\n"
-	         "  list [id <id> | uuid <id>]\n"
-	         "  status [id <id> | uuid <id> | path <path>]\n"
+	         _("Usage: nmcli connection { COMMAND | help }\n\n"
+	           "COMMAND := { show | up | down | add | modify | edit | delete | reload | load }\n\n"
+	           "  show [--active] [[id | uuid | path | apath] <ID>] ...\n\n"
 #if WITH_WIMAX
-	         "  up id <id> | uuid <id> [iface <iface>] [ap <BSSID>] [nsp <name>] [--nowait] [--timeout <timeout>]\n"
+	           "  up [[id | uuid | path] <ID>] [ifname <ifname>] [ap <BSSID>] [nsp <name>]\n\n"
 #else
-	         "  up id <id> | uuid <id> [iface <iface>] [ap <BSSID>] [--nowait] [--timeout <timeout>]\n"
+	           "  up [[id | uuid | path] <ID>] [ifname <ifname>] [ap <BSSID>]\n\n"
 #endif
-	         "  down id <id> | uuid <id>\n"
-	         "  delete id <id> | uuid <id>\n"
-	         "\n"
-	         ));
+	           "  down [id | uuid | path | apath] <ID>\n\n"
+	           "  add COMMON_OPTIONS TYPE_SPECIFIC_OPTIONS IP_OPTIONS\n\n"
+	           "  modify [--temporary] [id | uuid | path] <ID> ([+|-]<setting>.<property> <value>)+\n\n"
+	           "  edit [id | uuid | path] <ID>\n"
+	           "  edit [type <new_con_type>] [con-name <new_con_name>]\n\n"
+	           "  delete [id | uuid | path] <ID>\n\n"
+	           "  reload\n\n"
+	           "  load <filename> [ <filename>... ]\n\n"));
 }
 
-/* The real commands that do something - i.e. not 'help', etc. */
-static const char *real_con_commands[] = {
-	"list",
-	"status",
-	"up",
-	"down",
-	"delete",
-	NULL
-};
-
-/* quit main loop */
 static void
-quit (void)
+usage_connection_show (void)
 {
-	if (progress_id) {
-		g_source_remove (progress_id);
-		nmc_terminal_erase_line ();
-	}
-
-	g_main_loop_quit (loop);  /* quit main loop */
+	fprintf (stderr,
+	         _("Usage: nmcli connection show { ARGUMENTS | help }\n"
+	           "\n"
+	           "ARGUMENTS := [--active]\n"
+	           "\n"
+	           "List in-memory and on-disk connection profiles, some of which may also be\n"
+	           "active if a device is using that connection profile. Without a parameter, all\n"
+	           "profiles are listed. When --active option is specified, only the active\n"
+	           "profiles are shown.\n"
+	           "\n"
+	           "ARGUMENTS := [--active] [id | uuid | path | apath] <ID> ...\n"
+	           "\n"
+	           "Show details for specified connections. By default, both static configuration\n"
+	           "and active connection data are displayed. It is possible to filter the output\n"
+	           "using global '--fields' option. Refer to the manual page for more information.\n"
+	           "When --active option is specified, only the active profiles are taken into\n"
+	           "account.\n"));
 }
 
-static gboolean
-nmc_connection_detail (NMConnection *connection, NmCli *nmc)
+static void
+usage_connection_up (void)
 {
-	GError *error = NULL;
-	GArray *print_settings_array;
-	int i;
-	char *fields_str;
-	char *fields_all =    NMC_FIELDS_SETTINGS_NAMES_ALL;
-	char *fields_common = NMC_FIELDS_SETTINGS_NAMES_ALL;
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
-	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
-		fields_str = nmc->required_fields;
-
-	print_settings_array = parse_output_fields (fields_str, nmc_fields_settings_names, &error);
-	if (error) {
-		if (error->code == 0)
-			g_string_printf (nmc->return_text, _("Error: 'con list': %s"), error->message);
-		else
-			g_string_printf (nmc->return_text, _("Error: 'con list': %s; allowed fields: %s"), error->message, NMC_FIELDS_SETTINGS_NAMES_ALL);
-		g_error_free (error);
-		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-		return FALSE;
-	}
-
-	nmc->allowed_fields = nmc_fields_settings_names;
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ONLY;
-	nmc->print_fields.header_name = _("Connection details");
-	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTINGS_NAMES_ALL, nmc->allowed_fields, NULL);
-	print_fields (nmc->print_fields, nmc->allowed_fields);
-
-	/* Loop through the required settings and print them. */
-	for (i = 0; i < print_settings_array->len; i++) {
-		NMSetting *setting;
-		int section_idx = g_array_index (print_settings_array, int, i);
-
-		if (nmc->print_output != NMC_PRINT_TERSE && !nmc->multiline_output && was_output)
-			printf ("\n"); /* Empty line */
-
-		was_output = FALSE;
-
-		setting = nm_connection_get_setting_by_name (connection, nmc_fields_settings_names[section_idx].name);
-		if (setting) {
-			setting_details (setting, nmc);
-			was_output = TRUE;
-			continue;
-		}
-	}
-
-	if (print_settings_array)
-		g_array_free (print_settings_array, FALSE);
-
-	return NMC_RESULT_SUCCESS;
+	fprintf (stderr,
+	         _("Usage: nmcli connection up { ARGUMENTS | help }\n"
+	           "\n"
+	           "ARGUMENTS := [id | uuid | path] <ID> [ifname <ifname>] [ap <BSSID>] [nsp <name>]\n"
+	           "\n"
+	           "Activate a connection on a device. The profile to activate is identified by its\n"
+	           "name, UUID or D-Bus path.\n"
+	           "\n"
+	           "ARGUMENTS := ifname <ifname> [ap <BSSID>] [nsp <name>]\n"
+	           "\n"
+	           "Activate a device with a connection. The connection profile is selected\n"
+	           "automatically by NetworkManager.\n"
+	           "\n"
+	           "ifname - specifies the device to active the connection on\n"
+	           "ap     - specifies AP to connect to (only valid for Wi-Fi)\n"
+	           "nsp    - specifies NSP to connect to (only valid for WiMAX)\n\n"));
 }
 
 static void
-show_connection (NMConnection *data, gpointer user_data)
+usage_connection_down (void)
 {
-	NMConnection *connection = (NMConnection *) data;
-	NmCli *nmc = (NmCli *) user_data;
-	NMSettingConnection *s_con;
-	guint64 timestamp;
-	time_t timestamp_real;
-	char *timestamp_str;
-	char timestamp_real_str[64];
-
-	s_con = nm_connection_get_setting_connection (connection);
-	if (s_con) {
-		/* Obtain field values */
-		timestamp = nm_setting_connection_get_timestamp (s_con);
-		timestamp_str = g_strdup_printf ("%" G_GUINT64_FORMAT, timestamp);
-		timestamp_real = timestamp;
-		strftime (timestamp_real_str, sizeof (timestamp_real_str), "%c", localtime (&timestamp_real));
-
-		nmc->allowed_fields[0].value = nm_setting_connection_get_id (s_con);
-		nmc->allowed_fields[1].value = nm_setting_connection_get_uuid (s_con);
-		nmc->allowed_fields[2].value = nm_setting_connection_get_connection_type (s_con);
-		nmc->allowed_fields[3].value = timestamp_str;
-		nmc->allowed_fields[4].value = timestamp ? timestamp_real_str : _("never");
-		nmc->allowed_fields[5].value = nm_setting_connection_get_autoconnect (s_con) ? _("yes") : _("no");
-		nmc->allowed_fields[6].value = nm_setting_connection_get_read_only (s_con) ? _("yes") : _("no");
-		nmc->allowed_fields[7].value = nm_connection_get_path (connection);
-
-		nmc->print_fields.flags &= ~NMC_PF_FLAG_MAIN_HEADER_ADD & ~NMC_PF_FLAG_MAIN_HEADER_ONLY & ~NMC_PF_FLAG_FIELD_NAMES; /* Clear header flags */
-		print_fields (nmc->print_fields, nmc->allowed_fields);
-
-		g_free (timestamp_str);
-	}
+	fprintf (stderr,
+	         _("Usage: nmcli connection down { ARGUMENTS | help }\n"
+	           "\n"
+	           "ARGUMENTS := [id | uuid | path | apath] <ID>\n"
+	           "\n"
+	           "Deactivate a connection from a device (without preventing the device from\n"
+	           "further auto-activation). The profile to deactivate is identified by its name,\n"
+	           "UUID or D-Bus path.\n\n"));
 }
 
-static NMConnection *
-find_connection (GSList *list, const char *filter_type, const char *filter_val)
+static void
+usage_connection_add (void)
 {
-	NMSettingConnection *s_con;
-	NMConnection *connection;
-	GSList *iterator;
-	const char *id;
-	const char *uuid;
-
-	iterator = list;
-	while (iterator) {
-		connection = NM_CONNECTION (iterator->data);
-		s_con = nm_connection_get_setting_connection (connection);
-		if (s_con) {
-			id = nm_setting_connection_get_id (s_con);
-			uuid = nm_setting_connection_get_uuid (s_con);
-			if (filter_type) {
-				if ((strcmp (filter_type, "id") == 0 && strcmp (filter_val, id) == 0) ||
-				    (strcmp (filter_type, "uuid") == 0 && strcmp (filter_val, uuid) == 0)) {
-					return connection;
-				}
-			}
-		}
-		iterator = g_slist_next (iterator);
-	}
+	fprintf (stderr,
+	         _("Usage: nmcli connection add { ARGUMENTS | help }\n"
+	           "\n"
+	           "ARGUMENTS := COMMON_OPTIONS TYPE_SPECIFIC_OPTIONS IP_OPTIONS\n\n"
+	           "  COMMON_OPTIONS:\n"
+	           "                  type <type>\n"
+	           "                  ifname <interface name> | \"*\"\n"
+	           "                  [con-name <connection name>]\n"
+	           "                  [autoconnect yes|no]\n\n"
+	           "                  [save yes|no]\n\n"
+	           "  TYPE_SPECIFIC_OPTIONS:\n"
+	           "    ethernet:     [mac <MAC address>]\n"
+	           "                  [cloned-mac <cloned MAC address>]\n"
+	           "                  [mtu <MTU>]\n\n"
+	           "    wifi:         ssid <SSID>\n"
+	           "                  [mac <MAC address>]\n"
+	           "                  [cloned-mac <cloned MAC address>]\n"
+	           "                  [mtu <MTU>]\n\n"
+	           "    wimax:        [mac <MAC address>]\n"
+	           "                  [nsp <NSP>]\n\n"
+	           "    pppoe:        username <PPPoE username>\n"
+	           "                  [password <PPPoE password>]\n"
+	           "                  [service <PPPoE service name>]\n"
+	           "                  [mtu <MTU>]\n"
+	           "                  [mac <MAC address>]\n\n"
+	           "    gsm:          apn <APN>\n"
+	           "                  [user <username>]\n"
+	           "                  [password <password>]\n\n"
+	           "    cdma:         [user <username>]\n"
+	           "                  [password <password>]\n\n"
+	           "    infiniband:   [mac <MAC address>]\n"
+	           "                  [mtu <MTU>]\n"
+	           "                  [transport-mode datagram | connected]\n"
+	           "                  [parent <ifname>]\n"
+	           "                  [p-key <IPoIB P_Key>]\n\n"
+	           "    bluetooth:    [addr <bluetooth address>]\n"
+	           "                  [bt-type panu|dun-gsm|dun-cdma]\n\n"
+	           "    vlan:         dev <parent device (connection  UUID, ifname, or MAC)>\n"
+	           "                  id <VLAN ID>\n"
+	           "                  [flags <VLAN flags>]\n"
+	           "                  [ingress <ingress priority mapping>]\n"
+	           "                  [egress <egress priority mapping>]\n"
+	           "                  [mtu <MTU>]\n\n"
+	           "    bond:         [mode balance-rr (0) | active-backup (1) | balance-xor (2) | broadcast (3) |\n"
+	           "                        802.3ad    (4) | balance-tlb   (5) | balance-alb (6)]\n"
+	           "                  [primary <ifname>]\n"
+	           "                  [miimon <num>]\n"
+	           "                  [downdelay <num>]\n"
+	           "                  [updelay <num>]\n"
+	           "                  [arp-interval <num>]\n"
+	           "                  [arp-ip-target <num>]\n\n"
+	           "    bond-slave:   master <master (ifname, or connection UUID or name)>\n\n"
+	           "    team:         [config <file>|<raw JSON data>]\n\n"
+	           "    team-slave:   master <master (ifname, or connection UUID or name)>\n"
+	           "                  [config <file>|<raw JSON data>]\n\n"
+	           "    bridge:       [stp yes|no]\n"
+	           "                  [priority <num>]\n"
+	           "                  [forward-delay <2-30>]\n"
+	           "                  [hello-time <1-10>]\n"
+	           "                  [max-age <6-40>]\n"
+	           "                  [ageing-time <0-1000000>]\n"
+	           "                  [mac <MAC address>]\n\n"
+	           "    bridge-slave: master <master (ifname, or connection UUID or name)>\n"
+	           "                  [priority <0-63>]\n"
+	           "                  [path-cost <1-65535>]\n"
+	           "                  [hairpin yes|no]\n\n"
+	           "    vpn:          vpn-type vpnc|openvpn|pptp|openconnect|openswan|libreswan|ssh|l2tp|iodine|...\n"
+	           "                  [user <username>]\n\n"
+	           "    olpc-mesh:    ssid <SSID>\n"
+	           "                  [channel <1-13>]\n"
+	           "                  [dhcp-anycast <MAC address>]\n\n"
+	           "  IP_OPTIONS:\n"
+	           "                  [ip4 <IPv4 address>] [gw4 <IPv4 gateway>]\n"
+	           "                  [ip6 <IPv6 address>] [gw6 <IPv6 gateway>]\n\n"));
+}
 
-	return NULL;
+static void
+usage_connection_modify (void)
+{
+	fprintf (stderr,
+	         _("Usage: nmcli connection modify { ARGUMENTS | help }\n"
+	           "\n"
+	           "ARGUMENTS := [id | uuid | path] <ID> ([+|-]<setting>.<property> <value>)+\n"
+	           "\n"
+	           "Modify one or more properties of the connection profile.\n"
+	           "The profile is identified by its name, UUID or D-Bus path. For multi-valued\n"
+	           "properties you can use optional '+' or '-' prefix to the property name.\n"
+	           "The '+' sign allows appending items instead of overwriting the whole value.\n"
+	           "The '-' sign allows removing selected items instead of the whole value.\n"
+	           "\n"
+	           "Examples:\n"
+	           "nmcli con mod home-wifi wifi.ssid rakosnicek\n"
+	           "nmcli con mod em1-1 ipv4.method manual ipv4.addr \"192.168.1.2/24, 10.10.1.5/8\"\n"
+	           "nmcli con mod em1-1 +ipv4.dns 8.8.4.4\n"
+	           "nmcli con mod em1-1 -ipv4.dns 1\n"
+	           "nmcli con mod em1-1 -ipv6.addr \"abbe::cafe/56\"\n"
+	           "nmcli con mod bond0 +bond.options mii=500\n"
+	           "nmcli con mod bond0 -bond.options downdelay\n\n"));
 }
 
-static NMCResultCode
-do_connections_list (NmCli *nmc, int argc, char **argv)
+static void
+usage_connection_edit (void)
 {
-	GError *error1 = NULL;
-	GError *error2 = NULL;
-	char *fields_str;
-	char *fields_all =    NMC_FIELDS_CON_LIST_ALL;
-	char *fields_common = NMC_FIELDS_CON_LIST_COMMON;
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
-	gboolean valid_param_specified = FALSE;
+	fprintf (stderr,
+	         _("Usage: nmcli connection edit { ARGUMENTS | help }\n"
+	           "\n"
+	           "ARGUMENTS := [id | uuid | path] <ID>\n"
+	           "\n"
+	           "Edit an existing connection profile in an interactive editor.\n"
+	           "The profile is identified by its name, UUID or D-Bus path\n"
+	           "\n"
+	           "ARGUMENTS := [type <new connection type>] [con-name <new connection name>]\n"
+	           "\n"
+	           "Add a new connection profile in an interactive editor.\n\n"));
+}
 
-	nmc->should_wait = FALSE;
+static void
+usage_connection_delete (void)
+{
+	fprintf (stderr,
+	         _("Usage: nmcli connection delete { ARGUMENTS | help }\n"
+	           "\n"
+	           "ARGUMENTS := [id | uuid | path] <ID>\n"
+	           "\n"
+	           "Delete a connection profile.\n"
+	           "The profile is identified by its name, UUID or D-Bus path.\n\n"));
+}
 
-	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
-		fields_str = nmc->required_fields;
+static void
+usage_connection_reload (void)
+{
+	fprintf (stderr,
+	         _("Usage: nmcli connection reload { help }\n"
+	           "\n"
+	           "Reload all connection files from disk.\n\n"));
+}
 
-	nmc->allowed_fields = nmc_fields_con_list;
-	nmc->print_fields.indices = parse_output_fields (fields_str, nmc->allowed_fields, &error1);
-	/* error1 is checked later - it's not valid for connection details */
+static void
+usage_connection_load (void)
+{
+	fprintf (stderr,
+	         _("Usage: nmcli connection load { ARGUMENTS | help }\n"
+	           "\n"
+	           "ARGUMENTS := <filename> [<filename>...]\n"
+	           "\n"
+	           "Load/reload one or more connection files from disk. Use this after manually\n"
+	           "editing a connection file to ensure that NetworkManager is aware of its latest\n"
+	           "state.\n\n"));
+}
 
-	if (argc == 0) {
-		if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error2))
-			goto error;
-		if (error1)
-			goto error;
-		valid_param_specified = TRUE;
 
-		/* Print headers */
-		nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ADD | NMC_PF_FLAG_FIELD_NAMES;
-		nmc->print_fields.header_name = _("Connection list");
-		print_fields (nmc->print_fields, nmc->allowed_fields);
+/* The real commands that do something - i.e. not 'help', etc. */
+static const char *real_con_commands[] = {
+	"show",
+	"up",
+	"down",
+	"add",
+	"modify",
+	"edit",
+	"delete",
+	"reload",
+	"load",
+	NULL
+};
 
-		/* Print values */
-		g_slist_foreach (nmc->system_connections, (GFunc) show_connection, nmc);
+/* quit main loop */
+static void
+quit (void)
+{
+	if (progress_id) {
+		g_source_remove (progress_id);
+		progress_id = 0;
+		nmc_terminal_erase_line ();
 	}
-	else {
-		while (argc > 0) {
-			if (strcmp (*argv, "id") == 0 || strcmp (*argv, "uuid") == 0) {
-				const char *selector = *argv;
-				NMConnection *con;
-
-				if (next_arg (&argc, &argv) != 0) {
-					g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
-					nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-					return nmc->return_value;
-				}
-				valid_param_specified = TRUE;
-				if (!nmc->mode_specified)
-					nmc->multiline_output = TRUE;  /* multiline mode is default for 'con list id|uuid' */
 
-				con = find_connection (nmc->system_connections, selector, *argv);
-				if (con) {
-					nmc_connection_detail (con, nmc);
-				}
-				else {
-					g_string_printf (nmc->return_text, _("Error: %s - no such connection."), *argv);
-					nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
-				}
-				break;
-			}
-			else {
-				fprintf (stderr, _("Unknown parameter: %s\n"), *argv);
-			}
+	g_main_loop_quit (loop);  /* quit main loop */
+}
 
-			argc--;
-			argv++;
-		}
-	}
+static const char *
+construct_header_name (const char *base, const char *spec)
+{
+	static char header_name[128];
 
-	if (!valid_param_specified) {
-		g_string_printf (nmc->return_text, _("Error: no valid parameter specified."));
-		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-	}
-	return nmc->return_value;
+	if (spec == NULL)
+		return base;
 
-error:
-	if (error1) {
-		if (error1->code == 0)
-			g_string_printf (nmc->return_text, _("Error: 'con list': %s"), error1->message);
-		else
-			g_string_printf (nmc->return_text, _("Error: 'con list': %s; allowed fields: %s"), error1->message, NMC_FIELDS_CON_LIST_ALL);
-		g_error_free (error1);
-		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-	}
-	if (error2) {
-		g_string_printf (nmc->return_text, _("Error: %s."), error2->message);
-		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-		g_error_free (error2);
-	}
+	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 nmc->return_value;
+	return header_name;
 }
 
 static const char *
@@ -495,6 +589,55 @@ vpn_connection_state_to_string (NMVPNConnectionState state)
 	}
 }
 
+/* Caller has to free the returned string */
+static char *
+get_ac_device_string (NMActiveConnection *active)
+{
+	GString *dev_str;
+	const GPtrArray *devices;
+	int i;
+
+	if (!active)
+		return NULL;
+
+	/* Get devices of the active connection */
+	dev_str = g_string_new (NULL);
+	devices = nm_active_connection_get_devices (active);
+	for (i = 0; devices && (i < devices->len); i++) {
+		NMDevice *device = g_ptr_array_index (devices, i);
+		const char *dev_iface = nm_device_get_iface (device);
+
+		if (dev_iface) {
+			g_string_append (dev_str, dev_iface);
+			g_string_append_c (dev_str, ',');
+		}
+	}
+	if (dev_str->len > 0)
+		g_string_truncate (dev_str, dev_str->len - 1);  /* Cut off last ',' */
+
+	return g_string_free (dev_str, FALSE);
+}
+
+static NMActiveConnection *
+get_ac_for_connection (const GPtrArray *active_cons, NMConnection *connection)
+{
+	const char *con_path;
+	int i;
+	NMActiveConnection *ac = NULL;
+
+	/* Is the connection active? */
+	con_path = nm_connection_get_path (connection);
+	for (i = 0; active_cons && i < active_cons->len; i++) {
+		NMActiveConnection *candidate = g_ptr_array_index (active_cons, i);
+
+		if (!g_strcmp0 (nm_active_connection_get_connection (candidate), con_path)) {
+			ac = candidate;
+			break;
+		}
+	}
+	return ac;
+}
+
 static NMConnection *
 get_connection_for_active (const GSList *con_list, NMActiveConnection *active)
 {
@@ -514,7 +657,188 @@ get_connection_for_active (const GSList *con_list, NMActiveConnection *active)
 }
 
 static gboolean
-fill_in_fields_con_status (NMActiveConnection *active, GSList *con_list)
+nmc_connection_profile_details (NMConnection *connection, NmCli *nmc)
+{
+	GError *error = NULL;
+	GArray *print_settings_array;
+	GPtrArray *prop_array = NULL;
+	int i;
+	char *fields_str;
+	char *fields_all =    NMC_FIELDS_SETTINGS_NAMES_ALL;
+	char *fields_common = NMC_FIELDS_SETTINGS_NAMES_ALL;
+	const char *base_hdr = _("Connection profile 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
+		fields_str = nmc->required_fields;
+
+	print_settings_array = parse_output_fields (fields_str, nmc_fields_settings_names, TRUE, &prop_array, &error);
+	if (error) {
+		g_string_printf (nmc->return_text, _("Error: 'connection show': %s"), error->message);
+		g_error_free (error);
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		return FALSE;
+	}
+	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);
+
+	nmc_fields_settings_names[0].flags = NMC_OF_FLAG_MAIN_HEADER_ONLY;
+	print_required_fields (nmc, nmc_fields_settings_names);
+
+	/* Loop through the required settings and print them. */
+	for (i = 0; i < print_settings_array->len; i++) {
+		NMSetting *setting;
+		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)
+			printf ("\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);
+		if (setting) {
+			setting_details (setting, nmc, prop_name);
+			was_output = TRUE;
+			continue;
+		}
+	}
+
+	g_array_free (print_settings_array, TRUE);
+	if (prop_array)
+		g_ptr_array_free (prop_array, TRUE);
+
+	return TRUE;
+}
+
+static NMActiveConnection *
+find_active_connection (const GPtrArray *active_cons,
+                        const GSList *cons,
+                        const char *filter_type,
+                        const char *filter_val,
+                        int *idx)
+{
+	int i;
+	int start = (idx && *idx > 0) ? *idx : 0;
+	const char *path, *a_path, *path_num, *a_path_num;
+	const char *id;
+	const char *uuid;
+	NMConnection *con;
+	NMActiveConnection *found = NULL;
+
+	for (i = start; active_cons && (i < active_cons->len); i++) {
+		NMActiveConnection *candidate = g_ptr_array_index (active_cons, i);
+
+		path = nm_active_connection_get_connection (candidate);
+		a_path = nm_object_get_path (NM_OBJECT (candidate));
+		uuid = nm_active_connection_get_uuid (candidate);
+		path_num = path ? strrchr (path, '/') + 1 : NULL;
+		a_path_num = a_path ? strrchr (a_path, '/') + 1 : NULL;
+
+		con = get_connection_for_active (cons, candidate);
+		id = nm_connection_get_id (con);
+
+		/* When filter_type is NULL, compare connection ID (filter_val)
+		 * against all types. Otherwise, only compare against the specific
+		 * type. If 'path' or 'apath' filter types are specified, comparison
+		 * against numeric index (in addition to the whole path) is allowed.
+		 */
+		if (   (   (!filter_type || strcmp (filter_type, "id")  == 0)
+		        && strcmp (filter_val, id) == 0)
+		    || (   (!filter_type || strcmp (filter_type, "uuid") == 0)
+		        && strcmp (filter_val, uuid) == 0)
+		    || (   (!filter_type || strcmp (filter_type, "path") == 0)
+		        && (g_strcmp0 (filter_val, path) == 0 || (filter_type && g_strcmp0 (filter_val, path_num) == 0)))
+		    || (   (!filter_type || strcmp (filter_type, "apath") == 0)
+		        && (g_strcmp0 (filter_val, a_path) == 0 || (filter_type && g_strcmp0 (filter_val, a_path_num) == 0)))) {
+			if (!idx)
+				return candidate;
+			if (found) {
+				*idx = i;
+				return found;
+			}
+			found = candidate;
+		}
+	}
+
+	if (idx)
+		*idx = 0;
+	return found;
+}
+
+static void
+fill_output_connection (gpointer data, gpointer user_data, gboolean active_only)
+{
+	NMConnection *connection = (NMConnection *) data;
+	NmCli *nmc = (NmCli *) user_data;
+	NMSettingConnection *s_con;
+	guint64 timestamp;
+	time_t timestamp_real;
+	char *timestamp_str;
+	char *timestamp_real_str = "";
+	NmcOutputField *arr;
+	NMActiveConnection *ac = NULL;
+	const char *ac_path = NULL;
+	const char *ac_state = NULL;
+	char *ac_dev = NULL;
+
+	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);
+	if (active_only && !ac)
+		return;
+
+	if (ac) {
+		ac_path = nm_object_get_path (NM_OBJECT (ac));
+		ac_state = active_connection_state_to_string (nm_active_connection_get_state (ac));
+		ac_dev = get_ac_device_string (ac);
+	}
+
+	/* Obtain field values */
+	timestamp = nm_setting_connection_get_timestamp (s_con);
+	timestamp_str = g_strdup_printf ("%" G_GUINT64_FORMAT, timestamp);
+	if (timestamp) {
+		timestamp_real = timestamp;
+		timestamp_real_str = g_malloc0 (64);
+		strftime (timestamp_real_str, 64, "%c", localtime (&timestamp_real));
+	}
+
+	arr = nmc_dup_fields_array (nmc_fields_con_show,
+	                            sizeof (nmc_fields_con_show),
+	                            0);
+	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_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"));
+	set_val_strc (arr, 6, nm_setting_connection_get_read_only (s_con) ? _("yes") : _("no"));
+	set_val_strc (arr, 7, nm_connection_get_path (connection));
+	set_val_strc (arr, 8, ac ? _("yes") : _("no"));
+	set_val_str  (arr, 9, ac_dev);
+	set_val_strc (arr, 10, ac_state);
+	set_val_strc (arr, 11, ac_path);
+
+	g_ptr_array_add (nmc->output_data, arr);
+}
+
+static void
+fill_output_active_connection (NMActiveConnection *active,
+                               NmCli *nmc,
+                               gboolean with_group,
+                               guint32 o_flags)
 {
 	GSList *iter;
 	const char *active_path;
@@ -523,7 +847,10 @@ fill_in_fields_con_status (NMActiveConnection *active, GSList *con_list)
 	GString *dev_str;
 	NMActiveConnectionState state;
 	int i;
-	gboolean success = FALSE;
+	GSList *con_list = nmc->system_connections;
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
+	int idx_start = with_group ? 0 : 1;
 
 	active_path = nm_active_connection_get_connection (active);
 	state = nm_active_connection_get_state (active);
@@ -543,20 +870,29 @@ fill_in_fields_con_status (NMActiveConnection *active, GSList *con_list)
 	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++;
+		tmpl_len -= sizeof (NmcOutputField);
+	}
+
 	/* Fill field values */
-	nmc_fields_con_status[0].value = nmc_fields_status_details_groups[0].name;
-	nmc_fields_con_status[1].value = _("N/A");
-	nmc_fields_con_status[2].value = nm_active_connection_get_uuid (active);
-	nmc_fields_con_status[3].value = dev_str->str;
-	nmc_fields_con_status[4].value = active_connection_state_to_string (state);
-	nmc_fields_con_status[5].value = nm_active_connection_get_default (active) ? _("yes") : _("no");
-	nmc_fields_con_status[6].value = nm_active_connection_get_default6 (active) ? _("yes") : _("no");
-	nmc_fields_con_status[7].value = nm_active_connection_get_specific_object (active);
-	nmc_fields_con_status[8].value = NM_IS_VPN_CONNECTION (active) ? _("yes") : _("no");
-	nmc_fields_con_status[9].value = nm_object_get_path (NM_OBJECT (active));
-	nmc_fields_con_status[10].value = nm_active_connection_get_connection (active);
-	nmc_fields_con_status[11].value = _("N/A");
-	nmc_fields_con_status[12].value = nm_active_connection_get_master (active);
+	arr = nmc_dup_fields_array (tmpl, tmpl_len, o_flags);
+	if (with_group)
+		set_val_strc (arr, 0, nmc_fields_con_active_details_groups[0].name);
+	set_val_strc (arr, 1-idx_start, _("N/A"));
+	set_val_strc (arr, 2-idx_start, nm_active_connection_get_uuid (active));
+	set_val_str  (arr, 3-idx_start, dev_str->str);
+	set_val_strc (arr, 4-idx_start, active_connection_state_to_string (state));
+	set_val_strc (arr, 5-idx_start, nm_active_connection_get_default (active) ? _("yes") : _("no"));
+	set_val_strc (arr, 6-idx_start, nm_active_connection_get_default6 (active) ? _("yes") : _("no"));
+	set_val_strc (arr, 7-idx_start, nm_active_connection_get_specific_object (active));
+	set_val_strc (arr, 8-idx_start, NM_IS_VPN_CONNECTION (active) ? _("yes") : _("no"));
+	set_val_strc (arr, 9-idx_start, nm_object_get_path (NM_OBJECT (active)));
+	set_val_strc (arr, 10-idx_start, nm_active_connection_get_connection (active));
+	set_val_strc (arr, 11-idx_start, _("N/A"));
+	set_val_strc (arr, 12-idx_start, nm_active_connection_get_master (active));
 
 	for (iter = con_list; iter; iter = g_slist_next (iter)) {
 		NMConnection *connection = (NMConnection *) iter->data;
@@ -568,75 +904,15 @@ fill_in_fields_con_status (NMActiveConnection *active, GSList *con_list)
 			g_assert (s_con != NULL);
 
 			/* Fill field values that depend on NMConnection */
-			nmc_fields_con_status[1].value = nm_setting_connection_get_id (s_con);
-			nmc_fields_con_status[11].value = nm_setting_connection_get_zone (s_con);
+			set_val_strc (arr, 1-idx_start,  nm_setting_connection_get_id (s_con));
+			set_val_strc (arr, 11-idx_start, nm_setting_connection_get_zone (s_con));
 
-			success = TRUE;
 			break;
 		}
 	}
+	g_ptr_array_add (nmc->output_data, arr);
 
-	/* Just free GString here, the char array has to be freed after printing
-	 * (by free_fields_con_status()) */
 	g_string_free (dev_str, FALSE);
-	return success;
-}
-
-static void
-free_fields_con_status (void)
-{
-	/* Just DEVICES string was dynamically allocated */
-	g_free ((char *) nmc_fields_con_status[3].value);
-	nmc_fields_con_status[3].value = NULL;
-}
-
-static void
-show_active_connection (gpointer data, gpointer user_data)
-{
-	NMActiveConnection *active = NM_ACTIVE_CONNECTION (data);
-	NmCli *nmc = (NmCli *) user_data;
-
-	fill_in_fields_con_status (active, nmc->system_connections);
-
-	nmc->print_fields.flags &= ~NMC_PF_FLAG_MAIN_HEADER_ADD & ~NMC_PF_FLAG_MAIN_HEADER_ONLY & ~NMC_PF_FLAG_FIELD_NAMES; /* Clear header flags */
-	print_fields (nmc->print_fields, nmc->allowed_fields);
-
-	free_fields_con_status ();
-}
-
-static NMActiveConnection *
-find_active_connection (const GPtrArray *active_cons, const GSList *cons,
-                        const char *filter_type, const char *filter_val)
-{
-	int i;
-	const char *s_path, *a_path;
-	const char *id;
-	const char *uuid;
-	NMConnection *con;
-	NMSettingConnection *s_con;
-
-	for (i = 0; active_cons && (i < active_cons->len); i++) {
-		NMActiveConnection *candidate = g_ptr_array_index (active_cons, i);
-
-		s_path = nm_active_connection_get_connection (candidate);
-		a_path = nm_object_get_path (NM_OBJECT (candidate));
-		uuid = nm_active_connection_get_uuid (candidate);
-
-		con = get_connection_for_active (cons, candidate);
-		s_con = nm_connection_get_setting_connection (con);
-		g_assert (s_con != NULL);
-		id = nm_setting_connection_get_id (s_con);
-
-		if (filter_type) {
-			if (   (strcmp (filter_type, "id") == 0 && strcmp (filter_val, id) == 0)
-			    || (strcmp (filter_type, "uuid") == 0 && strcmp (filter_val, uuid) == 0)
-			    || (strcmp (filter_type, "path") == 0 && strcmp (filter_val, s_path) == 0)
-			    || (strcmp (filter_type, "path") == 0 && strcmp (filter_val, a_path) == 0)) {
-				return candidate;
-			}
-		}
-	}
-	return NULL;
 }
 
 typedef struct {
@@ -683,6 +959,9 @@ find_vpn_gateway_key (const char *vpn_type)
 	if (g_strcmp0 (vpn_type, "pptp") == 0)        return "gateway";
 	if (g_strcmp0 (vpn_type, "openconnect") == 0) return "gateway";
 	if (g_strcmp0 (vpn_type, "openswan") == 0)    return "right";
+	if (g_strcmp0 (vpn_type, "libreswan") == 0)   return "right";
+	if (g_strcmp0 (vpn_type, "ssh") == 0)         return "remote";
+	if (g_strcmp0 (vpn_type, "l2tp") == 0)        return "gateway";
 	return "";
 }
 
@@ -694,6 +973,8 @@ find_vpn_username_key (const char *vpn_type)
 	if (g_strcmp0 (vpn_type, "pptp") == 0)        return "user";
 	if (g_strcmp0 (vpn_type, "openconnect") == 0) return "username";
 	if (g_strcmp0 (vpn_type, "openswan") == 0)    return "leftxauthusername";
+	if (g_strcmp0 (vpn_type, "libreswan") == 0)   return "leftxauthusername";
+	if (g_strcmp0 (vpn_type, "l2tp") == 0)        return "user";
 	return "";
 }
 
@@ -726,17 +1007,18 @@ get_vpn_data_item (NMConnection *connection, enum VpnDataItem vpn_data_item)
 /* FIXME end */
 
 static gboolean
-nmc_active_connection_detail (NMActiveConnection *acon, NmCli *nmc)
+nmc_active_connection_details (NMActiveConnection *acon, NmCli *nmc)
 {
 	GError *error = NULL;
 	GArray *print_groups;
+	GPtrArray *group_fields = NULL;
 	int i;
 	char *fields_str;
-	char *fields_all =    NMC_FIELDS_CON_STATUS_DETAILS_ALL;
-	char *fields_common = NMC_FIELDS_CON_STATUS_DETAILS_ALL;
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+	char *fields_all =    NMC_FIELDS_CON_ACTIVE_DETAILS_ALL;
+	char *fields_common = NMC_FIELDS_CON_ACTIVE_DETAILS_ALL;
+	NmcOutputField *tmpl, *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)
@@ -746,77 +1028,93 @@ nmc_active_connection_detail (NMActiveConnection *acon, NmCli *nmc)
 	else
 		fields_str = nmc->required_fields;
 
-	print_groups = parse_output_fields (fields_str, nmc_fields_status_details_groups, &error);
+	print_groups = parse_output_fields (fields_str, nmc_fields_con_active_details_groups, TRUE, &group_fields, &error);
 	if (error) {
-		if (error->code == 0)
-			g_string_printf (nmc->return_text, _("Error: 'con status': %s"), error->message);
-		else
-			g_string_printf (nmc->return_text, _("Error: 'con status': %s; allowed fields: %s"), error->message, NMC_FIELDS_CON_STATUS_DETAILS_ALL);
+		g_string_printf (nmc->return_text, _("Error: 'connection show': %s"), error->message);
 		g_error_free (error);
 		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
 		return FALSE;
 	}
+	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);
 
-	nmc->allowed_fields = nmc_fields_status_details_groups;
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ONLY;
-	nmc->print_fields.header_name = _("Active connection details");
-	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_CON_STATUS_DETAILS_ALL, nmc->allowed_fields, NULL);
-	print_fields (nmc->print_fields, nmc->allowed_fields);
+	nmc_fields_con_active_details_groups[0].flags = NMC_OF_FLAG_MAIN_HEADER_ONLY;
+	print_required_fields (nmc, nmc_fields_con_active_details_groups);
 
 	/* 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)
 			printf ("\n"); /* Empty line */
 
 		was_output = FALSE;
 
-		/* GENERAL */
-		if (strcasecmp (nmc_fields_status_details_groups[group_idx].name, nmc_fields_status_details_groups[0].name) == 0) {
-			nmc->allowed_fields = nmc_fields_con_status;
-			nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_CON_STATUS_DETAILS_GENERAL_ALL, nmc->allowed_fields, NULL);
+		/* Remove any previous data */
+		nmc_empty_output_fields (nmc);
 
-			/* Print field names */
-			nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-			print_fields (nmc->print_fields, nmc->allowed_fields);
+		/* GENERAL */
+		if (strcasecmp (nmc_fields_con_active_details_groups[group_idx].name, nmc_fields_con_active_details_groups[0].name) == 0) {
+			/* Add field names */
+			tmpl = 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);
 
 			/* Fill in values */
-			fill_in_fields_con_status (acon, nmc->system_connections);
+			fill_output_active_connection (acon, nmc, TRUE, NMC_OF_FLAG_SECTION_PREFIX);
 
-			/* and print them */
-			nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-			print_fields (nmc->print_fields, nmc->allowed_fields);
+			print_data (nmc);  /* Print all data */
 
-			free_fields_con_status ();
 			was_output = TRUE;
 		}
 
-		/* IP */
-		if (strcasecmp (nmc_fields_status_details_groups[group_idx].name,  nmc_fields_status_details_groups[1].name) == 0) {
-			const GPtrArray *devices;
-			int j;
+		/* IP4 */
+		if (strcasecmp (nmc_fields_con_active_details_groups[group_idx].name,  nmc_fields_con_active_details_groups[1].name) == 0) {
+			gboolean b1 = FALSE;
+			NMIP4Config *cfg4 = nm_active_connection_get_ip4_config (acon);
 
-			devices = nm_active_connection_get_devices (acon);
-			for (j = 0; devices && (j < devices->len); j++) {
-				gboolean b1 = FALSE, b2 = FALSE, b3 = FALSE, b4 = FALSE;
-				NMDevice *device = g_ptr_array_index (devices, j);
-				NMIP4Config *cfg4 = nm_device_get_ip4_config (device);
-				NMIP6Config *cfg6 = nm_device_get_ip6_config (device);
-				NMDHCP4Config *dhcp4 = nm_device_get_dhcp4_config (device);
-				NMDHCP6Config *dhcp6 = nm_device_get_dhcp6_config (device);
+			b1 = print_ip4_config (cfg4, nmc, "IP4", group_fld);
+			was_output = was_output || b1;
+		}
 
-				b1 = print_ip4_config (cfg4, nmc, "IP4");
-				b2 = print_dhcp4_config (dhcp4, nmc, "DHCP4");
-				b3 = print_ip6_config (cfg6, nmc, "IP6");
-				b4 = print_dhcp6_config (dhcp6, nmc, "DHCP6");
-				was_output = was_output || b1 || b2 || b3 || b4;
-			}
+		/* DHCP4 */
+		if (strcasecmp (nmc_fields_con_active_details_groups[group_idx].name,  nmc_fields_con_active_details_groups[2].name) == 0) {
+			gboolean b1 = FALSE;
+			NMDHCP4Config *dhcp4 = nm_active_connection_get_dhcp4_config (acon);
+
+			b1 = print_dhcp4_config (dhcp4, nmc, "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) {
+			gboolean b1 = FALSE;
+			NMIP6Config *cfg6 = nm_active_connection_get_ip6_config (acon);
+
+			b1 = print_ip6_config (cfg6, nmc, "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) {
+			gboolean b1 = FALSE;
+			NMDHCP6Config *dhcp6 = nm_active_connection_get_dhcp6_config (acon);
+
+			b1 = print_dhcp6_config (dhcp6, nmc, "DHCP6", group_fld);
+			was_output = was_output || b1;
 		}
 
 		/* VPN */
 		if (NM_IS_VPN_CONNECTION (acon) &&
-		    strcasecmp (nmc_fields_status_details_groups[group_idx].name,  nmc_fields_status_details_groups[2].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;
@@ -831,12 +1129,12 @@ nmc_active_connection_detail (NMActiveConnection *acon, NmCli *nmc)
 			s_con = nm_connection_get_setting_connection (con);
 			g_assert (s_con != NULL);
 
-			nmc->allowed_fields = nmc_fields_status_details_vpn;
-			nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_CON_STATUS_DETAILS_VPN_ALL, nmc->allowed_fields, NULL);
-
-			/* Print field names */
-			nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-			print_fields (nmc->print_fields, nmc->allowed_fields);
+			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);
 
 			s_vpn = nm_connection_get_setting_vpn (con);
 			if (s_vpn) {
@@ -858,64 +1156,167 @@ nmc_active_connection_detail (NMActiveConnection *acon, NmCli *nmc)
 			vpn_state = nm_vpn_connection_get_vpn_state (NM_VPN_CONNECTION (acon));
 			vpn_state_str = g_strdup_printf ("%d - %s", vpn_state, vpn_connection_state_to_string (vpn_state));
 
-			/* Print values */
-			set_val_str (nmc->allowed_fields, 0, nmc_fields_status_details_groups[2].name);
-			set_val_str (nmc->allowed_fields, 1, type_str);
-			set_val_str (nmc->allowed_fields, 2, username ? username : get_vpn_data_item (con, VPN_DATA_ITEM_USERNAME));
-			set_val_str (nmc->allowed_fields, 3, get_vpn_data_item (con, VPN_DATA_ITEM_GATEWAY));
-			set_val_str (nmc->allowed_fields, 4, banner_str);
-			set_val_str (nmc->allowed_fields, 5, vpn_state_str);
-			set_val_arr (nmc->allowed_fields, 6, (const char **) vpn_data_array);
-
-			nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-			print_fields (nmc->print_fields, nmc->allowed_fields);
-
-			g_free (type_str);
-			g_free (banner_str);
-			g_free (vpn_state_str);
-			g_strfreev (vpn_data_array);
+			/* 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);
+			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);
+
+			print_data (nmc);  /* Print all data */
 			was_output = TRUE;
 		}
 	}
 
-	if (print_groups)
-		g_array_free (print_groups, FALSE);
+	g_array_free (print_groups, TRUE);
+	if (group_fields)
+		g_ptr_array_free (group_fields, TRUE);
 
 	return TRUE;
 }
 
-static NMCResultCode
-do_connections_status (NmCli *nmc, int argc, char **argv)
+static gboolean
+split_required_fields_for_con_show (const char *input,
+                                    char **profile_flds,
+                                    char **active_flds,
+                                    GError **error)
 {
-	const GPtrArray *active_cons;
-	GError *err = NULL;
-	GError *err1 = NULL;
+	char **fields, **iter;
+	char *dot;
+	GString *str1, *str2;
+	gboolean found;
+	gboolean group_profile = FALSE;
+	gboolean group_active = FALSE;
+	gboolean success = TRUE;
+	gboolean is_all, is_common;
+	int i;
 
-	nmc->should_wait = FALSE;
+	if (!input) {
+		*profile_flds = NULL;
+		*active_flds = NULL;
+		return TRUE;
+	}
 
-	if (!nmc_is_nm_running (nmc, &err)) {
-		if (err) {
-			g_string_printf (nmc->return_text, _("Error: Can't find out if NetworkManager is running: %s."), err->message);
-			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
-			g_error_free (err);
-		} else {
-			g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
-			nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
+	str1 = g_string_new (NULL);
+	str2 = g_string_new (NULL);
+
+	/* Split supplied fields string */
+	fields = g_strsplit_set (input, ",", -1);
+	for (iter = fields; iter && *iter; iter++) {
+		g_strstrip (*iter);
+		dot = strchr (*iter, '.');
+		if (dot)
+			*dot = '\0';
+
+		is_all = !dot && strcasecmp (*iter, "all") == 0;
+		is_common = !dot && strcasecmp (*iter, "common") == 0;
+
+		found = FALSE;
+
+		for (i = 0; nmc_fields_settings_names[i].name; i++) {
+			if (   is_all || is_common
+			    || !strcasecmp (*iter, nmc_fields_settings_names[i].name)) {
+				if (dot)
+					*dot = '.';
+				g_string_append (str1, *iter);
+				g_string_append_c (str1, ',');
+				found = TRUE;
+				break;
+			}
 		}
-		goto error;
+		if (found)
+			continue;
+		for (i = 0; nmc_fields_con_active_details_groups[i].name; i++) {
+			if (   is_all || is_common
+			    || !strcasecmp (*iter, nmc_fields_con_active_details_groups[i].name)) {
+				if (dot)
+					*dot = '.';
+				g_string_append (str2, *iter);
+				g_string_append_c (str2, ',');
+				found = TRUE;
+				break;
+			}
+		}
+		if (!found) {
+			if (dot)
+				*dot = '.';
+			if (!strcasecmp (*iter, CON_SHOW_DETAIL_GROUP_PROFILE))
+				group_profile = TRUE;
+			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);
+				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);
+				g_free (allowed2);
+				success = FALSE;
+				break;
+			}
+		}
+	}
+	if (fields)
+		g_strfreev (fields);
+
+	/* Handle pseudo groups: profile, active */
+	if (success && group_profile) {
+		if (str1->len > 0) {
+			g_set_error (error, NMCLI_ERROR, 0, _("'%s' has to be alone"),
+			             CON_SHOW_DETAIL_GROUP_PROFILE);
+			success = FALSE;
+		} else
+			g_string_assign (str1, "all,");
+	}
+	if (success && group_active) {
+		if (str2->len > 0) {
+			g_set_error (error, NMCLI_ERROR, 0, _("'%s' has to be alone"),
+			             CON_SHOW_DETAIL_GROUP_ACTIVE);
+			success = FALSE;
+		} else
+			g_string_assign (str2, "all,");
 	}
 
-	/* Get active connections */
+	if (success) {
+		if (str1->len > 0)
+			g_string_truncate (str1, str1->len - 1);
+		if (str2->len > 0)
+			g_string_truncate (str2, str2->len - 1);
+		*profile_flds = g_string_free (str1, str1->len == 0);
+		*active_flds = g_string_free (str2, str2->len == 0);
+	} else {
+		g_string_free (str1, TRUE);
+		g_string_free (str2, TRUE);
+	}
+	return success;
+}
+
+static NMCResultCode
+do_connections_show (NmCli *nmc, gboolean active_only, int argc, char **argv)
+{
+	GError *err = NULL;
+	char *profile_flds = NULL, *active_flds = NULL;
+
+	nmc->should_wait = FALSE;
 	nmc->get_client (nmc);
-	active_cons = nm_client_get_active_connections (nmc->client);
+
+	if (!nm_client_get_manager_running (nmc->client)) {
+		g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
+		nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
+		goto finish;
+	}
 
 	if (argc == 0) {
 		char *fields_str;
-		char *fields_all =    NMC_FIELDS_CON_STATUS_ALL;
-		char *fields_common = NMC_FIELDS_CON_STATUS_COMMON;
-		guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-		guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-		guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+		char *fields_all =    NMC_FIELDS_CON_SHOW_ALL;
+		char *fields_common = NMC_FIELDS_CON_SHOW_COMMON;
+		NmcOutputField *tmpl, *arr;
+		size_t tmpl_len;
+		GSList *iter;
 
 		if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0)
 			fields_str = fields_common;
@@ -924,61 +1325,127 @@ do_connections_status (NmCli *nmc, int argc, char **argv)
 		else
 			fields_str = nmc->required_fields;
 
-		nmc->allowed_fields = nmc_fields_con_status + 1 ;
-		nmc->print_fields.indices = parse_output_fields (fields_str, nmc->allowed_fields, &err1);
-		if (err1)
-			goto error;
+		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);
+		if (err) {
+			goto finish;
+		}
+		if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &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);
+
+		/* Add values */
+		for (iter = nmc->system_connections; iter; iter = g_slist_next (iter)) {
+			NMConnection *con = NM_CONNECTION (iter->data);
+			fill_output_connection (con, nmc, active_only);
+		}
+		print_data (nmc);  /* Print all data */
+	} else {
+		gboolean new_line = FALSE;
+		gboolean without_fields = (nmc->required_fields == NULL);
+		const GPtrArray *active_cons = nm_client_get_active_connections (nmc->client);
+		GSList *pos = NULL;
 
-		/* Print headers */
-		nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ADD | NMC_PF_FLAG_FIELD_NAMES;
-		nmc->print_fields.header_name = _("Active connections");
-		print_fields (nmc->print_fields, nmc->allowed_fields);
+		/* multiline mode is default for 'connection show <ID>' */
+		if (!nmc->mode_specified)
+			nmc->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))
+			goto finish;
+		g_free (nmc->required_fields);
+		nmc->required_fields = NULL;
 
-		if (active_cons && active_cons->len)
-			g_ptr_array_foreach ((GPtrArray *) active_cons, show_active_connection, (gpointer) nmc);
-	} else {
 		while (argc > 0) {
+			NMConnection *con;
+			NMActiveConnection *acon = NULL;
+			const char *selector = NULL;
+
 			if (   strcmp (*argv, "id") == 0
 			    || strcmp (*argv, "uuid") == 0
-			    || strcmp (*argv, "path") == 0) {
-				const char *selector = *argv;
-				NMActiveConnection *acon;
-
+			    || strcmp (*argv, "path") == 0
+			    || strcmp (*argv, "apath") == 0) {
+				selector = *argv;
 				if (next_arg (&argc, &argv) != 0) {
 					g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
 					nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-					return nmc->return_value;
+					goto finish;
 				}
-				if (!nmc->mode_specified)
-					nmc->multiline_output = TRUE;  /* multiline mode is default for 'con status id|uuid|path' */
+			}
 
-				acon = find_active_connection (active_cons, nmc->system_connections, selector, *argv);
-				if (acon) {
-					nmc_active_connection_detail (acon, nmc);
-				} else {
-					g_string_printf (nmc->return_text, _("Error: '%s' is not an active connection."), *argv);
-					nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+			/* Find connection by id, uuid, path or apath */
+			con = nmc_find_connection (nmc->system_connections, selector, *argv, &pos);
+			if (!con) {
+				acon = find_active_connection (active_cons, nmc->system_connections, selector, *argv, NULL);
+				if (acon)
+					con = get_connection_for_active (nmc->system_connections, acon);
+			}
+
+			/* Print connection details */
+			if (con) {
+				gboolean res;
+
+				/* Filter only active connections */
+				if (!acon)
+					acon = get_ac_for_connection (active_cons, con);
+				if (active_only && !acon) {
+					next_arg (&argc, &argv);
+					continue;
 				}
-				break;
+
+				/* Show an empty line between connections */
+				if (new_line)
+					printf ("\n");
+
+				/* Show profile configuration */
+				if (without_fields || profile_flds) {
+					nmc->required_fields = profile_flds;
+					res = nmc_connection_profile_details (con, nmc);
+					nmc->required_fields = NULL;
+					if (!res)
+						goto finish;
+				}
+
+				/* If the profile is active, print also active details */
+				if (without_fields || active_flds) {
+					if (acon) {
+						nmc->required_fields = active_flds;
+						res = nmc_active_connection_details (acon, nmc);
+						nmc->required_fields = NULL;
+						if (!res)
+							goto finish;
+					}
+				}
+				new_line = TRUE;
 			} else {
-				g_string_printf (nmc->return_text, _("Error: unknown parameter: %s"), *argv);
-				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				g_string_printf (nmc->return_text, _("Error: %s - no such connection profile."), *argv);
+				nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
+				goto finish;
 			}
-
-			argc--;
-			argv++;
+			
+			/* Take next argument.
+			 * But for pos != NULL we have more connections of the same name,
+			 * so process the same argument again.
+			 */
+			if (!pos)
+				next_arg (&argc, &argv);
 		}
 	}
 
-error:
-	if (err1) {
-		if (err1->code == 0)
-			g_string_printf (nmc->return_text, _("Error: 'con status': %s"), err1->message);
-		else
-			g_string_printf (nmc->return_text, _("Error: 'con status': %s; allowed fields: %s"), err1->message, NMC_FIELDS_CON_STATUS_ALL);
-		g_error_free (err1);
+finish:
+	if (err) {
+		g_string_printf (nmc->return_text, _("Error: %s."), err->message);
 		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		g_error_free (err);
 	}
+	g_free (profile_flds);
+	g_free (active_flds);
 	return nmc->return_value;
 }
 
@@ -1199,13 +1666,13 @@ active_connection_state_cb (NMActiveConnection *active, GParamSpec *pspec, gpoin
 	state = nm_active_connection_get_state (active);
 
 	if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
-		if (nmc->print_output == NMC_PRINT_PRETTY) {
+		if (nmc->print_output == NMC_PRINT_PRETTY)
 			nmc_terminal_erase_line ();
-			printf (_("Connection successfully activated (D-Bus active path: %s)\n"),
-			        nm_object_get_path (NM_OBJECT (active)));
-		}
+		printf (_("Connection successfully activated (D-Bus active path: %s)\n"),
+		        nm_object_get_path (NM_OBJECT (active)));
 		quit ();
-	} else if (state == NM_ACTIVE_CONNECTION_STATE_UNKNOWN) {
+	} else if (   state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED
+	           || state == NM_ACTIVE_CONNECTION_STATE_UNKNOWN) {
 		g_string_printf (nmc->return_text, _("Error: Connection activation failed."));
 		nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
 		quit ();
@@ -1229,11 +1696,10 @@ vpn_connection_state_cb (NMVPNConnection *vpn,
 		break;
 
 	case NM_VPN_CONNECTION_STATE_ACTIVATED:
-		if (nmc->print_output == NMC_PRINT_PRETTY) {
+		if (nmc->print_output == NMC_PRINT_PRETTY)
 			nmc_terminal_erase_line ();
-			printf (_("VPN connection successfully activated (D-Bus active path: %s)\n"),
-			        nm_object_get_path (NM_OBJECT (vpn)));
-		}
+		printf (_("VPN connection successfully activated (D-Bus active path: %s)\n"),
+		        nm_object_get_path (NM_OBJECT (vpn)));
 		quit ();
 		break;
 
@@ -1250,85 +1716,6 @@ vpn_connection_state_cb (NMVPNConnection *vpn,
 	}
 }
 
-/* --- VPN state workaround BEGIN --- */
-static NMVPNConnectionState
-dbus_get_vpn_state (const char *path)
-{
-	DBusGConnection *connection;
-	DBusGProxy *proxy;
-	GError *error = NULL;
-	GValue value = {0,};
-	NMVPNConnectionState state = NM_VPN_CONNECTION_STATE_UNKNOWN;
-
-	connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, NULL);
-	proxy = dbus_g_proxy_new_for_name (connection,
-	                                   NM_DBUS_SERVICE,
-	                                   path,
-	                                   "org.freedesktop.DBus.Properties");
-	if (!proxy) {
-		g_warning ("%s: couldn't create D-Bus object proxy.", __func__);
-		dbus_g_connection_unref (connection);
-		return NM_VPN_CONNECTION_STATE_UNKNOWN;
-	}
-
-	/* Get VpnState property for object 'path' through D-Bus Get() call. */
-	if (dbus_g_proxy_call (proxy,
-	                       "Get", &error,
-	                       G_TYPE_STRING, NM_DBUS_INTERFACE_VPN_CONNECTION,
-	                       G_TYPE_STRING, "VpnState",
-	                       G_TYPE_INVALID,
-	                       G_TYPE_VALUE, &value, G_TYPE_INVALID)) {
-
-		state = g_value_get_uint (&value);
-	} else {
-		g_warning ("Error in getting active connection 'Vpn' property: (%d) %s",
-		           error->code, error->message);
-		g_error_free (error);
-	}
-
-	g_object_unref (proxy);
-	dbus_g_connection_unref (connection);
-
-	return state;
-}
-
-typedef struct {
-	NmCli *nmc;
-	NMVPNConnection *vpn;
-} VpnGetStateInfo;
-
-static gboolean
-get_vpn_state_cb (gpointer user_data)
-{
-	VpnGetStateInfo *info = (VpnGetStateInfo *) user_data;
-	NmCli *nmc = info->nmc;
-	NMVPNConnection *vpn = info->vpn;
-	NMVPNConnectionState state;
-
-	if (!NM_IS_OBJECT (vpn)) {
-		/* Active connection failed and dissapeared, quit. */
-		g_string_printf (nmc->return_text, _("Error: Connection activation failed."));
-		nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
-		quit ();
-		g_free (info);
-		return FALSE;
-	}
-
-	state = dbus_get_vpn_state (nm_object_get_path (NM_OBJECT (vpn)));
-
-	vpn_connection_state_cb (vpn, state, NM_VPN_CONNECTION_STATE_REASON_UNKNOWN, nmc);
-
-	if (   state == NM_VPN_CONNECTION_STATE_ACTIVATED
-	    || state == NM_VPN_CONNECTION_STATE_FAILED
-	    || state == NM_VPN_CONNECTION_STATE_DISCONNECTED) {
-
-		g_free (info);
-		return FALSE;
-	} else
-		return TRUE;
-}
-/* --- VPN state workaround END --- */
-
 static gboolean
 timeout_cb (gpointer user_data)
 {
@@ -1368,15 +1755,9 @@ progress_vpn_cb (gpointer user_data)
 	NMVPNConnection *vpn = (NMVPNConnection *) user_data;
 	const char *str;
 
-	/* VPN state workaround */
-#if 0
 	str = NM_IS_VPN_CONNECTION (vpn) ?
 	        vpn_connection_state_to_string (nm_vpn_connection_get_vpn_state (vpn)) :
 	        "";
-#endif
-	str = NM_IS_OBJECT (vpn) ?
-	        vpn_connection_state_to_string (dbus_get_vpn_state (nm_object_get_path (NM_OBJECT (vpn)))) :
-	        "";
 
 	nmc_terminal_show_progress (str);
 
@@ -1388,6 +1769,35 @@ typedef struct {
 	NMDevice *device;
 } ActivateConnectionInfo;
 
+static gboolean
+master_iface_slaves_check (gpointer user_data)
+{
+	ActivateConnectionInfo *info = (ActivateConnectionInfo *) user_data;
+	NmCli *nmc = info->nmc;
+	NMDevice *device = info->device;
+	const GPtrArray *slaves = NULL;
+
+	if (NM_IS_DEVICE_BOND (device))
+		slaves = nm_device_bond_get_slaves (NM_DEVICE_BOND (device));
+	else if (NM_IS_DEVICE_TEAM (device))
+		slaves = nm_device_team_get_slaves (NM_DEVICE_TEAM (device));
+	else if (NM_IS_DEVICE_BRIDGE (device))
+		slaves = nm_device_bridge_get_slaves (NM_DEVICE_BRIDGE (device));
+	else
+		g_warning ("%s: should not be reached.", __func__);
+
+	if (!slaves) {
+		g_string_printf (nmc->return_text,
+		                 _("Error: Device '%s' is waiting for slaves before proceeding with activation."),
+		                 nm_device_get_iface (device));
+		nmc->return_value = NMC_RESULT_ERROR_TIMEOUT_EXPIRED;
+		quit ();
+	}
+
+	g_free (info);
+	return FALSE;
+}
+
 static void
 activate_connection_cb (NMClient *client, NMActiveConnection *active, GError *error, gpointer user_data)
 {
@@ -1395,6 +1805,7 @@ activate_connection_cb (NMClient *client, NMActiveConnection *active, GError *er
 	NmCli *nmc = info->nmc;
 	NMDevice *device = info->device;
 	NMActiveConnectionState state;
+	const GPtrArray *ac_devs;
 
 	if (error) {
 		g_string_printf (nmc->return_text, _("Error: Connection activation failed: %s"), error->message);
@@ -1402,18 +1813,23 @@ activate_connection_cb (NMClient *client, NMActiveConnection *active, GError *er
 		quit ();
 	} else {
 		state = nm_active_connection_get_state (active);
+		if (!device) {
+			/* device could be NULL for virtual devices. Fill it here. */
+			ac_devs = nm_active_connection_get_devices (active);
+			info->device = device = ac_devs && ac_devs->len > 0 ? g_ptr_array_index (ac_devs, 0) : NULL;
+		}
 
 		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 && nmc->print_output == NMC_PRINT_PRETTY) {
+			if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
+				if (nmc->print_output == NMC_PRINT_PRETTY)
+					nmc_terminal_erase_line ();
 				printf (_("Connection successfully activated (D-Bus active path: %s)\n"),
 				        nm_object_get_path (NM_OBJECT (active)));
 			}
 			quit ();
 		} else {
 			if (NM_IS_VPN_CONNECTION (active)) {
-				VpnGetStateInfo *vpn_info;
-
 				/* Monitor VPN state */
 				g_signal_connect (G_OBJECT (active), "vpn-state-changed", G_CALLBACK (vpn_connection_state_cb), nmc);
 
@@ -1423,19 +1839,6 @@ activate_connection_cb (NMClient *client, NMActiveConnection *active, GError *er
 						g_source_remove (progress_id);
 					progress_id = g_timeout_add (120, progress_vpn_cb, NM_VPN_CONNECTION (active));
 				}
-
-				/* --- workaround BEGIN --- */
-				/* There is a bug in libnm-glib or dbus-glib - 'vpn-state-changed' signal
-				 * is never issued. After inspection it appears that PropertiesChanged and
-				 * VpnStateChanged D-Bus signals are not processed, even if they are seen
-				 * on D-Bus (checked via dbus-monitor). Until the bug is identified and
-				 * fixed, we check the VPN state every second.
-				 */
-				vpn_info = g_malloc0 (sizeof (VpnGetStateInfo));
-				vpn_info->nmc = nmc;
-				vpn_info->vpn = NM_VPN_CONNECTION (active);
-				g_timeout_add_seconds (1, get_vpn_state_cb, vpn_info);
-				/* --- workaround END --- */
 			} else {
 				g_signal_connect (active, "notify::state", G_CALLBACK (active_connection_state_cb), nmc);
 
@@ -1449,61 +1852,150 @@ activate_connection_cb (NMClient *client, NMActiveConnection *active, GError *er
 
 			/* Start timer not to loop forever when signals are not emitted */
 			g_timeout_add_seconds (nmc->timeout, timeout_cb, nmc);
+
+			/* Check for bond or team or bridge slaves */
+			if (   NM_IS_DEVICE_BOND (device)
+			    || NM_IS_DEVICE_TEAM (device)
+			    || NM_IS_DEVICE_BRIDGE (device)) {
+				g_timeout_add_seconds (SLAVES_UP_TIMEOUT, master_iface_slaves_check, info);
+				return; /* info will be freed in master_iface_slaves_check () */
+			}
 		}
 	}
 	g_free (info);
 }
 
-static NMCResultCode
-do_connection_up (NmCli *nmc, int argc, char **argv)
+/* We were using nm_connection_get_virtual_iface_name() to determine whether the
+ * connection is virtual or not. But it did't work for VLANs without 
+ * vlan.interface-name. nm_connection_get_virtual_iface_name() returns NULL for those.
+ * So we need to use our own implementation for now.
+ */
+static gboolean
+is_connection_virtual (NMConnection *connection)
+{
+	if (   nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME)
+	    || nm_connection_is_type (connection, NM_SETTING_TEAM_SETTING_NAME)
+	    || nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME)
+	    || nm_connection_is_type (connection, NM_SETTING_BRIDGE_SETTING_NAME))
+		return TRUE;
+	if (nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME)) {
+		NMSettingInfiniband *s_infi = nm_connection_get_setting_infiniband (connection);
+		int p_key = nm_setting_infiniband_get_p_key (s_infi);
+		const char *parent = nm_setting_infiniband_get_parent (s_infi);
+
+		if (p_key != -1 && parent)
+			return TRUE;
+	}
+	return FALSE;
+}
+
+static gboolean
+nmc_activate_connection (NmCli *nmc,
+                         NMConnection *connection,
+                         const char *ifname,
+                         const char *ap,
+                         const char *nsp,
+                         NMClientActivateFn callback,
+                         GError **error)
 {
 	ActivateConnectionInfo *info;
 	NMDevice *device = NULL;
 	const char *spec_object = NULL;
 	gboolean device_found;
+	GError *local = NULL;
+
+	g_return_val_if_fail (nmc != NULL, FALSE);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	if (connection) {
+		device_found = find_device_for_connection (nmc, connection, ifname, ap, nsp, &device, &spec_object, &local);
+
+		/* Virtual connection may not have their interfaces created yet */
+		if (!device_found && !is_connection_virtual (connection)) {
+			g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_CON_ACTIVATION,
+				     "%s", local && local->message ? local->message : _("unknown error"));
+			g_clear_error (&local);
+			return FALSE;
+		}
+	} else if (ifname) {
+		device = nm_client_get_device_by_iface (nmc->client, ifname);
+		if (!device) {
+			g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_NOT_FOUND,
+			             _("unknown device '%s'."), ifname);
+			return FALSE;
+		}
+	} else {
+		g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_NOT_FOUND,
+		                     _("neither a valid connection nor device given"));
+		return FALSE;
+	}
+
+	info = g_malloc0 (sizeof (ActivateConnectionInfo));
+	info->nmc = nmc;
+	info->device = device;
+
+	nm_client_activate_connection (nmc->client,
+	                               connection,
+	                               device,
+	                               spec_object,
+	                               callback,
+	                               info);
+	return TRUE;
+}
+
+static NMCResultCode
+do_connection_up (NmCli *nmc, int argc, char **argv)
+{
 	NMConnection *connection = NULL;
-	NMSettingConnection *s_con;
-	const char *con_type;
-	const char *iface = NULL;
+	const char *ifname = NULL;
 	const char *ap = NULL;
 	const char *nsp = NULL;
-	gboolean id_specified = FALSE;
-	gboolean wait = TRUE;
 	GError *error = NULL;
-	gboolean is_virtual = FALSE;
+	const char *selector = NULL;
+	const char *name = NULL;
+	char *line = NULL;
 
-	/* Set default timeout for connection activation. It can take quite a long time.
-	 * Using 90 seconds.
+	/*
+	 * Set default timeout for connection activation.
+	 * Activation can take quite a long time, use 90 seconds.
 	 */
-	nmc->timeout = 90;
+	if (nmc->timeout == -1)
+		nmc->timeout = 90;
 
-	while (argc > 0) {
-		if (strcmp (*argv, "id") == 0 || strcmp (*argv, "uuid") == 0) {
-			const char *selector = *argv;
-			id_specified = TRUE;
+	if (argc == 0) {
+		if (nmc->ask) {
+			line = nmc_readline (PROMPT_CONNECTION);
+			name = line ? line : "";
+		}
+	} else if (strcmp (*argv, "ifname") != 0) {
+		if (   strcmp (*argv, "id") == 0
+		    || strcmp (*argv, "uuid") == 0
+		    || strcmp (*argv, "path") == 0) {
 
+			selector = *argv;
 			if (next_arg (&argc, &argv) != 0) {
-				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
+				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), selector);
 				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
 				goto error;
 			}
+			name = *argv;
+		}
+		name = *argv;
+		next_arg (&argc, &argv);
+	}
 
-			connection = find_connection (nmc->system_connections, selector, *argv);
+	if (name)
+		connection = nmc_find_connection (nmc->system_connections, selector, name, NULL);
 
-			if (!connection) {
-				g_string_printf (nmc->return_text, _("Error: Unknown connection: %s."), *argv);
-				nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
-				goto error;
-			}
-		}
-		else if (strcmp (*argv, "iface") == 0) {
+	while (argc > 0) {
+		if (strcmp (*argv, "ifname") == 0) {
 			if (next_arg (&argc, &argv) != 0) {
 				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
 				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
 				goto error;
 			}
 
-			iface = *argv;
+			ifname = *argv;
 		}
 		else if (strcmp (*argv, "ap") == 0) {
 			if (next_arg (&argc, &argv) != 0) {
@@ -1525,23 +2017,7 @@ do_connection_up (NmCli *nmc, int argc, char **argv)
 			nsp = *argv;
 		}
 #endif
-		else if (strcmp (*argv, "--nowait") == 0) {
-			wait = FALSE;
-		} else if (strcmp (*argv, "--timeout") == 0) {
-			if (next_arg (&argc, &argv) != 0) {
-				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
-				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-				goto error;
-			}
-
-			errno = 0;
-			nmc->timeout = strtol (*argv, NULL, 10);
-			if (errno || nmc->timeout < 0) {
-				g_string_printf (nmc->return_text, _("Error: timeout value '%s' is not valid."), *argv);
-				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-				goto error;
-			}
-		} else {
+		 else {
 			fprintf (stderr, _("Unknown parameter: %s\n"), *argv);
 		}
 
@@ -1549,292 +2025,6591 @@ do_connection_up (NmCli *nmc, int argc, char **argv)
 		argv++;
 	}
 
-	if (!id_specified) {
-		g_string_printf (nmc->return_text, _("Error: id or uuid has to be specified."));
-		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+	/* create NMClient */
+	nmc->get_client (nmc);
+
+	if (!nm_client_get_manager_running (nmc->client)) {
+		g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
+		nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
 		goto error;
 	}
 
-	if (!nmc_is_nm_running (nmc, &error)) {
-		if (error) {
-			g_string_printf (nmc->return_text, _("Error: Can't find out if NetworkManager is running: %s."), error->message);
-			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
-			g_error_free (error);
-		} else {
-			g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
-			nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
-		}
+	/* Use nowait_flag instead of should_wait because exiting has to be postponed till
+	 * active_connection_state_cb() is called. That gives NM time to check our permissions
+	 * and we can follow activation progress.
+	 */
+	nmc->nowait_flag = (nmc->timeout == 0);
+	nmc->should_wait = TRUE;
+
+	if (!nmc_activate_connection (nmc, connection, ifname, ap, nsp, activate_connection_cb, &error)) {
+		g_string_printf (nmc->return_text, _("Error: %s."),
+		                 error ? error->message : _("unknown error"));
+		nmc->return_value = error ? error->code : NMC_RESULT_ERROR_CON_ACTIVATION;
+		g_clear_error (&error);
 		goto error;
 	}
 
+	/* Start progress indication */
+	if (nmc->print_output == NMC_PRINT_PRETTY)
+		progress_id = g_timeout_add (120, progress_cb, _("preparing"));
+
+	g_free (line);
+	return nmc->return_value;
+error:
+	nmc->should_wait = FALSE;
+	g_free (line);
+	return nmc->return_value;
+}
+
+static NMCResultCode
+do_connection_down (NmCli *nmc, int argc, char **argv)
+{
+	NMActiveConnection *active;
+	const GPtrArray *active_cons;
+	char *line = NULL;
+	char **arg_arr = NULL;
+	char **arg_ptr = argv;
+	int arg_num = argc;
+	int idx = 0;
+
+	if (argc == 0) {
+		if (nmc->ask) {
+			line = nmc_readline (PROMPT_CONNECTION);
+			nmc_string_to_arg_array (line, "", &arg_arr, &arg_num);
+			arg_ptr = arg_arr;
+		}
+		if (arg_num == 0) {
+			g_string_printf (nmc->return_text, _("Error: No connection specified."));
+			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+			goto error;
+		}
+	}
+
 	/* create NMClient */
 	nmc->get_client (nmc);
 
+	if (!nm_client_get_manager_running (nmc->client)) {
+		g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
+		nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
+		goto error;
+	}
+
+	/* Get active connections */
+	active_cons = nm_client_get_active_connections (nmc->client);
+	while (arg_num > 0) {
+		const char *selector = NULL;
+
+		if (   strcmp (*arg_ptr, "id") == 0
+		    || strcmp (*arg_ptr, "uuid") == 0
+		    || strcmp (*arg_ptr, "path") == 0
+		    || strcmp (*arg_ptr, "apath") == 0) {
+
+			selector = *arg_ptr;
+			if (next_arg (&arg_num, &arg_ptr) != 0) {
+				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), selector);
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				goto error;
+			}
+		}
+
+		active = find_active_connection (active_cons, nmc->system_connections, selector, *arg_ptr, &idx);
+		if (active) {
+			nm_client_deactivate_connection (nmc->client, active);
+		} else {
+			g_string_printf (nmc->return_text, _("Error: '%s' is not an active connection."), *arg_ptr);
+			nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
+			goto error;
+		}
+
+		if (idx == 0)
+			next_arg (&arg_num, &arg_ptr);
+	}
+
+	// FIXME: do something better then sleep()
+	/* Don't quit immediatelly and give NM time to check our permissions */
+	sleep (1);
+
+error:
+	nmc->should_wait = FALSE;
+	g_strfreev (arg_arr);
+	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  },
+	{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL,       NULL, FALSE },
+	{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL,       NULL, FALSE },
+	{ 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_IP4_CONFIG_SETTING_NAME, NULL,       NULL, FALSE },
+	{ NM_SETTING_IP6_CONFIG_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  },
+	{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL, NULL, FALSE },
+	{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL, NULL, FALSE },
+	{ 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 },
+	{ NM_SETTING_IP4_CONFIG_SETTING_NAME,        NULL,       NULL, FALSE },
+	{ NM_SETTING_IP6_CONFIG_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  },
+	{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL,   NULL, FALSE },
+	{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL,   NULL, FALSE },
+	{ 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_IP4_CONFIG_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_IP4_CONFIG_SETTING_NAME, NULL,       NULL, FALSE },
+	{ NULL, NULL, NULL, FALSE }
+};
+
+static const NameItem nmc_mobile_settings [] = {
+	{ NM_SETTING_CONNECTION_SETTING_NAME, NULL,   NULL, TRUE  },
+	{ NM_SETTING_SERIAL_SETTING_NAME,     NULL,   NULL, FALSE },
+	{ NM_SETTING_PPP_SETTING_NAME,        NULL,   NULL, FALSE },
+	{ NM_SETTING_GSM_SETTING_NAME,        NULL,   NULL, TRUE  },
+	{ NM_SETTING_CDMA_SETTING_NAME,       NULL,   NULL, TRUE  },
+	{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL,   NULL, FALSE },
+	{ NM_SETTING_IP6_CONFIG_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  },
+	{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL,   NULL, FALSE },
+	{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL,   NULL, FALSE },
+	{ 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  },
+	{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL,   NULL, FALSE },
+	{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL,   NULL, FALSE },
+	{ NULL, NULL, NULL, FALSE }
+};
+
+/* PPPoE is a base connection type from historical reasons.
+ * See libnm-util/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 },
+	{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL,       NULL, FALSE },
+	{ NM_SETTING_IP6_CONFIG_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  },
+	{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL,        NULL, FALSE },
+	{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL,        NULL, FALSE },
+	{ 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  },
+	{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL,   NULL, FALSE },
+	{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL,   NULL, FALSE },
+	{ 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  },
+	{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL,       NULL, FALSE },
+	{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL,       NULL, FALSE },
+	{ 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 },
+	{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL,       NULL, FALSE },
+	{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL,       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 },
+	{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL,       NULL, FALSE },
+	{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL,       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 },
+	{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL,       NULL, FALSE },
+	{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL,       NULL, FALSE },
+	{ NULL, NULL, NULL, FALSE }
+};
+
+static const NameItem nmc_bond_slave_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 },
+	{ NULL, NULL, NULL, FALSE }
+};
+
+static const NameItem nmc_team_slave_settings [] = {
+	{ NM_SETTING_CONNECTION_SETTING_NAME, NULL,       NULL, TRUE  },
+	{ NM_SETTING_WIRED_SETTING_NAME,      "ethernet", NULL, TRUE  },
+	{ NM_SETTING_TEAM_PORT_SETTING_NAME,  NULL,       NULL, TRUE  },
+	{ NM_SETTING_802_1X_SETTING_NAME,     NULL,       NULL, FALSE },
+	{ NULL, NULL, NULL, FALSE }
+};
+
+static const NameItem nmc_bridge_slave_settings [] = {
+	{ NM_SETTING_CONNECTION_SETTING_NAME,  NULL,       NULL, TRUE  },
+	{ NM_SETTING_BRIDGE_PORT_SETTING_NAME, NULL,       NULL, TRUE  },
+	{ NM_SETTING_WIRED_SETTING_NAME,       "ethernet", NULL, TRUE  },
+	{ NM_SETTING_802_1X_SETTING_NAME,      NULL,       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      },
+	{ 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 },
+	{ NULL, NULL, NULL }
+};
+
+/*
+ * Return an alias for the 'name' if exists, else return the 'name'.
+ * The returned string must not be freed.
+ */
+static const char *
+get_name_alias (const char *name, const NameItem array[])
+{
+	const NameItem *iter = &array[0];
+
+	if (!name)
+		return NULL;
+
+        while (iter && iter->name) {
+		if (!strcmp (name, iter->name)) {
+			if (iter->alias)
+				return iter->alias;
+			else
+				return iter->name;
+		}
+		iter++;
+	}
+	return name;
+}
+
+/*
+ * Construct a string with names and aliases from the array formatted as:
+ * "name (alias), name, name (alias), name, name"
+ *
+ * Returns: string; the caller is responsible for freeing it.
+ */
+static char *
+get_valid_options_string (const NameItem array[])
+{
+	const NameItem *iter = &array[0];
+	GString *str;
+
+	str = g_string_sized_new (150);
+	while (iter && iter->name) {
+		if (str->len)
+			g_string_append (str, ", ");
+		if (iter->alias)
+			g_string_append_printf (str, "%s (%s)", iter->name, iter->alias);
+		else
+			g_string_append (str, iter->name);
+		iter++;
+	}
+	return g_string_free (str, FALSE);
+}
+
+/*
+ * Check if 'val' is valid string in either array->name or array->alias.
+ * It accepts shorter string provided they are not ambiguous.
+ * 'val' == NULL doesn't hurt.
+ *
+ * Returns: pointer to array->name string or NULL on failure.
+ * The returned string must not be freed.
+ */
+static const char *
+check_valid_name (const char *val, const NameItem array[], GError **error)
+{
+	const NameItem *iter;
+	GPtrArray *tmp_arr;
+	const char *str;
+	GError *tmp_err = NULL;
+
+	/* Create a temporary array that can be used in nmc_string_is_valid() */
+	tmp_arr = g_ptr_array_sized_new (30);
+	iter = &array[0];
+	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++;
+	}
+	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 (array);
+			g_set_error (error, 1, 0, _("'%s' not among [%s]"),
+			             val ? val : "", err_str);
+			g_free (err_str);
+			g_clear_error (&tmp_err);
+		}
+		g_ptr_array_free (tmp_arr, TRUE);
+		return NULL;
+	}
+
+	/* Return a pointer to the found string in passed 'array' */
+	iter = &array[0];
+	while (iter && iter->name) {
+		if (   (iter->name && g_strcmp0 (iter->name, str) == 0)
+		    || (iter->alias && g_strcmp0 (iter->alias, str) == 0)) {
+			g_ptr_array_free (tmp_arr, TRUE);
+			return iter->name;
+		}
+		iter++;
+	}
+	/* We should not really come here */
+	g_ptr_array_free (tmp_arr, TRUE);
+	g_set_error (error, 1, 0, _("Unknown error"));
+	return NULL;
+}
+
+static const NameItem *
+get_valid_settings_array (const char *con_type)
+{
+	guint i, num;
+
+	if (!con_type)
+		return NULL;
+
+	num = G_N_ELEMENTS (nmc_valid_connection_types);
+        for (i = 0; i < num; i++) {
+		if (!g_strcmp0 (con_type, nmc_valid_connection_types[i].name))
+			return nmc_valid_connection_types[i].settings;
+	}
+	return NULL;
+}
+
+static gboolean
+is_setting_mandatory (NMConnection *connection, NMSetting *setting)
+{
+	NMSettingConnection *s_con;
+	const char *c_type;
+	const NameItem *item;
+	const char *name;
+
 	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
-	con_type = nm_setting_connection_get_connection_type (s_con);
+	c_type = nm_setting_connection_get_connection_type (s_con);
 
-	if (   nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME)
-	    || nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME)
-	    || nm_connection_is_type (connection, NM_SETTING_BRIDGE_SETTING_NAME))
-		is_virtual = TRUE;
+	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++;
+	}
+	return FALSE;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static gboolean
+check_and_convert_mac (const char *mac,
+                       GByteArray **mac_array,
+                       int type,
+                       const char *keyword,
+                       GError **error)
+{
+	GByteArray *local_mac_array = NULL;
+	g_return_val_if_fail (mac_array == NULL || *mac_array == NULL, FALSE);
+
+	if (!mac)
+		return TRUE;
+
+	local_mac_array = nm_utils_hwaddr_atoba (mac, type);
+	if (!local_mac_array) {
+		g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+		             _("Error: '%s': '%s' is not a valid %s MAC address."),
+		             keyword, mac, type == ARPHRD_INFINIBAND ? _("InfiniBand") : _("Ethernet"));
+		return FALSE;
+	}
+
+	if (mac_array)
+		*mac_array = local_mac_array;
+	else
+		if (local_mac_array)
+			g_byte_array_free (local_mac_array, TRUE);
+
+	return TRUE;
+}
+
+static gboolean
+check_and_convert_mtu (const char *mtu, guint32 *mtu_int, GError **error)
+{
+	unsigned long local_mtu_int;
+
+	if (!mtu)
+		return TRUE;
+
+	if (!nmc_string_to_uint (mtu, TRUE, 0, G_MAXUINT32, &local_mtu_int)) {
+		g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+		             _("Error: 'mtu': '%s' is not a valid MTU."), mtu);
+		return FALSE;
+	}
+	if (mtu_int)
+		*mtu_int = (guint32) local_mtu_int;
+	return TRUE;
+}
+
+static gboolean
+check_infiniband_parent (const char *parent, GError **error)
+{
+	if (!parent)
+		return TRUE;
+
+	if (!nm_utils_iface_valid_name (parent)) {
+		g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+		             _("Error: 'parent': '%s' is not a valid interface name."), parent);
+		return FALSE;
+	}
+	return TRUE;
+}
+
+
+static gboolean
+check_infiniband_p_key (const char *p_key, guint32 *p_key_int, GError **error)
+{
+	unsigned long local_p_key_int;
+	gboolean p_key_valid = FALSE;
+	if (!p_key)
+		return TRUE;
+
+	if (!strncmp (p_key, "0x", 2))
+		p_key_valid = nmc_string_to_uint_base (p_key + 2, 16, TRUE, 0, G_MAXUINT16, &local_p_key_int);
+	else
+		p_key_valid = nmc_string_to_uint (p_key, TRUE, 0, G_MAXUINT16, &local_p_key_int);
+	if (!p_key_valid) {
+		g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+		             _("Error: 'p-key': '%s' is not a valid InfiniBand P_KEY."), p_key);
+		return FALSE;
+	}
+	if (p_key_int)
+		*p_key_int = (guint32) local_p_key_int;
+	return TRUE;
+}
+
+/* Checks InfiniBand mode.
+ * It accepts shortcuts and normalizes them ('mode' argument is modified on success).
+ */
+static gboolean
+check_infiniband_mode (char **mode, GError **error)
+{
+	char *tmp;
+	const char *checked_mode;
+	const char *modes[] = { "datagram", "connected", NULL };
+
+	if (!mode || !*mode)
+		return TRUE;
+
+	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 !!checked_mode;
+}
+
+static gboolean
+check_and_convert_vlan_flags (const char *flags, guint32 *flags_int, GError **error)
+{
+	unsigned long local_flags_int;
+
+	if (!flags)
+		return TRUE;
+
+	if (!nmc_string_to_uint (flags, TRUE, 0, 7, &local_flags_int)) {
+		g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+		             _("Error: 'flags': '%s' is not valid; use <0-7>."), flags);
+		return FALSE;
+	}
+	if (flags_int)
+		*flags_int = (guint32) local_flags_int;
+	return TRUE;
+}
+
+static gboolean
+check_and_convert_vlan_prio_maps (const char *prio_map,
+                                  NMVlanPriorityMap type,
+                                  char ***prio_map_arr,
+                                  GError **error)
+{
+	char **local_prio_map_arr;
+	GError *local_err = NULL;
+
+	if (!prio_map)
+		return TRUE;
+
+	if (!(local_prio_map_arr = nmc_vlan_parse_priority_maps (prio_map, type, &local_err))) {
+		g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+		             _("Error: '%s': '%s' is not valid; %s "),
+		             type == NM_VLAN_INGRESS_MAP ? "ingress" : "egress",
+		             prio_map, local_err->message);
+		return FALSE;
+	}
+
+	if (prio_map_arr)
+		*prio_map_arr = local_prio_map_arr;
+	return TRUE;
+}
+
+static gboolean
+add_ip4_address_to_connection (NMIP4Address *ip4addr, NMConnection *connection)
+{
+	NMSettingIP4Config *s_ip4;
+	gboolean ret;
+
+	if (!ip4addr)
+		return TRUE;
+
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
+	if (!s_ip4) {
+		s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new ();
+		nm_connection_add_setting (connection, NM_SETTING (s_ip4));
+		g_object_set (s_ip4,
+		              NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
+		              NULL);
+	}
+	ret = nm_setting_ip4_config_add_address (s_ip4, ip4addr);
+	nm_ip4_address_unref (ip4addr);
+
+	return ret;
+}
+
+static gboolean
+add_ip6_address_to_connection (NMIP6Address *ip6addr, NMConnection *connection)
+{
+	NMSettingIP6Config *s_ip6;
+	gboolean ret;
+
+	if (!ip6addr)
+		return TRUE;
+
+	s_ip6 = nm_connection_get_setting_ip6_config (connection);
+	if (!s_ip6) {
+		s_ip6 = (NMSettingIP6Config *) nm_setting_ip6_config_new ();
+		nm_connection_add_setting (connection, NM_SETTING (s_ip6));
+		g_object_set (s_ip6,
+		              NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_MANUAL,
+		              NULL);
+	}
+	ret = nm_setting_ip6_config_add_address (s_ip6, ip6addr);
+	nm_ip6_address_unref (ip6addr);
+
+	return ret;
+}
+
+static char *
+unique_master_iface_ifname (GSList *list,
+                            const char *type,
+                            const char *ifname_property,
+                            const char *try_name)
+{
+	NMConnection *connection;
+	NMSetting *setting;
+	char *new_name;
+	unsigned int num = 1;
+	GSList *iterator = list;
+	char *ifname_val = NULL;
+
+	new_name = g_strdup (try_name);
+	while (iterator) {
+		connection = NM_CONNECTION (iterator->data);
+		setting = nm_connection_get_setting_by_name (connection, type);
+		if (!setting) {
+			iterator = g_slist_next (iterator);
+			continue;
+		}
+
+		g_object_get (setting, ifname_property, &ifname_val, NULL);
+		if (g_strcmp0 (new_name, ifname_val) == 0) {
+			g_free (new_name);
+			new_name = g_strdup_printf ("%s%d", try_name, num++);
+			iterator = list;
+		} else
+			iterator = g_slist_next (iterator);
+		g_free (ifname_val);
+	}
+	return new_name;
+}
+
+static const char *
+_strip_master_prefix (const char *master, const char *(**func)(NMConnection *))
+{
+	if (!master)
+		return NULL;
+
+	if (g_str_has_prefix (master, "ifname/")) {
+		master = master + strlen ("ifname/");
+		if (func)
+			*func = nm_connection_get_virtual_iface_name;
+	} else if (g_str_has_prefix (master, "uuid/")) {
+		master = master + strlen ("uuid/");
+		if (func)
+			*func = nm_connection_get_uuid;
+	} else if (g_str_has_prefix (master, "id/")) {
+		master = master + strlen ("id/");
+		if (func)
+			 *func = nm_connection_get_id;
+	}
+	return master;
+}
+
+/* verify_master_for_slave:
+ * @connections: list af all connections
+ * @master: UUID, ifname or ID of the master connection
+ * @type: virtual connection type (bond, team, bridge, ...)
+ *
+ * Check whether master is a valid interface name, UUID or ID of some @type connection.
+ * First UUID and ifname are checked. If they don't match, ID is checked
+ * and replaced by UUID on a match.
+ *
+ * Returns: identifier of master connection if found, %NULL otherwise
+ */
+static const char *
+verify_master_for_slave (GSList *connections,
+                         const char *master,
+                         const char *type)
+{
+	NMConnection *connection;
+	NMSettingConnection *s_con;
+	const char *con_type, *id, *uuid, *ifname;
+	GSList *iterator = connections;
+	const char *found_by_id = NULL;
+	const char *out_master = NULL;
+	const char *(*func) (NMConnection *) = NULL;
+
+	if (!master)
+		return NULL;
+
+	master = _strip_master_prefix (master, &func);
+	while (iterator) {
+		connection = NM_CONNECTION (iterator->data);
+		s_con = nm_connection_get_setting_connection (connection);
+		g_assert (s_con);
+		con_type = nm_setting_connection_get_connection_type (s_con);
+		if (g_strcmp0 (con_type, type) != 0) {
+			iterator = g_slist_next (iterator);
+			continue;
+		}
+		if (func) {
+			/* There was a prefix; only compare to that type. */
+			if (g_strcmp0 (master, func (connection)) == 0) {
+				if (func == nm_connection_get_id)
+					out_master = nm_connection_get_uuid (connection);
+				else
+					out_master = master;
+				break;
+			}
+		} else {
+			id = nm_connection_get_id (connection);
+			uuid = nm_connection_get_uuid (connection);
+			ifname = nm_connection_get_virtual_iface_name (connection);
+			if (   g_strcmp0 (master, uuid) == 0
+			    || g_strcmp0 (master, ifname) == 0) {
+				out_master = master;
+				break;
+			}
+			if (!found_by_id && g_strcmp0 (master, id) == 0)
+				found_by_id = uuid;
+		}
+
+		iterator = g_slist_next (iterator);
+	}
+	return out_master ? out_master : found_by_id;
+}
+
+static gboolean
+bridge_prop_string_to_uint (const char *str,
+                            const char *nmc_arg,
+                            GType bridge_type,
+                            const char *propname,
+                            unsigned long *out_val,
+                            GError **error)
+{
+	GParamSpecUInt *pspec;
+
+	pspec = (GParamSpecUInt *) g_object_class_find_property (g_type_class_peek (bridge_type),
+	                                                         propname);
+	g_assert (G_IS_PARAM_SPEC_UINT (pspec));
+
+	if (!nmc_string_to_uint (str, TRUE, pspec->minimum, pspec->maximum, out_val)) {
+		g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+		             _("Error: '%s': '%s' is not valid; use <%u-%u>."),
+		             nmc_arg, str, pspec->minimum, pspec->maximum);
+		return FALSE;
+	}
+	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 gboolean
+normalize_yes_no (char **yes_no)
+{
+	char *tmp;
+	const char *checked_yes_no;
+	const char *strv[] = { WORD_LOC_YES, WORD_LOC_NO, NULL };
+
+	if (!yes_no || !*yes_no)
+		return FALSE;
+
+	tmp = g_strstrip (g_strdup (*yes_no));
+	checked_yes_no = nmc_string_is_valid (tmp, strv, NULL);
+	g_free (tmp);
+	if (g_strcmp0 (checked_yes_no, WORD_LOC_YES) == 0) {
+		g_free (*yes_no);
+		*yes_no = g_strdup (WORD_YES);
+	} else if (g_strcmp0 (checked_yes_no, WORD_LOC_NO) == 0) {
+		g_free (*yes_no);
+		*yes_no = g_strdup (WORD_NO);
+	}
+	return !!checked_yes_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)
+{
+	gboolean once_more;
+	GError *error = NULL;
+	const char *type = ethernet ? _("ethernet") : _("Wi-Fi");
+
+	/* Ask for optional arguments */
+	if (!want_provide_opt_args (type, 3))
+		return;
+
+	if (!*mtu) {
+		do {
+			*mtu = nmc_readline (_("MTU [auto]: "));
+			once_more = !check_and_convert_mtu (*mtu, NULL, &error);
+			if (once_more) {
+				printf ("%s\n", error->message);
+				g_clear_error (&error);
+				g_free (*mtu);
+			}
+		} while (once_more);
+	}
+	if (!*mac) {
+		do {
+			*mac = nmc_readline (_("MAC [none]: "));
+			once_more = !check_and_convert_mac (*mac, NULL, ARPHRD_ETHER, "mac", &error);
+			if (once_more) {
+				printf ("%s\n", error->message);
+				g_clear_error (&error);
+				g_free (*mac);
+			}
+		} while (once_more);
+	}
+	if (!*cloned_mac) {
+		do {
+			*cloned_mac = nmc_readline (_("Cloned MAC [none]: "));
+			once_more = !check_and_convert_mac (*cloned_mac, NULL, ARPHRD_ETHER, "cloned-mac", &error);
+			if (once_more) {
+				printf ("%s\n", error->message);
+				g_clear_error (&error);
+				g_free (*cloned_mac);
+			}
+		} while (once_more);
+	}
+}
+
+#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)
+{
+	gboolean once_more;
+	GError *error = NULL;
+
+	/* Ask for optional arguments */
+	if (!want_provide_opt_args (_("InfiniBand"), 5))
+		return;
+
+	if (!*mtu) {
+		do {
+			*mtu = nmc_readline (_("MTU [auto]: "));
+			once_more = !check_and_convert_mtu (*mtu, NULL, &error);
+			if (once_more) {
+				printf ("%s\n", error->message);
+				g_clear_error (&error);
+				g_free (*mtu);
+			}
+		} while (once_more);
+	}
+	if (!*mac) {
+		do {
+			*mac = nmc_readline (_("MAC [none]: "));
+			once_more = !check_and_convert_mac (*mac, NULL, ARPHRD_INFINIBAND, "mac", &error);
+			if (once_more) {
+				printf ("%s\n", error->message);
+				g_clear_error (&error);
+				g_free (*mac);
+			}
+		} while (once_more);
+	}
+	if (!*mode) {
+		do {
+			*mode = nmc_readline (_("Transport mode %s"), PROMPT_IB_MODE);
+			if (!*mode)
+				*mode = g_strdup ("datagram");
+			once_more = !check_infiniband_mode (mode, &error);
+			if (once_more) {
+				printf ("%s\n", error->message);
+				g_clear_error (&error);
+				g_free (*mode);
+			}
+		} while (once_more);
+	}
+	if (!*parent) {
+		do {
+			*parent = nmc_readline (_("Parent interface [none]: "));
+			once_more = !check_infiniband_parent (*parent, &error);
+			if (once_more) {
+				printf ("%s\n", error->message);
+				g_clear_error (&error);
+				g_free (*parent);
+			}
+		} while (once_more);
+	}
+	if (!*p_key) {
+		do {
+			*p_key = nmc_readline (_("P_KEY [none]: "));
+			once_more = !check_infiniband_p_key (*p_key, NULL, &error);
+			if (once_more) {
+				printf ("%s\n", error->message);
+				g_clear_error (&error);
+				g_free (*p_key);
+			}
+			/* If parent is specified, so has to be P_KEY */
+			if (!once_more && *parent && !*p_key) {
+				once_more = TRUE;
+				printf (_("Error: 'p-key' is mandatory when 'parent' is specified.\n"));
+			}
+		} while (once_more);
+	}
+}
+
+static void
+do_questionnaire_wifi (char **mtu, char **mac, char **cloned_mac)
+{
+	/* At present, the optional Wi-Fi arguments are the same as for ethernet. */
+	return do_questionnaire_ethernet (FALSE, mtu, mac, cloned_mac);
+}
+
+static void
+do_questionnaire_wimax (char **mac)
+{
+	gboolean once_more;
+	GError *error = NULL;
+
+	/* Ask for optional 'wimax' arguments. */
+	if (!want_provide_opt_args (_("WiMAX"), 1))
+		return;
+
+	if (!*mac) {
+		do {
+			*mac = nmc_readline (_("MAC [none]: "));
+			once_more = !check_and_convert_mac (*mac, NULL, ARPHRD_ETHER, "mac", &error);
+			if (once_more) {
+				printf ("%s\n", error->message);
+				g_clear_error (&error);
+				g_free (*mac);
+			}
+		} while (once_more);
+	}
+}
+
+static void
+do_questionnaire_pppoe (char **password, char **service, char **mtu, char **mac)
+{
+	gboolean once_more;
+	GError *error = NULL;
+
+	/* Ask for optional 'pppoe' arguments. */
+	if (!want_provide_opt_args (_("PPPoE"), 4))
+		return;
+
+	if (!*password)
+		*password = nmc_readline (_("Password [none]: "));
+	if (!*service)
+		*service = nmc_readline (_("Service [none]: "));
+
+	if (!*mtu) {
+		do {
+			*mtu = nmc_readline (_("MTU [auto]: "));
+			once_more = !check_and_convert_mtu (*mtu, NULL, &error);
+			if (once_more) {
+				printf ("%s\n", error->message);
+				g_clear_error (&error);
+				g_free (*mtu);
+			}
+		} while (once_more);
+	}
+	if (!*mac) {
+		do {
+			*mac = nmc_readline (_("MAC [none]: "));
+			once_more = !check_and_convert_mac (*mac, NULL, ARPHRD_ETHER, "mac", &error);
+			if (once_more) {
+				printf ("%s\n", error->message);
+				g_clear_error (&error);
+				g_free (*mac);
+			}
+		} while (once_more);
+	}
+}
+
+static void
+do_questionnaire_mobile (char **user, char **password)
+{
+	/* Ask for optional 'gsm' or 'cdma' arguments. */
+	if (!want_provide_opt_args (_("mobile broadband"), 2))
+		return;
+
+	if (!*user)
+		*user = nmc_readline (_("Username [none]: "));
+	if (!*password)
+		*password = nmc_readline (_("Password [none]: "));
+}
+
+#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)
+{
+	gboolean once_more;
+
+	/* Ask for optional 'bluetooth' arguments. */
+	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 %s"), PROMPT_BT_TYPE);
+			if (!*bt_type)
+				*bt_type = g_strdup ("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);
+	}
+}
+
+static void
+do_questionnaire_vlan (char **mtu, char **flags, char **ingress, char **egress)
+{
+	gboolean once_more;
+	GError *error = NULL;
+
+	/* Ask for optional 'vlan' arguments. */
+	if (!want_provide_opt_args (_("VLAN"), 4))
+		return;
+
+	if (!*mtu) {
+		do {
+			*mtu = nmc_readline (_("MTU [auto]: "));
+			once_more = !check_and_convert_mtu (*mtu, NULL, &error);
+			if (once_more) {
+				printf ("%s\n", error->message);
+				g_clear_error (&error);
+				g_free (*mtu);
+			}
+		} while (once_more);
+	}
+	if (!*flags) {
+		do {
+			*flags = nmc_readline (_("VLAN flags (<0-7>) [none]: "));
+			once_more = !check_and_convert_vlan_flags (*flags, NULL, &error);
+			if (once_more) {
+				printf ("%s\n", error->message);
+				g_clear_error (&error);
+				g_free (*flags);
+			}
+		} while (once_more);
+	}
+	if (!*ingress) {
+		do {
+			*ingress = nmc_readline (_("Ingress priority maps [none]: "));
+			once_more = !check_and_convert_vlan_prio_maps (*ingress, NM_VLAN_INGRESS_MAP, NULL, &error);
+			if (once_more) {
+				printf ("%s\n", error->message);
+				g_clear_error (&error);
+				g_free (*ingress);
+			}
+		} while (once_more);
+	}
+	if (!*egress) {
+		do {
+			*egress = nmc_readline (_("Egress priority maps [none]: "));
+			once_more = !check_and_convert_vlan_prio_maps (*egress, NM_VLAN_EGRESS_MAP, NULL, &error);
+			if (once_more) {
+				printf ("%s\n", error->message);
+				g_clear_error (&error);
+				g_free (*egress);
+			}
+		} while (once_more);
+	}
+}
+
+#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 *monitor_mode;
+	unsigned long tmp;
+	gboolean once_more;
+	GError *error = NULL;
+
+	/* Ask for optional 'bond' arguments. */
+	if (!want_provide_opt_args (_("bond"), 7))
+		return;
+
+	if (!*mode) {
+		const char *mode_tmp;
+		do {
+			*mode = nmc_readline (PROMPT_BOND_MODE);
+			if (!*mode)
+				*mode = g_strdup ("balance-rr");
+			mode_tmp = nmc_bond_validate_mode (*mode, &error);
+			g_free (*mode);
+			if (mode_tmp) {
+				*mode = g_strdup (mode_tmp);
+			} else {
+				printf ("%s\n", error->message);
+				g_clear_error (&error);
+			}
+		} while (!mode_tmp);
+	}
+
+	if (g_strcmp0 (*mode, "active-backup") == 0 && !*primary) {
+		do {
+			*primary = nmc_readline (_("Bonding primary interface [none]: "));
+			once_more = *primary && !nm_utils_iface_valid_name (*primary);
+			if (once_more) {
+				printf (_("Error: 'primary': '%s' is not a valid interface name.\n"),
+				        *primary);
+				g_free (*primary);
+			}
+		} while (once_more);
+	}
+
+	do {
+		monitor_mode = nmc_readline (_("Bonding monitoring mode %s"), PROMPT_BOND_MON_MODE);
+		if (!monitor_mode)
+			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, WORD_MIIMON, WORD_ARP);
+			g_free (monitor_mode);
+		}
+	} while (once_more);
+
+	if (matches (monitor_mode, WORD_MIIMON) == 0) {
+		if (!*miimon) {
+			do {
+				*miimon = nmc_readline (_("Bonding miimon [100]: "));
+				once_more = *miimon && !nmc_string_to_uint (*miimon, TRUE, 0, G_MAXUINT32, &tmp);
+				if (once_more) {
+					printf (_("Error: 'miimon': '%s' is not a valid number <0-%u>.\n"),
+					        *miimon, G_MAXUINT32);
+					g_free (*miimon);
+				}
+			} while (once_more);
+		}
+		if (!*downdelay) {
+			do {
+				*downdelay = nmc_readline (_("Bonding downdelay [0]: "));
+				once_more = *downdelay && !nmc_string_to_uint (*downdelay, TRUE, 0, G_MAXUINT32, &tmp);
+				if (once_more) {
+					printf (_("Error: 'downdelay': '%s' is not a valid number <0-%u>.\n"),
+					        *downdelay, G_MAXUINT32);
+					g_free (*downdelay);
+				}
+			} while (once_more);
+		}
+		if (!*updelay) {
+			do {
+				*updelay = nmc_readline (_("Bonding updelay [0]: "));
+				once_more = *updelay && !nmc_string_to_uint (*updelay, TRUE, 0, G_MAXUINT32, &tmp);
+				if (once_more) {
+					printf (_("Error: 'updelay': '%s' is not a valid number <0-%u>.\n"),
+					        *updelay, G_MAXUINT32);
+					g_free (*updelay);
+				}
+			} while (once_more);
+		}
+	} else {
+		if (!*arpinterval) {
+			do {
+				*arpinterval = nmc_readline (_("Bonding arp-interval [0]: "));
+				once_more = *arpinterval && !nmc_string_to_uint (*arpinterval, TRUE, 0, G_MAXUINT32, &tmp);
+				if (once_more) {
+					printf (_("Error: 'arp-interval': '%s' is not a valid number <0-%u>.\n"),
+					        *arpinterval, G_MAXUINT32);
+					g_free (*arpinterval);
+				}
+			} while (once_more);
+		}
+		if (!*arpiptarget) {
+			//FIXME: verify the string
+			*arpiptarget = nmc_readline (_("Bonding arp-ip-target [none]: "));
+		}
+	}
+
+	g_free (monitor_mode);
+}
+
+static void
+do_questionnaire_team_common (const char *type_name, char **config)
+{
+	gboolean once_more;
+	char *json = NULL;
+	GError *error = NULL;
+
+	/* Ask for optional arguments. */
+	if (!want_provide_opt_args (type_name, 1))
+		return;
+
+	if (!*config) {
+		do {
+			*config = nmc_readline (_("Team JSON configuration [none]: "));
+			once_more = !nmc_team_check_config (*config, &json, &error);
+			if (once_more) {
+				printf ("Error: %s\n", error->message);
+				g_clear_error (&error);
+				g_free (*config);
+			}
+		} while (once_more);
+	}
+
+	*config = json;
+}
+
+/* Both team and team-slave curently have just ithe same one optional argument */
+static void
+do_questionnaire_team (char **config)
+{
+	do_questionnaire_team_common (_("team"), config);
+}
+
+static void
+do_questionnaire_team_slave (char **config)
+{
+	do_questionnaire_team_common (_("team-slave"), config);
+}
+
+static void
+do_questionnaire_bridge (char **stp, char **priority, char **fwd_delay, char **hello_time,
+                         char **max_age, char **ageing_time, char **mac)
+{
+	unsigned long tmp;
+	gboolean once_more;
+	GError *error = NULL;
+
+	/* Ask for optional 'bridge' arguments. */
+	if (!want_provide_opt_args (_("bridge"), 7))
+		return;
+
+	if (!*stp) {
+		gboolean stp_bool;
+		do {
+			*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);
+				g_clear_error (&error);
+				g_free (*stp);
+			}
+		} while (once_more);
+	}
+	if (!*priority) {
+		do {
+			*priority = nmc_readline (_("STP priority [32768]: "));
+			*priority = *priority ? *priority : g_strdup ("32768");
+			once_more = !nmc_string_to_uint (*priority, TRUE, 0, G_MAXUINT16, &tmp);
+			if (once_more) {
+				printf (_("Error: 'priority': '%s' is not a valid number <0-%d>.\n"),
+				        *priority, G_MAXUINT16);
+				g_free (*priority);
+			}
+		} while (once_more);
+	}
+	if (!*fwd_delay) {
+		do {
+			*fwd_delay = nmc_readline (_("Forward delay [15]: "));
+			*fwd_delay = *fwd_delay ? *fwd_delay : g_strdup ("15");
+			once_more = !nmc_string_to_uint (*fwd_delay, TRUE, 2, 30, &tmp);
+			if (once_more) {
+				printf (_("Error: 'forward-delay': '%s' is not a valid number <2-30>.\n"),
+				        *fwd_delay);
+				g_free (*fwd_delay);
+			}
+		} while (once_more);
+	}
+
+	if (!*hello_time) {
+		do {
+			*hello_time = nmc_readline (_("Hello time [2]: "));
+			*hello_time = *hello_time ? *hello_time : g_strdup ("2");
+			once_more = !nmc_string_to_uint (*hello_time, TRUE, 1, 10, &tmp);
+			if (once_more) {
+				printf (_("Error: 'hello-time': '%s' is not a valid number <1-10>.\n"),
+				        *hello_time);
+				g_free (*hello_time);
+			}
+		} while (once_more);
+	}
+	if (!*max_age) {
+		do {
+			*max_age = nmc_readline (_("Max age [20]: "));
+			*max_age = *max_age ? *max_age : g_strdup ("20");
+			once_more = !nmc_string_to_uint (*max_age, TRUE, 6, 40, &tmp);
+			if (once_more) {
+				printf (_("Error: 'max-age': '%s' is not a valid number <6-40>.\n"),
+				        *max_age);
+				g_free (*max_age);
+			}
+		} while (once_more);
+	}
+	if (!*ageing_time) {
+		do {
+			*ageing_time = nmc_readline (_("MAC address ageing time [300]: "));
+			*ageing_time = *ageing_time ? *ageing_time : g_strdup ("300");
+			once_more = !nmc_string_to_uint (*ageing_time, TRUE, 0, 1000000, &tmp);
+			if (once_more) {
+				printf (_("Error: 'ageing-time': '%s' is not a valid number <0-1000000>.\n"),
+				        *ageing_time);
+				g_free (*ageing_time);
+			}
+		} while (once_more);
+	}
+	if (!*mac) {
+		do {
+			*mac = nmc_get_user_input (_("MAC [none]: "));
+			once_more = !check_and_convert_mac (*mac, NULL, ARPHRD_ETHER, "mac", &error);
+			if (once_more) {
+				printf ("%s\n", error->message);
+				g_clear_error (&error);
+				g_free (*mac);
+			}
+		} while (once_more);
+	}
+}
+
+static void
+do_questionnaire_bridge_slave (char **priority, char **path_cost, char **hairpin)
+{
+	unsigned long tmp;
+	gboolean once_more;
+	GError *error = NULL;
+
+	/* Ask for optional 'bridge-slave' arguments. */
+	if (!want_provide_opt_args (_("bridge-slave"), 3))
+		return;
+
+	if (!*priority) {
+		do {
+			*priority = nmc_readline (_("Bridge port priority [32]: "));
+			*priority = *priority ? *priority : g_strdup ("32");
+			once_more = !bridge_prop_string_to_uint (*priority, "priority", NM_TYPE_SETTING_BRIDGE_PORT,
+			                                         NM_SETTING_BRIDGE_PORT_PRIORITY, &tmp, &error);
+			if (once_more) {
+				printf ("%s\n", error->message);
+				g_clear_error (&error);
+				g_free (*priority);
+			}
+		} while (once_more);
+	}
+	if (!*path_cost) {
+		do {
+			*path_cost = nmc_readline (_("Bridge port STP path cost [100]: "));
+			*path_cost = *path_cost ? *path_cost : g_strdup ("100");
+			once_more = !bridge_prop_string_to_uint (*path_cost, "path-cost", NM_TYPE_SETTING_BRIDGE_PORT,
+			                                         NM_SETTING_BRIDGE_PORT_PATH_COST, &tmp, &error);
+			if (once_more) {
+				printf ("%s\n", error->message);
+				g_clear_error (&error);
+				g_free (*path_cost);
+			}
+		} while (once_more);
+	}
+	if (!*hairpin) {
+		gboolean hairpin_bool;
+		do {
+			*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);
+				g_clear_error (&error);
+				g_free (*hairpin);
+			}
+		} while (once_more);
+	}
+}
+
+static void
+do_questionnaire_vpn (char **user)
+{
+	/* Ask for optional 'vpn' arguments. */
+	if (!want_provide_opt_args (_("VPN"), 1))
+		return;
+
+	if (!*user)
+		*user = nmc_readline (_("Username [none]: "));
+}
+
+static void
+do_questionnaire_olpc (char **channel, char **dhcp_anycast)
+{
+	unsigned long tmp;
+	gboolean once_more;
+	GError *error = NULL;
+
+	/* Ask for optional 'olpc' arguments. */
+	if (!want_provide_opt_args (_("OLPC Mesh"), 2))
+		return;
+
+	if (!*channel) {
+		do {
+			*channel = nmc_readline (_("OLPC Mesh channel [1]: "));
+			once_more = *channel && !nmc_string_to_uint (*channel, TRUE, 1, 13, &tmp);
+			if (once_more) {
+				printf (_("Error: 'channel': '%s' is not a valid number <1-13>.\n"),
+				        *channel);
+				g_free (*channel);
+			}
+		} while (once_more);
+	}
+	if (!*dhcp_anycast) {
+		do {
+			*dhcp_anycast = nmc_readline (_("DHCP anycast MAC address [none]: "));
+			once_more = !check_and_convert_mac (*dhcp_anycast, NULL, ARPHRD_ETHER, "dhcp-anycast", &error);
+			if (once_more) {
+				printf ("%s\n", error->message);
+				g_clear_error (&error);
+				g_free (*dhcp_anycast);
+			}
+		} while (once_more);
+	}
+}
+
+static gboolean
+split_address (char* str, char **ip, char **gw, char **rest)
+{
+	size_t n1, n2, n3, n4, n5;
+
+	*ip = *gw = *rest = NULL;
+	if (!str)
+		return FALSE;
+
+	n1 = strspn  (str,    " \t");
+	n2 = strcspn (str+n1, " \t\0") + n1;
+	n3 = strspn  (str+n2, " \t")   + n2;
+	n4 = strcspn (str+n3, " \t\0") + n3;
+	n5 = strspn  (str+n4, " \t")   + n4;
+
+	str[n2] = str[n4] = '\0';
+	*ip = str[n1] ? str + n1 : NULL;
+	*gw = str[n3] ? str + n3 : NULL;
+	*rest = str[n5] ? str + n5 : NULL;
+
+	return TRUE;
+}
+
+static void
+ask_for_ip_addresses (NMConnection *connection, int family)
+{
+	gboolean ip_loop;
+	GError *error = NULL;
+	char *str, *ip, *gw, *rest;
+	const char *prompt;
+	gboolean added;
+	gpointer ipaddr;
+
+	if (family == 4)
+		prompt =_("IPv4 address (IP[/plen] [gateway]) [none]: ");
+	else
+		prompt =_("IPv6 address (IP[/plen] [gateway]) [none]: ");
+
+	ip_loop = TRUE;
+	do {
+		str = nmc_readline ("%s", prompt);
+		split_address (str, &ip, &gw, &rest);
+		if (ip) {
+			if (family == 4)
+				ipaddr = nmc_parse_and_build_ip4_address (ip, gw, &error);
+			else
+				ipaddr = nmc_parse_and_build_ip6_address (ip, gw, &error);
+			if (ipaddr) {
+				if (family == 4)
+					added = add_ip4_address_to_connection ((NMIP4Address *) ipaddr, connection);
+				else
+					added = add_ip6_address_to_connection ((NMIP6Address *) ipaddr, connection);
+				gw = gw ? gw : (family == 4) ? "0.0.0.0" : "::";
+				if (added)
+					printf (_("  Address successfully added: %s %s\n"), ip, gw);
+				else
+					printf (_("  Warning: address already present: %s %s\n"), ip, gw);
+				if (rest)
+					printf (_("  Warning: ignoring garbage at the end: '%s'\n"), rest);
+			} else {
+				g_prefix_error (&error, _("Error: "));
+				printf ("%s\n", error->message);
+				g_clear_error (&error);
+			}
+		} else
+			ip_loop = FALSE;
+
+		g_free (str);
+	} while (ip_loop);
+}
+
+static void
+do_questionnaire_ip (NMConnection *connection)
+{
+	char *answer;
+
+	/* Ask for IP addresses */
+	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;
+	}
+
+	printf (_("Press <Enter> to finish adding addresses.\n"));
+
+	ask_for_ip_addresses (connection, 4);
+	ask_for_ip_addresses (connection, 6);
+
+	g_free (answer);
+	return;
+}
+
+static gboolean
+complete_connection_by_type (NMConnection *connection,
+                             const char *con_type,
+                             GSList *all_connections,
+                             gboolean ask,
+                             int argc,
+                             char **argv,
+                             GError **error)
+{
+	NMSettingConnection *s_con;
+	NMSettingWired *s_wired;
+	NMSettingInfiniband *s_infiniband;
+	NMSettingWireless *s_wifi;
+	NMSettingWimax *s_wimax;
+	NMSettingPPPOE *s_pppoe;
+	NMSettingGsm *s_gsm;
+	NMSettingCdma *s_cdma;
+	NMSettingBluetooth *s_bt;
+	NMSettingVlan *s_vlan;
+	NMSettingBond *s_bond;
+	NMSettingTeam *s_team;
+	NMSettingTeamPort *s_team_port;
+	NMSettingBridge *s_bridge;
+	NMSettingBridgePort *s_bridge_port;
+	NMSettingVPN *s_vpn;
+	NMSettingOlpcMesh *s_olpc_mesh;
+
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	s_con = nm_connection_get_setting_connection (connection);
+	g_assert (s_con);
+
+	if (!strcmp (con_type, NM_SETTING_WIRED_SETTING_NAME)) {
+		/* Build up the settings required for 'ethernet' */
+		gboolean success = FALSE;
+		const char *mtu_c = NULL;
+		char *mtu = NULL;
+		guint32 mtu_int = 0;
+		const char *mac_c = NULL;
+		char *mac = NULL;
+		const char *cloned_mac_c = NULL;
+		char *cloned_mac = NULL;
+		GByteArray *array = NULL;
+		GByteArray *cloned_array = NULL;
+		nmc_arg_t exp_args[] = { {"mtu",        TRUE, &mtu_c,        FALSE},
+		                         {"mac",        TRUE, &mac_c,        FALSE},
+		                         {"cloned-mac", TRUE, &cloned_mac_c, FALSE},
+		                         {NULL} };
+
+		if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
+			return FALSE;
+
+		/* Also ask for all optional arguments if '--ask' is specified. */
+		mtu = mtu_c ? g_strdup (mtu_c) : NULL;
+		mac = mac_c ? g_strdup (mac_c) : NULL;
+		cloned_mac = cloned_mac_c ? g_strdup (cloned_mac_c) : NULL;
+		if (ask)
+			do_questionnaire_ethernet (TRUE, &mtu, &mac, &cloned_mac);
+
+		if (!check_and_convert_mtu (mtu, &mtu_int, error))
+			goto cleanup_wired;
+		if (!check_and_convert_mac (mac, &array, ARPHRD_ETHER, "mac", error))
+			goto cleanup_wired;
+		if (!check_and_convert_mac (cloned_mac, &cloned_array, ARPHRD_ETHER, "cloned-mac", error))
+			goto cleanup_wired;
+
+		/* Add ethernet setting */
+		s_wired = (NMSettingWired *) nm_setting_wired_new ();
+		nm_connection_add_setting (connection, NM_SETTING (s_wired));
+
+		if (mtu)
+			g_object_set (s_wired, NM_SETTING_WIRED_MTU, mtu_int, NULL);
+		if (array)
+			g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, array, NULL);
+		if (cloned_array)
+			g_object_set (s_wired, NM_SETTING_WIRED_CLONED_MAC_ADDRESS, cloned_array, NULL);
+
+		success = TRUE;
+cleanup_wired:
+		g_free (mtu);
+		g_free (mac);
+		g_free (cloned_mac);
+		if (array)
+			g_byte_array_free (array, TRUE);
+		if (cloned_array)
+			g_byte_array_free (cloned_array, TRUE);
+		if (!success)
+			return FALSE;
+
+	} else if (!strcmp (con_type, NM_SETTING_INFINIBAND_SETTING_NAME)) {
+		/* Build up the settings required for 'infiniband' */
+		gboolean success = FALSE;
+		const char *mtu_c = NULL;
+		char *mtu = NULL;
+		guint32 mtu_int = 0;
+		const char *mac_c = NULL;
+		char *mac = NULL;
+		GByteArray *array = NULL;
+		const char *mode_c = NULL;
+		char *mode = NULL;
+		const char *parent_c = NULL;
+		char *parent = NULL;
+		const char *p_key_c = NULL;
+		char *p_key = NULL;
+		guint32 p_key_int = 0;
+		nmc_arg_t exp_args[] = { {"mtu",            TRUE, &mtu_c,    FALSE},
+		                         {"mac",            TRUE, &mac_c,    FALSE},
+		                         {"transport-mode", TRUE, &mode_c,   FALSE},
+		                         {"parent",         TRUE, &parent_c, FALSE},
+		                         {"p-key",          TRUE, &p_key_c,  FALSE},
+		                         {NULL} };
+
+		if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
+			return FALSE;
+
+		/* Also ask for all optional arguments if '--ask' is specified. */
+		mtu = mtu_c ? g_strdup (mtu_c) : NULL;
+		mac = mac_c ? g_strdup (mac_c) : NULL;
+		mode = mode_c ? g_strdup (mode_c) : NULL;
+		parent = parent_c ? g_strdup (parent_c) : NULL;
+		p_key = p_key_c ? g_strdup (p_key_c) : NULL;
+		if (ask)
+			do_questionnaire_infiniband (&mtu, &mac, &mode, &parent, &p_key);
+
+		if (!check_and_convert_mtu (mtu, &mtu_int, error))
+			goto cleanup_ib;
+		if (!check_and_convert_mac (mac, &array, ARPHRD_INFINIBAND, "mac", error))
+			goto cleanup_ib;
+		if (!check_infiniband_mode (&mode, error))
+			goto cleanup_ib;
+		if (p_key) {
+			if (!check_infiniband_p_key (p_key, &p_key_int, error))
+				goto cleanup_ib;
+			if (!check_infiniband_parent (parent, error))
+				goto cleanup_ib;
+		} else if (parent) {
+			g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+			             _("Error: 'parent': not valid without 'p-key'."));
+			goto cleanup_ib;
+		}
+
+		/* Add 'infiniband' setting */
+		s_infiniband = (NMSettingInfiniband *) nm_setting_infiniband_new ();
+		nm_connection_add_setting (connection, NM_SETTING (s_infiniband));
+
+		g_object_set (s_infiniband, NM_SETTING_INFINIBAND_TRANSPORT_MODE, mode ? mode : "datagram", NULL);
+		if (mtu)
+			g_object_set (s_infiniband, NM_SETTING_INFINIBAND_MTU, mtu_int, NULL);
+		if (array) {
+			g_object_set (s_infiniband, NM_SETTING_INFINIBAND_MAC_ADDRESS, array, NULL);
+			g_byte_array_free (array, TRUE);
+		}
+		if (p_key)
+			g_object_set (s_infiniband, NM_SETTING_INFINIBAND_P_KEY, p_key_int, NULL);
+		if (parent)
+			g_object_set (s_infiniband, NM_SETTING_INFINIBAND_PARENT, parent, NULL);
+
+
+		success = TRUE;
+cleanup_ib:
+		g_free (mtu);
+		g_free (mac);
+		g_free (mode);
+		g_free (parent);
+		g_free (p_key);
+		if (!success)
+			return FALSE;
+
+	} else if (!strcmp (con_type, NM_SETTING_WIRELESS_SETTING_NAME)) {
+		/* Build up the settings required for 'wifi' */
+		gboolean success = FALSE;
+		char *ssid_ask = NULL;
+		const char *ssid = NULL;
+		GByteArray *ssid_arr = NULL;
+		const char *mtu_c = NULL;
+		char *mtu = NULL;
+		guint32 mtu_int = 0;
+		const char *mac_c = NULL;
+		char *mac = NULL;
+		GByteArray *mac_array = NULL;
+		const char *cloned_mac_c = NULL;
+		char *cloned_mac = NULL;
+		GByteArray *cloned_mac_array = NULL;
+		nmc_arg_t exp_args[] = { {"ssid",       TRUE, &ssid,         !ask},
+		                         {"mtu",        TRUE, &mtu_c,        FALSE},
+		                         {"mac",        TRUE, &mac_c,        FALSE},
+		                         {"cloned-mac", TRUE, &cloned_mac_c, FALSE},
+		                         {NULL} };
+
+		if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
+			return FALSE;
+
+		if (!ssid && ask)
+			ssid = ssid_ask = nmc_readline (_("SSID: "));
+		if (!ssid) {
+			g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+			                     _("Error: 'ssid' is required."));
+			return FALSE;
+		}
+
+		/* Also ask for all optional arguments if '--ask' is specified. */
+		mtu = mtu_c ? g_strdup (mtu_c) : NULL;
+		mac = mac_c ? g_strdup (mac_c) : NULL;
+		cloned_mac = cloned_mac_c ? g_strdup (cloned_mac_c) : NULL;
+		if (ask)
+			do_questionnaire_wifi (&mtu, &mac, &cloned_mac);
+
+		if (!check_and_convert_mtu (mtu, &mtu_int, error))
+			goto cleanup_wifi;
+		if (!check_and_convert_mac (mac, &mac_array, ARPHRD_ETHER, "mac", error))
+			goto cleanup_wifi;
+		if (!check_and_convert_mac (cloned_mac, &cloned_mac_array, ARPHRD_ETHER, "cloned-mac", error))
+			goto cleanup_wifi;
+
+		/* Add wifi setting */
+		s_wifi = (NMSettingWireless *) nm_setting_wireless_new ();
+		nm_connection_add_setting (connection, NM_SETTING (s_wifi));
+
+		ssid_arr = g_byte_array_sized_new (strlen (ssid));
+		g_byte_array_append (ssid_arr, (const guint8 *) ssid, strlen (ssid));
+		g_object_set (s_wifi, NM_SETTING_WIRELESS_SSID, ssid_arr, NULL);
+
+		if (mtu)
+			g_object_set (s_wifi, NM_SETTING_WIRELESS_MTU, mtu_int, NULL);
+		if (mac_array)
+			g_object_set (s_wifi, NM_SETTING_WIRELESS_MAC_ADDRESS, mac_array, NULL);
+		if (cloned_mac_array)
+			g_object_set (s_wifi, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, cloned_mac_array, NULL);
+
+		success = TRUE;
+cleanup_wifi:
+		g_free (ssid_ask);
+		g_free (mtu);
+		g_free (mac);
+		g_free (cloned_mac);
+		if (ssid_arr)
+			g_byte_array_free (ssid_arr, TRUE);
+		if (mac_array)
+			g_byte_array_free (mac_array, TRUE);
+		if (cloned_mac_array)
+			g_byte_array_free (cloned_mac_array, TRUE);
+		if (!success)
+			return FALSE;
+
+	} else if (!strcmp (con_type, NM_SETTING_WIMAX_SETTING_NAME)) {
+		/* Build up the settings required for 'wimax' */
+		gboolean success = FALSE;
+		const char *nsp_name = NULL;
+		char *nsp_name_ask = NULL;
+		const char *mac_c = NULL;
+		char *mac = NULL;
+		GByteArray *mac_array = NULL;
+		nmc_arg_t exp_args[] = { {"nsp", TRUE, &nsp_name, !ask},
+		                         {"mac", TRUE, &mac_c,    FALSE},
+		                         {NULL} };
+
+		if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
+			return FALSE;
+
+		if (!nsp_name && ask)
+			nsp_name = nsp_name_ask = nmc_readline (_("WiMAX NSP name: "));
+		if (!nsp_name) {
+			g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+			                     _("Error: 'nsp' is required."));
+			goto cleanup_wimax;
+		}
+
+		/* Also ask for all optional arguments if '--ask' is specified. */
+		mac = mac_c ? g_strdup (mac_c) : NULL;
+		if (ask)
+			do_questionnaire_wimax (&mac);
+
+		if (!check_and_convert_mac (mac, &mac_array, ARPHRD_ETHER, "mac", error))
+			goto cleanup_wimax;
+
+		/* Add 'wimax' setting */
+		s_wimax = (NMSettingWimax *) nm_setting_wimax_new ();
+		nm_connection_add_setting (connection, NM_SETTING (s_wimax));
+		g_object_set (s_wimax, NM_SETTING_WIMAX_NETWORK_NAME, nsp_name, NULL);
+
+		if (mac_array) {
+			g_object_set (s_wimax, NM_SETTING_WIMAX_MAC_ADDRESS, mac_array, NULL);
+			g_byte_array_free (mac_array, TRUE);
+		}
+
+		success = TRUE;
+cleanup_wimax:
+		g_free (nsp_name_ask);
+		g_free (mac);
+		if (!success)
+			return FALSE;
+
+	} else if (!strcmp (con_type, NM_SETTING_PPPOE_SETTING_NAME)) {
+		/* Build up the settings required for 'pppoe' */
+		gboolean success = FALSE;
+		const char *username = NULL;
+		char *username_ask = NULL;
+		const char *password_c = NULL;
+		char *password = NULL;
+		const char *service_c = NULL;
+		char *service = NULL;
+		const char *mtu_c = NULL;
+		char *mtu = NULL;
+		guint32 mtu_int = 0;
+		const char *mac_c = NULL;
+		char *mac = NULL;
+		GByteArray *mac_array = NULL;
+		nmc_arg_t exp_args[] = { {"username", TRUE, &username,   !ask},
+		                         {"password", TRUE, &password_c, FALSE},
+		                         {"service",  TRUE, &service_c,  FALSE},
+		                         {"mtu",      TRUE, &mtu_c,      FALSE},
+		                         {"mac",      TRUE, &mac_c,      FALSE},
+		                         {NULL} };
+
+		if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
+			return FALSE;
+
+		if (!username && ask)
+			username = username_ask = nmc_readline (_("PPPoE username: "));
+		if (!username) {
+			g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+			                     _("Error: 'username' is required."));
+			goto cleanup_pppoe;
+		}
+
+		/* Also ask for all optional arguments if '--ask' is specified. */
+		password = g_strdup (password_c);
+		service = g_strdup (service_c);
+		mtu = g_strdup (mtu_c);
+		mac = g_strdup (mac_c);
+		if (ask)
+			do_questionnaire_pppoe (&password, &service, &mtu, &mac);
+
+		if (!check_and_convert_mtu (mtu, &mtu_int, error))
+			goto cleanup_pppoe;
+		if (!check_and_convert_mac (mac, &mac_array, ARPHRD_ETHER, "mac", error))
+			goto cleanup_pppoe;
+
+		/* Add 'pppoe' setting */
+		s_pppoe = (NMSettingPPPOE *) nm_setting_pppoe_new ();
+		nm_connection_add_setting (connection, NM_SETTING (s_pppoe));
+		g_object_set (s_pppoe, NM_SETTING_PPPOE_USERNAME, username, NULL);
+		g_object_set (s_pppoe, NM_SETTING_PPPOE_PASSWORD, password, NULL);
+		g_object_set (s_pppoe, NM_SETTING_PPPOE_SERVICE, service, NULL);
+
+		/* Add ethernet setting */
+		s_wired = (NMSettingWired *) nm_setting_wired_new ();
+		nm_connection_add_setting (connection, NM_SETTING (s_wired));
+		if (mtu)
+			g_object_set (s_wired, NM_SETTING_WIRED_MTU, mtu_int, NULL);
+		if (mac_array)
+			g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, mac_array, NULL);
+
+		success = TRUE;
+cleanup_pppoe:
+		g_free (username_ask);
+		g_free (password);
+		g_free (service);
+		g_free (mtu);
+		g_free (mac);
+		if (mac_array)
+			g_byte_array_free (mac_array, TRUE);
+		if (!success)
+			return FALSE;
+
+	} else if (   !strcmp (con_type, NM_SETTING_GSM_SETTING_NAME)
+	           || !strcmp (con_type, NM_SETTING_CDMA_SETTING_NAME)) {
+		/* Build up the settings required for 'gsm' or 'cdma' mobile broadband */
+		gboolean success = FALSE;
+		const char *apn = NULL;
+		char *apn_ask = NULL;
+		const char *user_c = NULL;
+		char *user = NULL;
+		const char *password_c = NULL;
+		char *password = NULL;
+		gboolean is_gsm;
+		int i = 0;
+		nmc_arg_t gsm_args[] = { {NULL}, {NULL}, {NULL}, /* placeholders */
+		                         {NULL} };
+
+		is_gsm = !strcmp (con_type, NM_SETTING_GSM_SETTING_NAME);
+
+		if (is_gsm)
+			gsm_args[i++] = (nmc_arg_t) {"apn", TRUE, &apn, !ask};
+		gsm_args[i++] = (nmc_arg_t) {"user",     TRUE, &user_c,     FALSE};
+		gsm_args[i++] = (nmc_arg_t) {"password", TRUE, &password_c, FALSE};
+		gsm_args[i++] = (nmc_arg_t) {NULL};
+
+		if (!nmc_parse_args (gsm_args, FALSE, &argc, &argv, error))
+			return FALSE;
+
+		if (!apn && ask && is_gsm)
+			apn = apn_ask = nmc_readline (_("APN: "));
+		if (!apn && is_gsm) {
+			g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+			                     _("Error: 'apn' is required."));
+			goto cleanup_mobile;
+		}
+
+		/* Also ask for all optional arguments if '--ask' is specified. */
+		user = user_c ? g_strdup (user_c) : NULL;
+		password = password_c ? g_strdup (password_c) : NULL;
+		if (ask)
+			do_questionnaire_mobile (&user, &password);
+
+		if (is_gsm) {
+			g_object_set (s_con, NM_SETTING_CONNECTION_TYPE, NM_SETTING_GSM_SETTING_NAME, NULL);
+
+			/* Add 'gsm' setting */
+			s_gsm = (NMSettingGsm *) nm_setting_gsm_new ();
+			nm_connection_add_setting (connection, NM_SETTING (s_gsm));
+			g_object_set (s_gsm,
+			              NM_SETTING_GSM_NUMBER, "*99#",
+			              NM_SETTING_GSM_APN, apn,
+			              NM_SETTING_GSM_USERNAME, user,
+			              NM_SETTING_GSM_PASSWORD, password,
+			              NULL);
+			g_free (apn_ask);
+		} else {
+			g_object_set (s_con, NM_SETTING_CONNECTION_TYPE, NM_SETTING_CDMA_SETTING_NAME, NULL);
+
+			/* Add 'cdma' setting */
+			s_cdma = (NMSettingCdma *) nm_setting_cdma_new ();
+			nm_connection_add_setting (connection, NM_SETTING (s_cdma));
+			g_object_set (s_cdma,
+			              NM_SETTING_CDMA_NUMBER, "#777",
+			              NM_SETTING_CDMA_USERNAME, user,
+			              NM_SETTING_CDMA_PASSWORD, password,
+			              NULL);
+		}
+
+		success = TRUE;
+cleanup_mobile:
+		g_free (user);
+		g_free (password);
+		if (!success)
+			return FALSE;
+
+	} else if (!strcmp (con_type, NM_SETTING_BLUETOOTH_SETTING_NAME)) {
+		/* Build up the settings required for 'bluetooth' */
+		gboolean success = FALSE;
+		const char *addr = NULL;
+		char *addr_ask = NULL;
+		const char *bt_type_c = NULL;
+		char *bt_type = NULL;
+		GByteArray *array = NULL;
+		nmc_arg_t exp_args[] = { {"addr",    TRUE, &addr,      !ask},
+		                         {"bt-type", TRUE, &bt_type_c, FALSE},
+		                         {NULL} };
+
+		if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
+			return FALSE;
+
+		if (!addr && ask)
+			addr = addr_ask = nmc_readline (_("Bluetooth device address: "));
+		if (!addr) {
+			g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+			                     _("Error: 'addr' is required."));
+			return FALSE;
+		}
+		if (!check_and_convert_mac (addr, &array, ARPHRD_ETHER, "addr", error))
+			goto cleanup_bt;
+
+		/* Also ask for all optional arguments if '--ask' is specified. */
+		bt_type = bt_type_c ? g_strdup (bt_type_c) : NULL;
+		if (ask)
+			do_questionnaire_bluetooth (&bt_type);
+
+		/* Default to 'panu' if bt-type is not provided. */
+		if (!bt_type)
+			bt_type = g_strdup (NM_SETTING_BLUETOOTH_TYPE_PANU);
+
+		/* Add 'bluetooth' setting */
+		s_bt = (NMSettingBluetooth *) nm_setting_bluetooth_new ();
+		nm_connection_add_setting (connection, NM_SETTING (s_bt));
+
+		if (array) {
+			g_object_set (s_bt, NM_SETTING_BLUETOOTH_BDADDR, array, NULL);
+			g_byte_array_free (array, TRUE);
+		}
+
+		/* 'dun' type requires adding 'gsm' or 'cdma' setting */
+		if (   !strcmp (bt_type, NM_SETTING_BLUETOOTH_TYPE_DUN)
+		    || !strcmp (bt_type, NM_SETTING_BLUETOOTH_TYPE_DUN"-gsm")) {
+			bt_type = g_strdup (NM_SETTING_BLUETOOTH_TYPE_DUN);
+			s_gsm = (NMSettingGsm *) nm_setting_gsm_new ();
+			nm_connection_add_setting (connection, NM_SETTING (s_gsm));
+			g_object_set (s_gsm, NM_SETTING_GSM_NUMBER, "*99#", NULL);
+//			g_object_set (s_gsm, NM_SETTING_GSM_APN, "FIXME", NULL;
+
+		} else if (!strcmp (bt_type, NM_SETTING_BLUETOOTH_TYPE_DUN"-cdma")) {
+			bt_type = g_strdup (NM_SETTING_BLUETOOTH_TYPE_DUN);
+			s_cdma = (NMSettingCdma *) nm_setting_cdma_new ();
+			nm_connection_add_setting (connection, NM_SETTING (s_cdma));
+			g_object_set (s_cdma, NM_SETTING_CDMA_NUMBER, "#777", NULL);
+
+		} else if (!strcmp (bt_type, NM_SETTING_BLUETOOTH_TYPE_PANU)) {
+			/* 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]."),
+			             bt_type, NM_SETTING_BLUETOOTH_TYPE_PANU, NM_SETTING_BLUETOOTH_TYPE_DUN,
+			             NM_SETTING_BLUETOOTH_TYPE_DUN"-gsm", NM_SETTING_BLUETOOTH_TYPE_DUN"-cdma");
+			goto cleanup_bt;
+		}
+		g_object_set (s_bt, NM_SETTING_BLUETOOTH_TYPE, bt_type, NULL);
+
+		success = TRUE;
+cleanup_bt:
+		g_free (addr_ask);
+		g_free (bt_type);
+		if (!success)
+			return FALSE;
+
+	} else if (!strcmp (con_type, NM_SETTING_VLAN_SETTING_NAME)) {
+		/* Build up the settings required for 'vlan' */
+		gboolean success = FALSE;
+		const char *ifname = NULL;
+		const char *parent = NULL;
+		char *parent_ask = NULL;
+		const char *vlan_id = NULL;
+		char *vlan_id_ask = NULL;
+		unsigned long id = 0;
+		const char *flags_c = NULL;
+		char *flags = NULL;
+		guint32 flags_int = 0;
+		const char *ingress_c = NULL, *egress_c = NULL;
+		char *ingress = NULL, *egress = NULL;
+		char **ingress_arr = NULL, **egress_arr = NULL, **p;
+		const char *mtu_c = NULL;
+		char *mtu = NULL;
+		guint32 mtu_int;
+		GByteArray *addr_array = NULL;
+		nmc_arg_t exp_args[] = { {"dev",     TRUE, &parent,    !ask},
+		                         {"id",      TRUE, &vlan_id,   !ask},
+		                         {"flags",   TRUE, &flags_c,   FALSE},
+		                         {"ingress", TRUE, &ingress_c, FALSE},
+		                         {"egress",  TRUE, &egress_c,  FALSE},
+		                         {"mtu",     TRUE, &mtu_c,     FALSE},
+		                         {NULL} };
+
+		if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
+			return FALSE;
+
+		if (!parent && ask)
+			parent = parent_ask = nmc_readline (_("VLAN parent device or connection UUID: "));
+		if (!parent) {
+			g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+			                     _("Error: 'dev' is required."));
+			return FALSE;
+		}
+		if (!vlan_id && ask)
+			vlan_id = vlan_id_ask = nmc_readline (_("VLAN ID <0-4095>: "));
+		if (!vlan_id) {
+			g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+			                     _("Error: 'id' is required."));
+			goto cleanup_vlan;
+		}
+		if (vlan_id) {
+			if (!nmc_string_to_uint (vlan_id, TRUE, 0, 4095, &id)) {
+				g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+				             _("Error: 'id': '%s' is not valid; use <0-4095>."),
+				             vlan_id);
+				goto cleanup_vlan;
+			}
+		}
+
+		if (   !(addr_array = nm_utils_hwaddr_atoba (parent, ARPHRD_ETHER))
+		    && !nm_utils_is_uuid (parent)
+		    && !nm_utils_iface_valid_name (parent)) {
+			g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+			             _("Error: 'dev': '%s' is neither UUID, interface name, nor MAC."),
+			             parent);
+			goto cleanup_vlan;
+		}
+
+		/* Also ask for all optional arguments if '--ask' is specified. */
+		mtu = mtu_c ? g_strdup (mtu_c) : NULL;
+		flags = flags_c ? g_strdup (flags_c) : NULL;
+		ingress = ingress_c ? g_strdup (ingress_c) : NULL;
+		egress = egress_c ? g_strdup (egress_c) : NULL;
+		if (ask)
+			do_questionnaire_vlan (&mtu, &flags, &ingress, &egress);
+
+		/* ifname is taken from connection's ifname */
+		ifname = nm_setting_connection_get_interface_name (s_con);
+
+		if (!check_and_convert_mtu (mtu, &mtu_int, error))
+			goto cleanup_vlan;
+		if (!check_and_convert_vlan_flags (flags, &flags_int, error))
+			goto cleanup_vlan;
+		if (!check_and_convert_vlan_prio_maps (ingress, NM_VLAN_INGRESS_MAP, &ingress_arr, error))
+			goto cleanup_vlan;
+		if (!check_and_convert_vlan_prio_maps (egress, NM_VLAN_EGRESS_MAP, &egress_arr, error))
+			goto cleanup_vlan;
+
+		/* Add 'vlan' setting */
+		s_vlan = (NMSettingVlan *) nm_setting_vlan_new ();
+		nm_connection_add_setting (connection, NM_SETTING (s_vlan));
+
+		/* Add 'wired' setting if necessary */
+		if (mtu || addr_array) {
+			s_wired = (NMSettingWired *) nm_setting_wired_new ();
+			nm_connection_add_setting (connection, NM_SETTING (s_wired));
+
+			if (mtu)
+				g_object_set (s_wired, NM_SETTING_WIRED_MTU, mtu_int, NULL);
+			if (addr_array)
+				g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, addr_array, NULL);
+		}
+
+		/* Set 'vlan' properties */
+		if (!addr_array)
+			g_object_set (s_vlan, NM_SETTING_VLAN_PARENT, parent, NULL);
+
+		if (ifname)
+			g_object_set (s_vlan, NM_SETTING_VLAN_INTERFACE_NAME, ifname, NULL);
+		g_object_set (s_vlan, NM_SETTING_VLAN_ID, id, NULL);
+
+		if (flags)
+			g_object_set (s_vlan, NM_SETTING_VLAN_FLAGS, flags_int, NULL);
+		for (p = ingress_arr; p && *p; p++)
+			nm_setting_vlan_add_priority_str (s_vlan, NM_VLAN_INGRESS_MAP, *p);
+		for (p = egress_arr; p && *p; p++)
+			nm_setting_vlan_add_priority_str (s_vlan, NM_VLAN_EGRESS_MAP, *p);
+
+		success = TRUE;
+cleanup_vlan:
+		g_free (mtu);
+		g_free (flags);
+		g_free (ingress);
+		g_free (egress);
+		if (addr_array)
+			g_byte_array_free (addr_array, TRUE);
+		g_free (parent_ask);
+		g_free (vlan_id_ask);
+		g_strfreev (ingress_arr);
+		g_strfreev (egress_arr);
+		if (!success)
+			return FALSE;
 
-	device_found = find_device_for_connection (nmc, connection, iface, ap, nsp, &device, &spec_object, &error);
-	/* Virtual connection may not have their interfaces created yet */
-	if (!device_found && !is_virtual) {
-		if (error)
-			g_string_printf (nmc->return_text, _("Error: No suitable device found: %s."), error->message);
+	} else if (!strcmp (con_type, NM_SETTING_BOND_SETTING_NAME)) {
+		/* Build up the settings required for 'bond' */
+		gboolean success = FALSE;
+		char *bond_ifname = NULL;
+		const char *ifname = NULL;
+		const char *bond_mode_c = NULL;
+		char *bond_mode = NULL;
+		const char *bond_primary_c = NULL;
+		char *bond_primary = NULL;
+		const char *bond_miimon_c = NULL;
+		char *bond_miimon = NULL;
+		const char *bond_downdelay_c = NULL;
+		char *bond_downdelay = NULL;
+		const char *bond_updelay_c = NULL;
+		char *bond_updelay = NULL;
+		const char *bond_arpinterval_c = NULL;
+		char *bond_arpinterval = NULL;
+		const char *bond_arpiptarget_c = NULL;
+		char *bond_arpiptarget = NULL;
+		nmc_arg_t exp_args[] = { {"mode",          TRUE, &bond_mode_c,        FALSE},
+		                         {"primary",       TRUE, &bond_primary_c,     FALSE},
+		                         {"miimon",        TRUE, &bond_miimon_c,      FALSE},
+		                         {"downdelay",     TRUE, &bond_downdelay_c,   FALSE},
+		                         {"updelay",       TRUE, &bond_updelay_c,     FALSE},
+		                         {"arp-interval",  TRUE, &bond_arpinterval_c, FALSE},
+		                         {"arp-ip-target", TRUE, &bond_arpiptarget_c, FALSE},
+		                         {NULL} };
+
+		if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
+			return FALSE;
+
+		/* Also ask for all optional arguments if '--ask' is specified. */
+		bond_mode = bond_mode_c ? g_strdup (bond_mode_c) : NULL;
+		bond_primary = bond_primary_c ? g_strdup (bond_primary_c) : NULL;
+		bond_miimon = bond_miimon_c ? g_strdup (bond_miimon_c) : NULL;
+		bond_downdelay = bond_downdelay_c ? g_strdup (bond_downdelay_c) : NULL;
+		bond_updelay = bond_updelay_c ? g_strdup (bond_updelay_c) : NULL;
+		bond_arpinterval = bond_arpinterval_c ? g_strdup (bond_arpinterval_c) : NULL;
+		bond_arpiptarget = bond_arpiptarget_c ? g_strdup (bond_arpiptarget_c) : NULL;
+		if (ask)
+			do_questionnaire_bond (&bond_mode, &bond_primary, &bond_miimon,
+			                       &bond_downdelay, &bond_updelay,
+			                       &bond_arpinterval, &bond_arpiptarget);
+
+		/* Use connection's ifname as 'bond' ifname if exists, else generate one */
+		ifname = nm_setting_connection_get_interface_name (s_con);
+		if (!ifname)
+			bond_ifname = unique_master_iface_ifname (all_connections,
+			                                          NM_SETTING_BOND_SETTING_NAME,
+			                                          NM_SETTING_BOND_INTERFACE_NAME,
+			                                          "nm-bond");
+		else
+			bond_ifname = g_strdup (ifname);
+
+		/* Add 'bond' setting */
+		s_bond = (NMSettingBond *) nm_setting_bond_new ();
+		nm_connection_add_setting (connection, NM_SETTING (s_bond));
+
+		/* Set bond options */
+		g_object_set (s_bond, NM_SETTING_BOND_INTERFACE_NAME, bond_ifname, NULL);
+		if (bond_mode) {
+			GError *err = NULL;
+			const char *bm;
+			if (!(bm = nmc_bond_validate_mode (bond_mode, &err))) {
+				g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+				             _("Error: 'mode': %s."), err->message);
+				g_clear_error (&err);
+				goto cleanup_bond;
+			}
+			nm_setting_bond_add_option (s_bond, NM_SETTING_BOND_OPTION_MODE, bm);
+		}
+		if (bond_primary) {
+			if (!nm_utils_iface_valid_name (bond_primary)) {
+				g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+				             _("Error: 'primary': '%s' is not a valid interface name."),
+				             bond_primary);
+				goto cleanup_bond;
+			}
+			nm_setting_bond_add_option (s_bond, NM_SETTING_BOND_OPTION_PRIMARY, bond_primary);
+		}
+		if (bond_miimon)
+			nm_setting_bond_add_option (s_bond, NM_SETTING_BOND_OPTION_MIIMON, bond_miimon);
+		if (bond_downdelay && strcmp (bond_downdelay, "0") != 0)
+			nm_setting_bond_add_option (s_bond, NM_SETTING_BOND_OPTION_DOWNDELAY, bond_downdelay);
+		if (bond_updelay && strcmp (bond_updelay, "0") != 0)
+			nm_setting_bond_add_option (s_bond, NM_SETTING_BOND_OPTION_UPDELAY, bond_updelay);
+		if (bond_arpinterval && strcmp (bond_arpinterval, "0") != 0)
+			nm_setting_bond_add_option (s_bond, NM_SETTING_BOND_OPTION_ARP_INTERVAL, bond_arpinterval);
+		if (bond_arpiptarget)
+			nm_setting_bond_add_option (s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET, bond_arpiptarget);
+
+		success = TRUE;
+cleanup_bond:
+		g_free (bond_ifname);
+		g_free (bond_mode);
+		g_free (bond_primary);
+		g_free (bond_miimon);
+		g_free (bond_downdelay);
+		g_free (bond_updelay);
+		g_free (bond_arpinterval);
+		g_free (bond_arpiptarget);
+		if (!success)
+			return FALSE;
+
+	} else if (!strcmp (con_type, "bond-slave")) {
+		/* Build up the settings required for 'bond-slave' */
+		const char *master = NULL;
+		char *master_ask = NULL;
+		const char *checked_master = NULL;
+		const char *type = NULL;
+		nmc_arg_t exp_args[] = { {"master", TRUE, &master, !ask},
+		                         {"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 (PROMPT_BOND_MASTER);
+		if (!master) {
+			g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+			                     _("Error: 'master' is required."));
+			return FALSE;
+		}
+		/* Verify master argument */
+		checked_master = verify_master_for_slave (all_connections, master, NM_SETTING_BOND_SETTING_NAME);
+		if (!checked_master)
+			printf (_("Warning: master='%s' doesn't refer to any existing profile.\n"), master);
+
+		if (type)
+			printf (_("Warning: 'type' is currently ignored. "
+			          "We only support ethernet slaves for now.\n"));
+
+		/* Change properties in 'connection' setting */
+		g_object_set (s_con,
+		              NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME,
+		              NM_SETTING_CONNECTION_MASTER, checked_master ? checked_master : _strip_master_prefix (master, NULL),
+		              NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_BOND_SETTING_NAME,
+		              NULL);
+
+		/* Add ethernet setting */
+		s_wired = (NMSettingWired *) nm_setting_wired_new ();
+		nm_connection_add_setting (connection, NM_SETTING (s_wired));
+
+		g_free (master_ask);
+
+	} else if (!strcmp (con_type, NM_SETTING_TEAM_SETTING_NAME)) {
+		/* Build up the settings required for 'team' */
+		gboolean success = FALSE;
+		char *team_ifname = NULL;
+		const char *ifname = NULL;
+		const char *config_c = NULL;
+		char *config = NULL;
+		char *json = NULL;
+		nmc_arg_t exp_args[] = { {"config", TRUE, &config_c, FALSE},
+		                         {NULL} };
+
+		if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
+			return FALSE;
+
+		/* Also ask for all optional arguments if '--ask' is specified. */
+		config = g_strdup (config_c);
+		if (ask)
+			do_questionnaire_team (&config);
+
+		/* Use connection's ifname as 'team' ifname if exists, else generate one */
+		ifname = nm_setting_connection_get_interface_name (s_con);
+		if (!ifname)
+			team_ifname = unique_master_iface_ifname (all_connections,
+			                                          NM_SETTING_TEAM_SETTING_NAME,
+			                                          NM_SETTING_TEAM_INTERFACE_NAME,
+			                                          "nm-team");
+		else
+			team_ifname = g_strdup (ifname);
+
+		/* Add 'team' setting */
+		s_team = (NMSettingTeam *) nm_setting_team_new ();
+		nm_connection_add_setting (connection, NM_SETTING (s_team));
+
+		if (!nmc_team_check_config (config, &json, error)) {
+			g_prefix_error (error, _("Error: "));
+			goto cleanup_team;
+		}
+
+		/* Set team options */
+		g_object_set (s_team, NM_SETTING_TEAM_INTERFACE_NAME, team_ifname, NULL);
+		g_object_set (s_team, NM_SETTING_TEAM_CONFIG, json, NULL);
+
+		success = TRUE;
+cleanup_team:
+		g_free (team_ifname);
+		g_free (config);
+		g_free (json);
+		if (!success)
+			return FALSE;
+
+	} else if (!strcmp (con_type, "team-slave")) {
+		/* Build up the settings required for 'team-slave' */
+		gboolean success = FALSE;
+		const char *master = NULL;
+		char *master_ask = NULL;
+		const char *checked_master = NULL;
+		const char *type = NULL;
+		const char *config_c = NULL;
+		char *config = NULL;
+		char *json = NULL;
+		nmc_arg_t exp_args[] = { {"master", TRUE, &master,   !ask},
+		                         {"type",   TRUE, &type,     FALSE},
+		                         {"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 (PROMPT_TEAM_MASTER);
+		if (!master) {
+			g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+			                     _("Error: 'master' is required."));
+			return FALSE;
+		}
+		/* Verify master argument */
+		checked_master = verify_master_for_slave (all_connections, master, NM_SETTING_TEAM_SETTING_NAME);
+		if (!checked_master)
+			printf (_("Warning: master='%s' doesn't refer to any existing profile.\n"), master);
+
+		/* Also ask for all optional arguments if '--ask' is specified. */
+		config = g_strdup (config_c);
+		if (ask)
+			do_questionnaire_team_slave (&config);
+
+		if (type)
+			printf (_("Warning: 'type' is currently ignored. "
+			          "We only support ethernet slaves for now.\n"));
+
+		/* Add 'team-port' setting */
+		s_team_port = (NMSettingTeamPort *) nm_setting_team_port_new ();
+		nm_connection_add_setting (connection, NM_SETTING (s_team_port));
+
+		if (!nmc_team_check_config (config, &json, error)) {
+			g_prefix_error (error, _("Error: "));
+			goto cleanup_team_slave;
+		}
+
+		/* Set team-port options */
+		g_object_set (s_team_port, NM_SETTING_TEAM_PORT_CONFIG, json, NULL);
+
+		/* Change properties in 'connection' setting */
+		g_object_set (s_con,
+		              NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME,
+		              NM_SETTING_CONNECTION_MASTER, checked_master ? checked_master : _strip_master_prefix (master, NULL),
+		              NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_TEAM_SETTING_NAME,
+		              NULL);
+
+		/* Add ethernet setting */
+		s_wired = (NMSettingWired *) nm_setting_wired_new ();
+		nm_connection_add_setting (connection, NM_SETTING (s_wired));
+
+		success = TRUE;
+cleanup_team_slave:
+		g_free (master_ask);
+		g_free (config);
+		g_free (json);
+		if (!success)
+			return FALSE;
+
+	} else if (!strcmp (con_type, NM_SETTING_BRIDGE_SETTING_NAME)) {
+		/* Build up the settings required for 'bridge' */
+		gboolean success = FALSE;
+		char *bridge_ifname = NULL;
+		const char *ifname = NULL;
+		const char *stp_c = NULL;
+		char *stp = NULL;
+		const char *priority_c = NULL;
+		char *priority = NULL;
+		const char *fwd_delay_c = NULL;
+		char *fwd_delay = NULL;
+		const char *hello_time_c = NULL;
+		char *hello_time = NULL;
+		const char *max_age_c = NULL;
+		char *max_age = NULL;
+		const char *ageing_time_c = NULL;
+		char *ageing_time = NULL;
+		gboolean stp_bool;
+		unsigned long stp_prio_int, fwd_delay_int, hello_time_int,
+		              max_age_int, ageing_time_int;
+		const char *mac_c = NULL;
+		char *mac = NULL;
+		GByteArray *mac_array = NULL;
+		nmc_arg_t exp_args[] = { {"stp",           TRUE, &stp_c,         FALSE},
+		                         {"priority",      TRUE, &priority_c,    FALSE},
+		                         {"forward-delay", TRUE, &fwd_delay_c,   FALSE},
+		                         {"hello-time",    TRUE, &hello_time_c,  FALSE},
+		                         {"max-age",       TRUE, &max_age_c,     FALSE},
+		                         {"ageing-time",   TRUE, &ageing_time_c, FALSE},
+		                         {"mac",           TRUE, &mac_c,         FALSE},
+		                         {NULL} };
+
+		if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
+			return FALSE;
+
+		/* Also ask for all optional arguments if '--ask' is specified. */
+		stp = stp_c ? g_strdup (stp_c) : NULL;
+		priority = priority_c ? g_strdup (priority_c) : NULL;
+		fwd_delay = fwd_delay_c ? g_strdup (fwd_delay_c) : NULL;
+		hello_time = hello_time_c ? g_strdup (hello_time_c) : NULL;
+		max_age = max_age_c ? g_strdup (max_age_c) : NULL;
+		ageing_time = ageing_time_c ? g_strdup (ageing_time_c) : NULL;
+		mac = g_strdup (mac_c);
+		if (ask)
+			do_questionnaire_bridge (&stp, &priority, &fwd_delay, &hello_time,
+			                         &max_age, &ageing_time, &mac);
+
+		/* Use connection's ifname as 'bridge' ifname if exists, else generate one */
+		ifname = nm_setting_connection_get_interface_name (s_con);
+		if (!ifname)
+			bridge_ifname = unique_master_iface_ifname (all_connections,
+			                                            NM_SETTING_BRIDGE_SETTING_NAME,
+			                                            NM_SETTING_BRIDGE_INTERFACE_NAME,
+			                                            "nm-bridge");
+		else
+			bridge_ifname = g_strdup (ifname);
+
+		if (stp) {
+			GError *tmp_err = NULL;
+			if (!nmc_string_to_bool (stp, &stp_bool, &tmp_err)) {
+				g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+				             _("Error: 'stp': %s."), tmp_err->message);
+				g_clear_error (&tmp_err);
+				goto cleanup_bridge;
+			}
+		}
+
+		/* Add 'bond' setting */
+		/* Must be done *before* bridge_prop_string_to_uint() so that the type is known */
+		s_bridge = (NMSettingBridge *) nm_setting_bridge_new ();
+		nm_connection_add_setting (connection, NM_SETTING (s_bridge));
+
+		if (priority)
+			if (!bridge_prop_string_to_uint (priority, "priority", NM_TYPE_SETTING_BRIDGE,
+			                                 NM_SETTING_BRIDGE_PRIORITY, &stp_prio_int, error))
+				goto cleanup_bridge;
+		if (fwd_delay)
+			if (!bridge_prop_string_to_uint (fwd_delay, "forward-delay", NM_TYPE_SETTING_BRIDGE,
+			                                 NM_SETTING_BRIDGE_FORWARD_DELAY, &fwd_delay_int, error))
+				goto cleanup_bridge;
+		if (hello_time)
+			if (!bridge_prop_string_to_uint (hello_time, "hello-time", NM_TYPE_SETTING_BRIDGE,
+			                                 NM_SETTING_BRIDGE_HELLO_TIME, &hello_time_int, error))
+				goto cleanup_bridge;
+		if (max_age)
+			if (!bridge_prop_string_to_uint (max_age, "max-age", NM_TYPE_SETTING_BRIDGE,
+			                                 NM_SETTING_BRIDGE_MAX_AGE, &max_age_int, error))
+				goto cleanup_bridge;
+		if (ageing_time)
+			if (!bridge_prop_string_to_uint (ageing_time, "ageing-time", NM_TYPE_SETTING_BRIDGE,
+			                                 NM_SETTING_BRIDGE_AGEING_TIME, &ageing_time_int, error))
+				goto cleanup_bridge;
+		if (!check_and_convert_mac (mac, &mac_array, ARPHRD_ETHER, "mac", error))
+			goto cleanup_bridge;
+
+		/* Set bridge options */
+		g_object_set (s_bridge, NM_SETTING_BRIDGE_INTERFACE_NAME, bridge_ifname, NULL);
+		if (stp)
+			g_object_set (s_bridge, NM_SETTING_BRIDGE_STP, stp_bool, NULL);
+		if (priority)
+			g_object_set (s_bridge, NM_SETTING_BRIDGE_PRIORITY, stp_prio_int, NULL);
+		if (fwd_delay)
+			g_object_set (s_bridge, NM_SETTING_BRIDGE_FORWARD_DELAY, fwd_delay_int, NULL);
+		if (hello_time)
+			g_object_set (s_bridge, NM_SETTING_BRIDGE_HELLO_TIME, hello_time_int, NULL);
+		if (max_age)
+			g_object_set (s_bridge, NM_SETTING_BRIDGE_MAX_AGE, max_age_int, NULL);
+		if (ageing_time)
+			g_object_set (s_bridge, NM_SETTING_BRIDGE_AGEING_TIME, ageing_time_int, NULL);
+		if (mac_array)
+			g_object_set (s_bridge, NM_SETTING_BRIDGE_MAC_ADDRESS, mac_array, NULL);
+
+		success = TRUE;
+cleanup_bridge:
+		g_free (bridge_ifname);
+		g_free (stp);
+		g_free (priority);
+		g_free (fwd_delay);
+		g_free (hello_time);
+		g_free (max_age);
+		g_free (ageing_time);
+		g_free (mac);
+		if (mac_array)
+			g_byte_array_free (mac_array, TRUE);
+		if (!success)
+			return FALSE;
+
+	} else if (!strcmp (con_type, "bridge-slave")) {
+		/* Build up the settings required for 'bridge-slave' */
+		gboolean success = FALSE;
+		const char *master = NULL;
+		char *master_ask = NULL;
+		const char *checked_master = NULL;
+		const char *type = NULL;
+		const char *priority_c = NULL;
+		char *priority = NULL;
+		const char *path_cost_c = NULL;
+		char *path_cost = NULL;
+		const char *hairpin_c = NULL;
+		char *hairpin = NULL;
+		unsigned long prio_int, path_cost_int;
+		gboolean hairpin_bool;
+		nmc_arg_t exp_args[] = { {"master",    TRUE, &master,      !ask},
+		                         {"type",      TRUE, &type,        FALSE},
+		                         {"priority",  TRUE, &priority_c,  FALSE},
+		                         {"path-cost", TRUE, &path_cost_c, FALSE},
+		                         {"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 (PROMPT_BRIDGE_MASTER);
+		if (!master) {
+			g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+			                     _("Error: 'master' is required."));
+			return FALSE;
+		}
+		/* Verify master argument */
+		checked_master = verify_master_for_slave (all_connections, master, NM_SETTING_BRIDGE_SETTING_NAME);
+		if (!checked_master)
+			printf (_("Warning: master='%s' doesn't refer to any existing profile.\n"), master);
+
+		if (type)
+			printf (_("Warning: 'type' is currently ignored. "
+			          "We only support ethernet slaves for now.\n"));
+
+		/* Add 'bridge-port' setting */
+		/* Must be done *before* bridge_prop_string_to_uint() so that the type is known */
+		s_bridge_port = (NMSettingBridgePort *) nm_setting_bridge_port_new ();
+		nm_connection_add_setting (connection, NM_SETTING (s_bridge_port));
+
+		/* Also ask for all optional arguments if '--ask' is specified. */
+		priority = priority_c ? g_strdup (priority_c) : NULL;
+		path_cost = path_cost_c ? g_strdup (path_cost_c) : NULL;
+		hairpin = hairpin_c ? g_strdup (hairpin_c) : NULL;
+		if (ask)
+			do_questionnaire_bridge_slave (&priority, &path_cost, &hairpin);
+
+		if (priority)
+			if (!bridge_prop_string_to_uint (priority, "priority", NM_TYPE_SETTING_BRIDGE_PORT,
+			                                 NM_SETTING_BRIDGE_PORT_PRIORITY, &prio_int, error))
+				goto cleanup_bridge_slave;
+		if (path_cost)
+			if (!bridge_prop_string_to_uint (path_cost, "path-cost", NM_TYPE_SETTING_BRIDGE_PORT,
+			                                 NM_SETTING_BRIDGE_PORT_PATH_COST, &path_cost_int, error))
+				goto cleanup_bridge_slave;
+		if (hairpin) {
+			GError *tmp_err = NULL;
+			if (!nmc_string_to_bool (hairpin, &hairpin_bool, &tmp_err)) {
+				g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+				             _("Error: 'hairpin': %s."), tmp_err->message);
+				g_clear_error (&tmp_err);
+				goto cleanup_bridge_slave;
+			}
+		}
+
+		/* Change properties in 'connection' setting */
+		g_object_set (s_con,
+		              NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME,
+		              NM_SETTING_CONNECTION_MASTER, checked_master ? checked_master : _strip_master_prefix (master, NULL),
+		              NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_BRIDGE_SETTING_NAME,
+		              NULL);
+
+		/* Add ethernet setting */
+		s_wired = (NMSettingWired *) nm_setting_wired_new ();
+		nm_connection_add_setting (connection, NM_SETTING (s_wired));
+
+		if (priority)
+			g_object_set (s_bridge_port, NM_SETTING_BRIDGE_PORT_PRIORITY, prio_int, NULL);
+		if (path_cost)
+			g_object_set (s_bridge_port, NM_SETTING_BRIDGE_PORT_PATH_COST, path_cost_int, NULL);
+		if (hairpin)
+			g_object_set (s_bridge_port, NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, hairpin_bool, NULL);
+
+		success = TRUE;
+cleanup_bridge_slave:
+		g_free (master_ask);
+		g_free (priority);
+		g_free (path_cost);
+		g_free (hairpin);
+		if (!success)
+			return FALSE;
+
+	} else if (!strcmp (con_type, NM_SETTING_VPN_SETTING_NAME)) {
+		/* Build up the settings required for 'vpn' */
+		gboolean success = FALSE;
+		const char *vpn_type = NULL;
+		char *vpn_type_ask = NULL;
+		const char *user_c = NULL;
+		char *user = NULL;
+		const char *st;
+		char *service_type = NULL;
+		nmc_arg_t exp_args[] = { {"vpn-type", TRUE, &vpn_type, !ask},
+		                         {"user",     TRUE, &user_c,   FALSE},
+		                         {NULL} };
+
+		if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
+			return FALSE;
+
+		if (!vpn_type && ask)
+			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;
+		}
+		if (vpn_type_ask)
+			vpn_type = g_strstrip (vpn_type_ask);
+
+		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;
+		}
+		service_type = g_strdup_printf ("%s.%s", NM_DBUS_INTERFACE, st);
+
+		/* Also ask for all optional arguments if '--ask' is specified. */
+		user = user_c ? g_strdup (user_c) : NULL;
+		if (ask)
+			do_questionnaire_vpn (&user);
+
+		/* Add 'vpn' setting */
+		s_vpn = (NMSettingVPN *) nm_setting_vpn_new ();
+		nm_connection_add_setting (connection, NM_SETTING (s_vpn));
+
+		g_object_set (s_vpn, NM_SETTING_VPN_SERVICE_TYPE, service_type, NULL);
+		g_object_set (s_vpn, NM_SETTING_VPN_USER_NAME, user, NULL);
+
+		success = TRUE;
+cleanup_vpn:
+		g_free (vpn_type_ask);
+		g_free (service_type);
+		g_free (user);
+		if (!success)
+			return FALSE;
+
+	} else if (!strcmp (con_type, NM_SETTING_OLPC_MESH_SETTING_NAME)) {
+		/* Build up the settings required for 'olpc' */
+		gboolean success = FALSE;
+		char *ssid_ask = NULL;
+		const char *ssid = NULL;
+		GByteArray *ssid_arr;
+		const char *channel_c = NULL;
+		char *channel = NULL;
+		unsigned long chan;
+		const char *dhcp_anycast_c = NULL;
+		char *dhcp_anycast = NULL;
+		GByteArray *array = NULL;
+		nmc_arg_t exp_args[] = { {"ssid",         TRUE, &ssid,           !ask},
+		                         {"channel",      TRUE, &channel_c,      FALSE},
+		                         {"dhcp-anycast", TRUE, &dhcp_anycast_c, FALSE},
+		                         {NULL} };
+
+		if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
+			return FALSE;
+
+		if (!ssid && ask)
+			ssid = ssid_ask = nmc_readline (_("SSID: "));
+		if (!ssid) {
+			g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+			                     _("Error: 'ssid' is required."));
+			goto cleanup_olpc;
+		}
+
+		/* Also ask for all optional arguments if '--ask' is specified. */
+		channel = channel_c ? g_strdup (channel_c) : NULL;
+		dhcp_anycast = dhcp_anycast_c ? g_strdup (dhcp_anycast_c) : NULL;
+		if (ask)
+			do_questionnaire_olpc (&channel, &dhcp_anycast);
+
+		if (channel) {
+			if (!nmc_string_to_uint (channel, TRUE, 1, 13, &chan)) {
+				g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+				             _("Error: 'channel': '%s' is not valid; use <1-13>."),
+				             channel);
+				goto cleanup_olpc;
+			}
+		}
+		if (!check_and_convert_mac (dhcp_anycast, &array, ARPHRD_ETHER, "dhcp-anycast", error))
+			goto cleanup_olpc;
+
+		/* Add OLPC mesh setting */
+		s_olpc_mesh = (NMSettingOlpcMesh *) nm_setting_olpc_mesh_new ();
+		nm_connection_add_setting (connection, NM_SETTING (s_olpc_mesh));
+
+		ssid_arr = g_byte_array_sized_new (strlen (ssid));
+		g_byte_array_append (ssid_arr, (const guint8 *) ssid, strlen (ssid));
+		g_object_set (s_olpc_mesh, NM_SETTING_OLPC_MESH_SSID, ssid_arr, NULL);
+		if (channel)
+			g_object_set (s_olpc_mesh, NM_SETTING_OLPC_MESH_CHANNEL, chan, NULL);
 		else
-			g_string_printf (nmc->return_text, _("Error: No suitable device found."));
+			g_object_set (s_olpc_mesh, NM_SETTING_OLPC_MESH_CHANNEL, 1, NULL);
+		if (array) {
+			g_object_set (s_olpc_mesh, NM_SETTING_OLPC_MESH_DHCP_ANYCAST_ADDRESS, array, NULL);
+			g_byte_array_free (array, TRUE);
+		}
+		g_byte_array_free (ssid_arr, TRUE);
+
+		success = TRUE;
+cleanup_olpc:
+		g_free (ssid_ask);
+		g_free (channel);
+		g_free (dhcp_anycast);
+		if (!success)
+			return FALSE;
+
+	} else {
+		g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+		             _("Error: '%s' is not a valid connection type."),
+		             con_type);
+		return FALSE;
+	}
+
+	/* Read and add IP configuration */
+	if (   strcmp (con_type, "bond-slave") != 0
+	    && strcmp (con_type, "team-slave") != 0
+	    && strcmp (con_type, "bridge-slave") != 0) {
+
+		NMIP4Address *ip4addr = NULL;
+		NMIP6Address *ip6addr = NULL;
+		const char *ip4 = NULL, *gw4 = NULL, *ip6 = NULL, *gw6 = NULL;
+		nmc_arg_t exp_args[] = { {"ip4", TRUE, &ip4, FALSE}, {"gw4", TRUE, &gw4, FALSE},
+		                         {"ip6", TRUE, &ip6, FALSE}, {"gw6", TRUE, &gw6, FALSE},
+		                         {NULL} };
+
+		while (argc) {
+			nmc_arg_t *p;
+
+			/* reset 'found' flag */
+			for (p = exp_args; p->name; p++)
+				p->found = FALSE;
+
+			ip4 = gw4 = ip6 = gw6 = NULL;
+
+			if (!nmc_parse_args (exp_args, TRUE, &argc, &argv, error))
+				return FALSE;
+
+			/* coverity[dead_error_begin] */
+			if (ip4) {
+				ip4addr = nmc_parse_and_build_ip4_address (ip4, gw4, error);
+				if (!ip4addr) {
+					g_prefix_error (error, _("Error: "));
+					return FALSE;
+				}
+				add_ip4_address_to_connection (ip4addr, connection);
+			}
+
+			/* coverity[dead_error_begin] */
+			if (ip6) {
+				ip6addr = nmc_parse_and_build_ip6_address (ip6, gw6, error);
+				if (!ip6addr) {
+					g_prefix_error (error, _("Error: "));
+					return FALSE;
+				}
+				add_ip6_address_to_connection (ip6addr, connection);
+			}
+		}
+
+		/* Ask for addresses if '--ask' is specified. */
+		if (ask)
+			do_questionnaire_ip (connection);
+	}
+
+	return TRUE;
+}
+
+static char *
+unique_connection_name (GSList *list, const char *try_name)
+{
+	NMConnection *connection;
+	const char *name;
+	char *new_name;
+	unsigned int num = 1;
+	GSList *iterator = list;
+
+	new_name = g_strdup (try_name);
+	while (iterator) {
+		connection = NM_CONNECTION (iterator->data);
+
+		name = nm_connection_get_id (connection);
+		if (g_strcmp0 (new_name, name) == 0) {
+			g_free (new_name);
+			new_name = g_strdup_printf ("%s-%d", try_name, num++);
+			iterator = list;
+		}
+		iterator = g_slist_next (iterator);
+	}
+	return new_name;
+}
+
+typedef struct {
+	NmCli *nmc;
+	char *con_name;
+} AddConnectionInfo;
+
+static void
+add_connection_cb (NMRemoteSettings *settings,
+                   NMRemoteConnection *connection,
+                   GError *error,
+                   gpointer user_data)
+{
+	AddConnectionInfo *info = (AddConnectionInfo *) user_data;
+	NmCli *nmc = info->nmc;
+
+	if (error) {
+		g_string_printf (nmc->return_text,
+		                 _("Error: Failed to add '%s' connection: (%d) %s"),
+		                 info->con_name, error->code, error->message);
 		nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
+	} else {
+		printf (_("Connection '%s' (%s) successfully added.\n"),
+		        nm_connection_get_id (NM_CONNECTION (connection)),
+		        nm_connection_get_uuid (NM_CONNECTION (connection)));
+	}
+
+	g_free (info->con_name);
+	g_free (info);
+	quit ();
+}
+
+static gboolean
+add_new_connection (gboolean persistent,
+                    NMRemoteSettings *settings,
+                    NMConnection *connection,
+                    NMRemoteSettingsAddConnectionFunc callback,
+                    gpointer user_data)
+{
+	if (persistent)
+		return nm_remote_settings_add_connection (settings, connection, callback, user_data);
+	else
+		return nm_remote_settings_add_connection_unsaved (settings, connection, callback, user_data);
+}
+
+static void
+update_connection (gboolean persistent,
+                   NMRemoteConnection *connection,
+                   NMRemoteConnectionResultFunc callback,
+                   gpointer user_data)
+{
+	if (persistent)
+		nm_remote_connection_commit_changes (connection, callback, user_data);
+	else
+		nm_remote_connection_commit_changes_unsaved (connection, callback, user_data);
+}
+
+static char *
+gen_func_vpn_types (const char *text, int state)
+{
+	return nmc_rl_gen_func_basic (text, state, nmc_known_vpns);
+}
+
+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_ib_type (const 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 (const 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 (const 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 (const 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 (const 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 (const char *text, int start, int end)
+{
+	char **match_array = NULL;
+	rl_compentry_func_t *generator_func = NULL;
+
+	/* Disable readline's default filename completion */
+	rl_attempted_completion_over = 1;
+
+	/* 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
+do_connection_add (NmCli *nmc, int argc, char **argv)
+{
+	NMConnection *connection = NULL;
+	NMSettingConnection *s_con;
+	char *uuid;
+	char *default_name = NULL;
+	const char *type = NULL;
+	char *type_ask = NULL;
+	const char *con_name = NULL;
+	const char *autoconnect = NULL;
+	gboolean auto_bool = TRUE;
+	const char *ifname = NULL;
+	char *ifname_ask = NULL;
+	gboolean ifname_mandatory = TRUE;
+	const char *save = NULL;
+	gboolean save_bool = TRUE;
+	AddConnectionInfo *info = NULL;
+	const char *setting_name;
+	GError *error = NULL;
+	nmc_arg_t exp_args[] = { {"type",        TRUE, &type,        !nmc->ask},
+	                         {"con-name",    TRUE, &con_name,    FALSE},
+	                         {"autoconnect", TRUE, &autoconnect, FALSE},
+	                         {"ifname",      TRUE, &ifname,      FALSE},
+	                         {"save",        TRUE, &save,        FALSE},
+	                         {NULL} };
+
+	rl_attempted_completion_function = (rl_completion_func_t *) nmcli_con_add_tab_completion;
+
+	nmc->return_value = NMC_RESULT_SUCCESS;
+
+	if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, &error)) {
+		g_string_assign (nmc->return_text, error->message);
+		nmc->return_value = error->code;
+		g_clear_error (&error);
+		goto error;
+	}
+
+	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 (PROMPT_CON_TYPE);
+		g_free (types_tmp);
+	}
+	if (!type) {
+		g_string_printf (nmc->return_text, _("Error: 'type' argument is required."));
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		goto error;
+	}
+	if (type_ask)
+		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."),
+		                 error->message);
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		g_clear_error (&error);
+		goto error;
+	}
+	if (autoconnect) {
+		GError *tmp_err = NULL;
+		if (!nmc_string_to_bool (autoconnect, &auto_bool, &tmp_err)) {
+			g_string_printf (nmc->return_text, _("Error: 'autoconnect': %s."),
+			                 tmp_err->message);
+			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+			g_clear_error (&tmp_err);
+			goto error;
+		}
+	}
+	if (save) {
+		GError *tmp_err = NULL;
+		if (!nmc_string_to_bool (save, &save_bool, &tmp_err)) {
+			g_string_printf (nmc->return_text, _("Error: 'save': %s."),
+			                 tmp_err->message);
+			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+			g_clear_error (&tmp_err);
+			goto error;
+		}
+	}
+
+	/* ifname is mandatory for all connection types except virtual ones (bond, team, bridge, vlan) */
+	if (   strcmp (type, NM_SETTING_BOND_SETTING_NAME) == 0
+	    || strcmp (type, NM_SETTING_TEAM_SETTING_NAME) == 0
+	    || strcmp (type, NM_SETTING_BRIDGE_SETTING_NAME) == 0
+	    || strcmp (type, NM_SETTING_VLAN_SETTING_NAME) == 0)
+		ifname_mandatory = FALSE;
+
+	if (!ifname && ifname_mandatory && nmc->ask) {
+		ifname = ifname_ask = nmc_readline (_("Interface name [*]: "));
+		if (!ifname)
+			ifname = ifname_ask = g_strdup ("*");
+	}
+	if (!ifname && ifname_mandatory) {
+		g_string_printf (nmc->return_text, _("Error: 'ifname' argument is required."));
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		goto error;
+	}
+	if (ifname) {
+		if (!nm_utils_iface_valid_name (ifname) && strcmp (ifname, "*") != 0) {
+			g_string_printf (nmc->return_text,
+			                 _("Error: 'ifname': '%s' is not a valid interface nor '*'."),
+			                 ifname);
+			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+			goto error;
+		}
+		/* Special value of '*' means no specific interface name */
+		if (strcmp (ifname, "*") == 0)
+			ifname = NULL;
+	}
+
+	/* Create a new connection object */
+	connection = nm_connection_new ();
+
+	/* Build up the 'connection' setting */
+	s_con = (NMSettingConnection *) nm_setting_connection_new ();
+	uuid = nm_utils_uuid_generate ();
+	if (con_name)
+		default_name = g_strdup (con_name);
+	else {
+		char *try_name = ifname ?
+		                     g_strdup_printf ("%s-%s", get_name_alias (setting_name, nmc_valid_connection_types), ifname)
+		                   : g_strdup (get_name_alias (setting_name, nmc_valid_connection_types));
+		default_name = unique_connection_name (nmc->system_connections, try_name);
+		g_free (try_name);
+	}
+	g_object_set (s_con,
+	              NM_SETTING_CONNECTION_ID, default_name,
+	              NM_SETTING_CONNECTION_UUID, uuid,
+	              NM_SETTING_CONNECTION_TYPE, setting_name,
+	              NM_SETTING_CONNECTION_AUTOCONNECT, auto_bool,
+	              NM_SETTING_CONNECTION_INTERFACE_NAME, ifname,
+	              NULL);
+	g_free (uuid);
+	g_free (default_name);
+	nm_connection_add_setting (connection, NM_SETTING (s_con));
+
+	if (!complete_connection_by_type (connection,
+	                                  setting_name,
+	                                  nmc->system_connections,
+	                                  nmc->ask,
+	                                  argc,
+	                                  argv,
+	                                  &error)) {
+		g_string_assign (nmc->return_text, error->message);
+		nmc->return_value = error->code;
 		g_clear_error (&error);
 		goto error;
 	}
 
-	/* Use nowait_flag instead of should_wait because exiting has to be postponed till
-	 * active_connection_state_cb() is called. That gives NM time to check our permissions
-	 * and we can follow activation progress.
-	 */
-	nmc->nowait_flag = !wait;
 	nmc->should_wait = TRUE;
 
-	info = g_malloc0 (sizeof (ActivateConnectionInfo));
+	info = g_malloc0 (sizeof (AddConnectionInfo));
 	info->nmc = nmc;
-	info->device = device;
+	info->con_name = g_strdup (nm_connection_get_id (connection));
 
-	nm_client_activate_connection (nmc->client,
-	                               connection,
-	                               device,
-	                               spec_object,
-	                               activate_connection_cb,
-	                               info);
+	/* Tell the settings service to add the new connection */
+	add_new_connection (save_bool,
+	                    nmc->system_settings,
+	                    connection,
+	                    add_connection_cb,
+	                    info);
 
-	/* Start progress indication */
-	if (nmc->print_output == NMC_PRINT_PRETTY)
-		progress_id = g_timeout_add (120, progress_cb, "preparing");
+	if (connection)
+		g_object_unref (connection);
 
 	return nmc->return_value;
+
 error:
+	if (connection)
+		g_object_unref (connection);
+	g_free (type_ask);
+	g_free (ifname_ask);
+
 	nmc->should_wait = FALSE;
 	return nmc->return_value;
 }
 
-static NMCResultCode
-do_connection_down (NmCli *nmc, int argc, char **argv)
+
+/*----------------------------------------------------------------------------*/
+/* Functions for readline TAB completion in editor */
+
+static void
+uuid_display_hook (char **array, int len, int max_len)
 {
-	NMConnection *connection = NULL;
-	NMActiveConnection *active = NULL;
-	GError *error = NULL;
-	const GPtrArray *active_cons;
-	const char *con_path;
-	const char *active_path;
-	gboolean id_specified = FALSE;
-	gboolean wait = TRUE;
-	int i;
+	NMConnection *con;
+	int i, max = 0;
+	char *tmp;
+	const char *id;
 
-	while (argc > 0) {
-		if (strcmp (*argv, "id") == 0 || strcmp (*argv, "uuid") == 0) {
-			const char *selector = *argv;
-			id_specified = TRUE;
+	for (i = 1; i <= len; i++) {
+		con = nmc_find_connection (nmc_tab_completion.nmc->system_connections, "uuid", array[i], NULL);
+		id = con ? nm_connection_get_id (con) : NULL;
+		if (id) {
+			tmp = g_strdup_printf ("%s (%s)", array[i], id);
+			g_free (array[i]);
+			array[i] = tmp;
+			if (max < strlen (id))
+				max = strlen (id);
+		}
+	}
+	rl_display_match_list (array, len, max_len + max + 3);
+	rl_forced_update_display ();
+}
 
-			if (next_arg (&argc, &argv) != 0) {
-				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
-				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-				goto error;
+static char *pre_input_deftext;
+static int
+set_deftext (void)
+{
+	if (pre_input_deftext && rl_startup_hook) {
+		rl_insert_text (pre_input_deftext);
+		g_free (pre_input_deftext);
+		pre_input_deftext = NULL;
+		rl_startup_hook = NULL;
+	}
+	return 0;
+}
+
+static char *
+gen_nmcli_cmds_menu (const char *text, int state)
+{
+	const char *words[] = { "goto", "set", "remove", "describe", "print", "verify",
+	                        "save", "activate", "back", "help", "quit", "nmcli",
+	                        NULL };
+	return nmc_rl_gen_func_basic (text, state, words);
+}
+
+static char *
+gen_nmcli_cmds_submenu (const char *text, int state)
+{
+	const char *words[] = { "set", "add", "change", "remove", "describe",
+	                        "print", "back", "help", "quit",
+	                        NULL };
+	return nmc_rl_gen_func_basic (text, state, words);
+}
+
+static char *
+gen_cmd_nmcli (const char *text, int state)
+{
+	const char *words[] = { "status-line", "save-confirmation", "prompt-color", NULL };
+	return nmc_rl_gen_func_basic (text, state, words);
+}
+
+static char *
+gen_cmd_nmcli_prompt_color (const char *text, int state)
+{
+	const char *words[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", NULL };
+	return nmc_rl_gen_func_basic (text, state, words);
+}
+
+static char *
+gen_func_bool_values (const char *text, int state)
+{
+	const char *words[] = { "yes", "no", NULL };
+	return nmc_rl_gen_func_basic (text, state, words);
+}
+
+static char *
+gen_cmd_verify0 (const char *text, int state)
+{
+	const char *words[] = { "all", NULL };
+	return nmc_rl_gen_func_basic (text, state, words);
+}
+
+static char *
+gen_cmd_print0 (const char *text, int state)
+{
+	static char **words = NULL;
+	char *ret = NULL;
+
+	if (!state) {
+		GHashTable *settings;
+		GHashTableIter iter;
+		const char *setting_name;
+		int i = 0;
+
+		settings = nm_connection_to_hash (nmc_tab_completion.connection, NM_SETTING_HASH_FLAG_NO_SECRETS);
+		words = g_new (char *, g_hash_table_size (settings) + 2);
+		g_hash_table_iter_init (&iter, settings);
+		while (g_hash_table_iter_next (&iter, (gpointer) &setting_name, NULL))
+			words [i++] = g_strdup (setting_name);
+		words[i++] = g_strdup ("all");
+		words[i] = NULL;
+		g_hash_table_unref (settings);
+	}
+
+	if (words) {
+		ret = nmc_rl_gen_func_basic (text, state, (const char **) words);
+		if (ret == NULL) {
+			g_strfreev (words);
+			words = NULL;
+		}
+	}
+	return ret;
+}
+
+static char *
+gen_cmd_print2 (const char *text, int state)
+{
+	const char *words[] = { "setting", "connection", "all", NULL };
+	return nmc_rl_gen_func_basic (text, state, words);
+}
+
+static char *
+gen_cmd_save (const char *text, int state)
+{
+	const char *words[] = { "persistent", "temporary", NULL };
+	return nmc_rl_gen_func_basic (text, state, words);
+}
+
+static char *
+gen_connection_types (const char *text, int state)
+{
+	static int list_idx, len;
+	const char *c_type, *a_type;
+
+	if (!state) {
+		list_idx = 0;
+		len = strlen (text);
+	}
+
+	while (nmc_valid_connection_types[list_idx].name) {
+		a_type = nmc_valid_connection_types[list_idx].alias;
+		c_type = nmc_valid_connection_types[list_idx].name;
+		list_idx++;
+		if (a_type && !strncmp (text, a_type, len))
+			return g_strdup (a_type);
+		if (c_type && !strncmp (text, c_type, len))
+			return g_strdup (c_type);
+	}
+
+	return NULL;
+}
+
+static char *
+gen_setting_names (const char *text, int state)
+{
+	static int list_idx, len;
+	const char *s_name, *a_name;
+	const NameItem *valid_settings_arr;
+
+	if (!state) {
+		list_idx = 0;
+		len = strlen (text);
+	}
+
+	valid_settings_arr = get_valid_settings_array (nmc_tab_completion.con_type);
+	if (!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;
+		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;
+}
+
+static char *
+gen_property_names (const char *text, int state)
+{
+	NMSetting *setting = NULL;
+	char **valid_props = NULL;
+	char *ret = NULL;
+	const char *line = rl_line_buffer;
+	const char *setting_name;
+	char **strv = NULL;
+	const NameItem *valid_settings_arr;
+	const char *p1;
+
+	/* Try to get the setting from 'line' - setting_name.property */
+	p1 = strchr (line, '.');
+	if (p1) {
+		while (p1 > line && !g_ascii_isspace (*p1))
+			p1--;
+
+		strv = g_strsplit (p1+1, ".", 2);
+
+		valid_settings_arr = get_valid_settings_array (nmc_tab_completion.con_type);
+		setting_name = check_valid_name (strv[0], valid_settings_arr, NULL);
+		setting = nmc_setting_new_for_name (setting_name);
+	} else {
+		/* Else take the current setting, if any */
+		setting = nmc_tab_completion.setting ? g_object_ref (nmc_tab_completion.setting) : NULL;
+	}
+
+	if (setting) {
+		valid_props = nmc_setting_get_valid_properties (setting);
+		ret = nmc_rl_gen_func_basic (text, state, (const char **) valid_props);
+	}
+
+	g_strfreev (strv);
+	g_strfreev (valid_props);
+	if (setting)
+		g_object_unref (setting);
+	return ret;
+}
+
+static char *
+gen_compat_devices (const char *text, int state)
+{
+	int i, j = 0;
+	const GPtrArray *devices;
+	const char **compatible_devices;
+	char *ret;
+
+	devices = nm_client_get_devices (nmc_tab_completion.nmc->client);
+	if (!devices || devices->len < 1)
+		return NULL;
+
+	compatible_devices = g_new (const char *, devices->len + 1);
+	for (i = 0; i < devices->len; i++) {
+		NMDevice *dev = g_ptr_array_index (devices, i);
+		const char *ifname = nm_device_get_iface (dev);
+		NMDevice *device = NULL;
+		const char *spec_object = NULL;
+
+		if (find_device_for_connection (nmc_tab_completion.nmc, nmc_tab_completion.connection,
+		                                ifname, NULL, NULL, &device, &spec_object, NULL)) {
+			compatible_devices[j++] = ifname;
+		}
+	}
+	compatible_devices[j] = NULL;
+
+	ret = nmc_rl_gen_func_basic (text, state, compatible_devices);
+
+	g_free (compatible_devices);
+	return ret;
+}
+
+static char *
+gen_vpn_uuids (const char *text, int state)
+{
+	GSList *iter;
+	guint len;
+	int i = 0;
+	const char **uuids;
+	char *ret;
+
+	len = g_slist_length (nmc_tab_completion.nmc->system_connections);
+	if (len < 1)
+		return NULL;
+
+	uuids = g_new (const char *, len + 1);
+	for (iter = nmc_tab_completion.nmc->system_connections; iter; iter = g_slist_next (iter)) {
+		const char *type = nm_connection_get_connection_type (NM_CONNECTION (iter->data));
+
+		if (g_strcmp0 (type, NM_SETTING_VPN_SETTING_NAME) == 0)
+			uuids[i++] = nm_connection_get_uuid (NM_CONNECTION (iter->data));
+	}
+	uuids[i] = NULL;
+
+	ret = nmc_rl_gen_func_basic (text, state, uuids);
+
+	g_free (uuids);
+	return ret;
+}
+
+static rl_compentry_func_t *
+get_gen_func_cmd_nmcli (const char *str)
+{
+	if (!str)
+		return NULL;
+	if (matches (str, "status-line") == 0)
+		return gen_func_bool_values;
+	if (matches (str, "save-confirmation") == 0)
+		return gen_func_bool_values;
+	if (matches (str, "prompt-color") == 0)
+		return gen_cmd_nmcli_prompt_color;
+	return NULL;
+}
+
+/*
+ * Helper function parsing line for completion.
+ * IN:
+ *   line : the whole line to be parsed
+ *   end  : the position of cursor in the line
+ *   cmd  : command to match
+ * OUT:
+ *   cw_num    : is set to the word number being completed (1, 2, 3, 4).
+ *   prev_word : returns the previous word (so that we have some context).
+ *
+ * Returns TRUE when the first word of the 'line' matches 'cmd'.
+ *
+ * Examples:
+ * line="rem"              cmd="remove"   -> TRUE  cw_num=1
+ * line="set con"          cmd="set"      -> TRUE  cw_num=2
+ * line="go ipv4.method"   cmd="goto"     -> TRUE  cw_num=2
+ * line="  des eth.mtu "   cmd="describe" -> TRUE  cw_num=3
+ * line=" bla ipv4.method" cmd="goto"     -> FALSE
+ */
+static gboolean
+should_complete_cmd (const char *line, int end, const char *cmd,
+                     int *cw_num, char **prev_word)
+{
+	char *tmp;
+	const char *word1, *word2, *word3;
+	size_t n1, n2, n3, n4, n5, n6;
+	gboolean word1_done, word2_done, word3_done;
+	gboolean ret = FALSE;
+
+	if (!line)
+		return FALSE;
+
+	tmp = g_strdup (line);
+
+	n1 = strspn  (tmp,    " \t");
+	n2 = strcspn (tmp+n1, " \t\0") + n1;
+	n3 = strspn  (tmp+n2, " \t")   + n2;
+	n4 = strcspn (tmp+n3, " \t\0") + n3;
+	n5 = strspn  (tmp+n4, " \t")   + n4;
+	n6 = strcspn (tmp+n5, " \t\0") + n5;
+
+	word1_done = end > n2;
+	word2_done = end > n4;
+	word3_done = end > n6;
+	tmp[n2] = tmp[n4] = tmp[n6] = '\0';
+
+	word1 = tmp[n1] ? tmp + n1 : NULL;
+	word2 = tmp[n3] ? tmp + n3 : NULL;
+	word3 = tmp[n5] ? tmp + n5 : NULL;
+
+	if (!word1_done) {
+		if (cw_num)
+			*cw_num = 1;
+		if (prev_word)
+			*prev_word = NULL;
+	} else if (!word2_done) {
+		if (cw_num)
+			*cw_num = 2;
+		if (prev_word)
+			*prev_word = g_strdup (word1);
+	} else if (!word3_done) {
+		if (cw_num)
+			*cw_num = 3;
+		if (prev_word)
+			*prev_word = g_strdup (word2);
+	} else {
+		if (cw_num)
+			*cw_num = 4;
+		if (prev_word)
+			*prev_word = g_strdup (word3);
+	}
+
+	if (word1 && matches (word1, cmd) == 0)
+		ret = TRUE;
+
+	g_free (tmp);
+	return ret;
+}
+
+static char *
+extract_property_name (const char *prompt, const char *line)
+{
+	char *prop = NULL;
+
+	/* If prompt is set take the property name from it, else extract it from line */
+	if (!prompt) {
+		const char *p1;
+		size_t num;
+		p1 = strchr (line, '.');
+		if (p1) {
+			p1++;
+		} else {
+			size_t n1, n2, n3;
+			n1 = strspn  (line,    " \t");
+			n2 = strcspn (line+n1, " \t\0") + n1;
+			n3 = strspn  (line+n2, " \t")   + n2;
+			p1 = line + n3;
+		}
+		num = strcspn (p1, " \t\0");
+		prop = g_strndup (p1, num);
+	} else {
+		const char *p1, *dot;
+		size_t num;
+		p1 = strchr (prompt, ' ');
+		/* prompt looks like this: "nmcli 802-1x>" or "nmcli 802-1x.pac-file>" */
+		if (p1) {
+			dot = strchr (p1 + 1, '.');
+			p1 = dot ? dot + 1 : p1;
+			num = strcspn  (p1, ">");
+			prop = g_strndup (p1, num);
+		}
+	}
+
+	return prop;
+}
+
+static gboolean
+should_complete_files (const char *prompt, const char *line)
+{
+	char *prop;
+	gboolean found = FALSE;
+	const char *file_properties[] = {
+		/* '802-1x' properties */
+		"ca-cert",
+		"ca-path",
+		"client-cert",
+		"pac-file",
+		"phase2-ca-cert",
+		"phase2-ca-path",
+		"phase2-client-cert",
+		"private-key",
+		"phase2-private-key",
+		/* 'team' and 'team-port' properties */
+		"config",
+		NULL
+	};
+
+	prop = extract_property_name (prompt, line);
+	if (prop) {
+		found = !!nmc_string_is_valid (prop, file_properties, NULL);
+		g_free (prop);
+	}
+	return found;
+}
+
+static gboolean
+should_complete_vpn_uuids (const char *prompt, const char *line)
+{
+	char *prop;
+	gboolean found = FALSE;
+	const char *uuid_properties[] = {
+		/* 'connection' properties */
+		"secondaries",
+		NULL
+	};
+
+	prop = extract_property_name (prompt, line);
+	if (prop) {
+		found = !!nmc_string_is_valid (prop, uuid_properties, NULL);
+		g_free (prop);
+	}
+	return found;
+}
+
+/* from readline */
+extern int rl_complete_with_tilde_expansion;
+
+/*
+ * Attempt to complete on the contents of TEXT.  START and END show the
+ * region of TEXT that contains the word to complete.  We can use the
+ * entire line in case we want to do some simple parsing.  Return the
+ * array of matches, or NULL if there aren't any.
+ */
+static char **
+nmcli_editor_tab_completion (const char *text, int start, int end)
+{
+	char **match_array = NULL;
+	const char *line = rl_line_buffer;
+	const char *prompt = rl_prompt;
+	rl_compentry_func_t *generator_func = NULL;
+	gboolean copy_char;
+	const char *p1;
+	char *p2, *prompt_tmp;
+	char *word = NULL;
+	size_t n1;
+	int num;
+
+	/* Restore standard append character to space */
+	rl_completion_append_character = ' ';
+
+	/* Restore standard function for displaying matches */
+	rl_completion_display_matches_hook = NULL;
+
+	/* Disable default filename completion */
+	rl_attempted_completion_over = 1;
+
+	/* Enable tilde expansion when filenames are completed */
+	rl_complete_with_tilde_expansion = 1;
+
+	/* Filter out possible ANSI color escape sequences */
+	p1 = prompt;
+	p2 = prompt_tmp = g_strdup (prompt);
+	copy_char = TRUE;
+	while (*p1) {
+		if (*p1 == '\33')
+			copy_char = FALSE;
+		if (copy_char)
+			*p2++ = *p1;
+		if (!copy_char && *p1 == 'm')
+			copy_char = TRUE;
+		p1++;
+	}
+	*p2 = '\0';
+
+	/* Find the first non-space character */
+	n1 = strspn (line, " \t");
+
+	/* Choose the right generator function */
+	if (strcmp (prompt_tmp, EDITOR_PROMPT_CON_TYPE) == 0)
+		generator_func = gen_connection_types;
+	else if (strcmp (prompt_tmp, EDITOR_PROMPT_SETTING) == 0)
+		generator_func = gen_setting_names;
+	else if (strcmp (prompt_tmp, EDITOR_PROMPT_PROPERTY) == 0)
+		generator_func = gen_property_names;
+	else if (   g_str_has_suffix (rl_prompt, prompt_yes_no (TRUE, NULL))
+	         || g_str_has_suffix (rl_prompt, prompt_yes_no (FALSE, NULL)))
+		generator_func = gen_func_bool_values_l10n;
+	else if (g_str_has_prefix (prompt_tmp, "nmcli")) {
+		if (!strchr (prompt_tmp, '.')) {
+			int level = g_str_has_prefix (prompt_tmp, "nmcli>") ? 0 : 1;
+			const char *dot = strchr (line, '.');
+
+			/* Main menu  - level 0,1 */
+			if (start == n1)
+				generator_func = gen_nmcli_cmds_menu;
+			else {
+				if (should_complete_cmd (line, end, "goto", &num, NULL) && num <= 2) {
+					if (level == 0 && (!dot || dot >= line + end))
+						generator_func = gen_setting_names;
+					else
+						generator_func = gen_property_names;
+				} else if (should_complete_cmd (line, end, "set", &num, NULL)) {
+					if (num < 3) {
+						if (level == 0 && (!dot || dot >= line + end)) {
+							generator_func = gen_setting_names;
+							rl_completion_append_character = '.';
+						} else
+							generator_func = gen_property_names;
+					} else if (num >= 3) {
+						if (num == 3 && should_complete_files (NULL, line))
+							rl_attempted_completion_over = 0;
+						if (should_complete_vpn_uuids (NULL, line)) {
+							rl_completion_display_matches_hook = uuid_display_hook;
+							generator_func = gen_vpn_uuids;
+						}
+					}
+				} else if (  (   should_complete_cmd (line, end, "remove", &num, NULL)
+				              || should_complete_cmd (line, end, "describe", &num, NULL))
+				           && num <= 2) {
+					if (level == 0 && (!dot || dot >= line + end)) {
+						generator_func = gen_setting_names;
+						rl_completion_append_character = '.';
+					} else
+						generator_func = gen_property_names;
+				} else if (should_complete_cmd (line, end, "nmcli", &num, &word)) {
+					if (num < 3)
+						generator_func = gen_cmd_nmcli;
+					else if (num == 3)
+						generator_func = get_gen_func_cmd_nmcli (word);
+				} else if (should_complete_cmd (line, end, "print", &num, NULL) && num <= 2) {
+					if (level == 0 && (!dot || dot >= line + end))
+						generator_func = gen_cmd_print0;
+					else
+						generator_func = gen_property_names;
+				} else if (should_complete_cmd (line, end, "verify", &num, NULL) && num <= 2) {
+					generator_func = gen_cmd_verify0;
+				} else if (should_complete_cmd (line, end, "activate", &num, NULL) && num <= 2) {
+					generator_func = gen_compat_devices;
+				} else if (should_complete_cmd (line, end, "save", &num, NULL) && num <= 2) {
+					generator_func = gen_cmd_save;
+				} else if (should_complete_cmd (line, end, "help", &num, NULL) && num <= 2)
+					generator_func = gen_nmcli_cmds_menu;
 			}
+		} else {
+			/* Submenu - level 2 */
+			if (start == n1)
+				generator_func = gen_nmcli_cmds_submenu;
+			else {
+				if (   should_complete_cmd (line, end, "add", &num, NULL)
+				    || should_complete_cmd (line, end, "set", &num, NULL)) {
+					if (num <= 2 && should_complete_files (prompt_tmp, line))
+						rl_attempted_completion_over = 0;
+					else if (should_complete_vpn_uuids (prompt_tmp, line)) {
+						rl_completion_display_matches_hook = uuid_display_hook;
+						generator_func = gen_vpn_uuids;
+					}
+				}
+				if (should_complete_cmd (line, end, "print", &num, NULL) && num <= 2)
+					generator_func = gen_cmd_print2;
+				else if (should_complete_cmd (line, end, "help", &num, NULL) && num <= 2)
+					generator_func = gen_nmcli_cmds_submenu;
+			}
+		}
+	}
 
-			connection = find_connection (nmc->system_connections, selector, *argv);
+	if (generator_func)
+		match_array = rl_completion_matches (text, generator_func);
 
-			if (!connection) {
-				g_string_printf (nmc->return_text, _("Error: Unknown connection: %s."), *argv);
-				nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
-				goto error;
+	g_free (prompt_tmp);
+	g_free (word);
+	return match_array;
+}
+
+#define NMCLI_EDITOR_HISTORY ".nmcli-history"
+
+static void
+load_history_cmds (const char *uuid)
+{
+	GKeyFile *kf;
+	char *filename;
+	char **keys;
+	char *line;
+	size_t i;
+	GError *err = NULL;
+
+	filename = g_build_filename (g_get_home_dir (), NMCLI_EDITOR_HISTORY, NULL);
+	kf = g_key_file_new ();
+	if (!g_key_file_load_from_file (kf, filename, G_KEY_FILE_KEEP_COMMENTS, &err)) {
+		if (err->code == G_KEY_FILE_ERROR_PARSE)
+			printf ("Warning: %s parse error: %s\n", filename, err->message);
+		g_key_file_free (kf);
+		g_free (filename);
+		return;
+	}
+	keys = g_key_file_get_keys (kf, uuid, NULL, NULL);
+	for (i = 0; keys && keys[i]; i++) {
+		line = g_key_file_get_string (kf, uuid, keys[i], NULL);
+		if (line && *line)
+			add_history (line);
+		g_free (line);
+	}
+	g_strfreev (keys);
+	g_key_file_free (kf);
+	g_free (filename);
+}
+
+static void
+save_history_cmds (const char *uuid)
+{
+	HIST_ENTRY **hist = NULL;
+	GKeyFile *kf;
+	char *filename;
+	size_t i;
+	char *key;
+	char *data;
+	gsize len = 0;
+	GError *err = NULL;
+
+	hist = history_list ();
+	if (hist) {
+		filename = g_build_filename (g_get_home_dir (), NMCLI_EDITOR_HISTORY, NULL);
+		kf = g_key_file_new ();
+		if (!g_key_file_load_from_file (kf, filename, G_KEY_FILE_KEEP_COMMENTS, &err)) {
+			if (   err->code != G_FILE_ERROR_NOENT
+			    && err->code != G_KEY_FILE_ERROR_NOT_FOUND) {
+				printf ("Warning: %s parse error: %s\n", filename, err->message);
+				g_key_file_free (kf);
+				g_free (filename);
+				g_clear_error (&err);
+				return;
 			}
+			g_clear_error (&err);
 		}
-		else if (strcmp (*argv, "--nowait") == 0) {
-			wait = FALSE;
+
+		/* Remove previous history group and save new history entries */
+		g_key_file_remove_group (kf, uuid, NULL);
+		for (i = 0; hist[i]; i++)
+		{
+			key = g_strdup_printf ("%zd", i);
+			g_key_file_set_string (kf, uuid, key, hist[i]->line);
+			g_free (key);
 		}
-		else {
-			fprintf (stderr, _("Unknown parameter: %s\n"), *argv);
+
+		/* Write history to file */
+		data = g_key_file_to_data (kf, &len, NULL);
+		if (data) {
+			g_file_set_contents (filename, data, len, NULL);
+			g_free (data);
 		}
+		g_key_file_free (kf);
+		g_free (filename);
+	}
+}
 
-		argc--;
-		argv++;
+/*----------------------------------------------------------------------------*/
+
+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_connection_profile_details (connection, nmc);
+}
+
+static void
+editor_show_setting (NMSetting *setting, NmCli *nmc)
+{
+	printf (_("['%s' setting values]\n"),
+	        nm_setting_get_name (setting));
+
+	nmc->print_output = NMC_PRINT_NORMAL;
+	nmc->multiline_output = TRUE;
+	nmc->escape_values = 0;
+
+	/* Remove any previous data */
+	nmc_empty_output_fields (nmc);
+
+	setting_details (setting, nmc, NULL);
+}
+
+typedef enum {
+	NMC_EDITOR_MAIN_CMD_UNKNOWN = 0,
+	NMC_EDITOR_MAIN_CMD_GOTO,
+	NMC_EDITOR_MAIN_CMD_REMOVE,
+	NMC_EDITOR_MAIN_CMD_SET,
+	NMC_EDITOR_MAIN_CMD_DESCRIBE,
+	NMC_EDITOR_MAIN_CMD_PRINT,
+	NMC_EDITOR_MAIN_CMD_VERIFY,
+	NMC_EDITOR_MAIN_CMD_SAVE,
+	NMC_EDITOR_MAIN_CMD_ACTIVATE,
+	NMC_EDITOR_MAIN_CMD_BACK,
+	NMC_EDITOR_MAIN_CMD_HELP,
+	NMC_EDITOR_MAIN_CMD_NMCLI,
+	NMC_EDITOR_MAIN_CMD_QUIT,
+} NmcEditorMainCmd;
+
+static NmcEditorMainCmd
+parse_editor_main_cmd (const char *cmd, char **cmd_arg)
+{
+	NmcEditorMainCmd editor_cmd = NMC_EDITOR_MAIN_CMD_UNKNOWN;
+	char **vec;
+
+	vec = nmc_strsplit_set (cmd, " \t", 2);
+	if (g_strv_length (vec) < 1) {
+		if (cmd_arg)
+			*cmd_arg = NULL;
+		return NMC_EDITOR_MAIN_CMD_UNKNOWN;
 	}
 
-	if (!id_specified) {
-		g_string_printf (nmc->return_text, _("Error: id or uuid has to be specified."));
-		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-		goto error;
+	if (matches (vec[0], "goto") == 0)
+		editor_cmd = NMC_EDITOR_MAIN_CMD_GOTO;
+	else if (matches (vec[0], "remove") == 0)
+		editor_cmd = NMC_EDITOR_MAIN_CMD_REMOVE;
+	else if (matches (vec[0], "set") == 0)
+		editor_cmd = NMC_EDITOR_MAIN_CMD_SET;
+	else if (matches (vec[0], "describe") == 0)
+		editor_cmd = NMC_EDITOR_MAIN_CMD_DESCRIBE;
+	else if (matches (vec[0], "print") == 0)
+		editor_cmd = NMC_EDITOR_MAIN_CMD_PRINT;
+	else if (matches (vec[0], "verify") == 0)
+		editor_cmd = NMC_EDITOR_MAIN_CMD_VERIFY;
+	else if (matches (vec[0], "save") == 0)
+		editor_cmd = NMC_EDITOR_MAIN_CMD_SAVE;
+	else if (matches (vec[0], "activate") == 0)
+		editor_cmd = NMC_EDITOR_MAIN_CMD_ACTIVATE;
+	else if (matches (vec[0], "back") == 0)
+		editor_cmd = NMC_EDITOR_MAIN_CMD_BACK;
+	else if (matches (vec[0], "help") == 0 || strcmp (vec[0], "?") == 0)
+		editor_cmd = NMC_EDITOR_MAIN_CMD_HELP;
+	else if (matches (vec[0], "quit") == 0)
+		editor_cmd = NMC_EDITOR_MAIN_CMD_QUIT;
+	else if (matches (vec[0], "nmcli") == 0)
+		editor_cmd = NMC_EDITOR_MAIN_CMD_NMCLI;
+
+	/* set pointer to command argument */
+	if (cmd_arg)
+		*cmd_arg = vec[1] ? g_strstrip (g_strdup (vec[1])) : NULL;
+
+	g_strfreev (vec);
+	return editor_cmd;
+}
+
+static void
+editor_main_usage (void)
+{
+	printf ("------------------------------------------------------------------------------\n");
+	/* TRANSLATORS: do not translate command names and keywords before ::
+	 *              However, you should translate terms enclosed in <>.
+	 */
+	printf (_("---[ Main menu ]---\n"
+	          "goto     [<setting> | <prop>]        :: go to a setting or property\n"
+	          "remove   <setting>[.<prop>] | <prop> :: remove setting or reset property value\n"
+	          "set      [<setting>.<prop> <value>]  :: set property value\n"
+	          "describe [<setting>.<prop>]          :: describe property\n"
+	          "print    [all | <setting>[.<prop>]]  :: print the connection\n"
+	          "verify   [all]                       :: verify the connection\n"
+	          "save     [persistent|temporary]      :: save the connection\n"
+	          "activate [<ifname>] [/<ap>|<nsp>]    :: activate the connection\n"
+	          "back                                 :: go one level up (back)\n"
+	          "help/?   [<command>]                 :: print this help\n"
+	          "nmcli    <conf-option> <value>       :: nmcli configuration\n"
+	          "quit                                 :: exit nmcli\n"));
+	printf ("------------------------------------------------------------------------------\n");
+}
+
+static void
+editor_main_help (const char *command)
+{
+	if (!command)
+		editor_main_usage ();
+	else {
+		/* detailed command descriptions */
+		NmcEditorMainCmd cmd = parse_editor_main_cmd (command, NULL);
+
+		switch (cmd) {
+		case NMC_EDITOR_MAIN_CMD_GOTO:
+			printf (_("goto <setting>[.<prop>] | <prop>  :: enter setting/property for editing\n\n"
+			          "This command enters into a setting or property for editing it.\n\n"
+			          "Examples: nmcli> goto connection\n"
+			          "          nmcli connection> goto secondaries\n"
+			          "          nmcli> goto ipv4.addresses\n"));
+			break;
+		case NMC_EDITOR_MAIN_CMD_REMOVE:
+			printf (_("remove <setting>[.<prop>]  :: remove setting or reset property value\n\n"
+			          "This command removes an entire setting from the connection, or if a property\n"
+			          "is given, resets that property to the default value.\n\n"
+			          "Examples: nmcli> remove wifi-sec\n"
+			          "          nmcli> remove eth.mtu\n"));
+			break;
+		case NMC_EDITOR_MAIN_CMD_SET:
+			printf (_("set [<setting>.<prop> <value>]  :: set property value\n\n"
+			          "This command sets property value.\n\n"
+			          "Example: nmcli> set con.id My connection\n"));
+			break;
+		case NMC_EDITOR_MAIN_CMD_DESCRIBE:
+			printf (_("describe [<setting>.<prop>]  :: describe property\n\n"
+			          "Shows property description. You can consult nm-settings(5) "
+			          "manual page to see all NM settings and properties.\n"));
+			break;
+		case NMC_EDITOR_MAIN_CMD_PRINT:
+			printf (_("print [all]  :: print setting or connection values\n\n"
+			          "Shows current property or the whole connection.\n\n"
+			          "Example: nmcli ipv4> print all\n"));
+			break;
+		case NMC_EDITOR_MAIN_CMD_VERIFY:
+			printf (_("verify [all]  :: verify setting or connection validity\n\n"
+			          "Verifies whether the setting or connection is valid and can "
+			          "be saved later. It indicates invalid values on error.\n\n"
+			          "Examples: nmcli> verify\n"
+			          "          nmcli bond> verify\n"));
+			break;
+		case NMC_EDITOR_MAIN_CMD_SAVE:
+			printf (_("save [persistent|temporary]  :: save the connection\n\n"
+			          "Sends the connection profile to NetworkManager that either will save it\n"
+			          "persistently, or will only keep it in memory. 'save' without an argument\n"
+			          "means 'save persistent'.\n"
+			          "Note that once you save the profile persistently those settings are saved\n"
+			          "across reboot or restart. Subsequent changes can also be temporary or\n"
+			          "persistent, but any temporary changes will not persist across reboot or\n"
+			          "restart. If you want to fully remove the persistent connection, the connection\n"
+			          "profile must be deleted.\n"));
+			break;
+		case NMC_EDITOR_MAIN_CMD_ACTIVATE:
+			printf (_("activate [<ifname>] [/<ap>|<nsp>]  :: activate the connection\n\n"
+			          "Activates the connection.\n\n"
+			          "Available options:\n"
+			          "<ifname>    - device the connection will be activated on\n"
+			          "/<ap>|<nsp> - AP (Wi-Fi) or NSP (WiMAX) (prepend with / when <ifname> is not specified)\n"));
+			break;
+		case NMC_EDITOR_MAIN_CMD_BACK:
+			printf (_("back  :: go to upper menu level\n\n"));
+			break;
+		case NMC_EDITOR_MAIN_CMD_HELP:
+			printf (_("help/? [<command>]  :: help for the nmcli commands\n\n"));
+			break;
+		case NMC_EDITOR_MAIN_CMD_NMCLI:
+			printf (_("nmcli [<conf-option> <value>]  :: nmcli configuration\n\n"
+			          "Configures nmcli. The following options are available:\n"
+			          "status-line yes | no        [default: no]\n"
+			          "save-confirmation yes | no  [default: yes]\n"
+			          "prompt-color <0-8>          [default: 0]\n"
+			          "  0 = normal\n"
+			          "  1 = \33[30mblack\33[0m\n"
+			          "  2 = \33[31mred\33[0m\n"
+			          "  3 = \33[32mgreen\33[0m\n"
+			          "  4 = \33[33myellow\33[0m\n"
+			          "  5 = \33[34mblue\33[0m\n"
+			          "  6 = \33[35mmagenta\33[0m\n"
+			          "  7 = \33[36mcyan\33[0m\n"
+			          "  8 = \33[37mwhite\33[0m\n"
+			          "\n"
+			          "Examples: nmcli> nmcli status-line yes\n"
+			          "          nmcli> nmcli save-confirmation no\n"
+			          "          nmcli> nmcli prompt-color 3\n"));
+			break;
+		case NMC_EDITOR_MAIN_CMD_QUIT:
+			printf (_("quit  :: exit nmcli\n\n"
+			          "This command exits nmcli. When the connection being edited "
+			          "is not saved, the user is asked to confirm the action.\n"));
+			break;
+		default:
+			printf (_("Unknown command: '%s'\n"), command);
+			break;
+		}
 	}
+}
 
-	if (!nmc_is_nm_running (nmc, &error)) {
-		if (error) {
-			g_string_printf (nmc->return_text, _("Error: Can't find out if NetworkManager is running: %s."), error->message);
-			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
-			g_error_free (error);
+typedef enum {
+	NMC_EDITOR_SUB_CMD_UNKNOWN = 0,
+	NMC_EDITOR_SUB_CMD_SET,
+	NMC_EDITOR_SUB_CMD_ADD,
+	NMC_EDITOR_SUB_CMD_CHANGE,
+	NMC_EDITOR_SUB_CMD_REMOVE,
+	NMC_EDITOR_SUB_CMD_DESCRIBE,
+	NMC_EDITOR_SUB_CMD_PRINT,
+	NMC_EDITOR_SUB_CMD_BACK,
+	NMC_EDITOR_SUB_CMD_HELP,
+	NMC_EDITOR_SUB_CMD_QUIT
+} NmcEditorSubCmd;
+
+static NmcEditorSubCmd
+parse_editor_sub_cmd (const char *cmd, char **cmd_arg)
+{
+	NmcEditorSubCmd editor_cmd = NMC_EDITOR_SUB_CMD_UNKNOWN;
+	char **vec;
+
+	vec = nmc_strsplit_set (cmd, " \t", 2);
+	if (g_strv_length (vec) < 1) {
+		if (cmd_arg)
+			*cmd_arg = NULL;
+		return NMC_EDITOR_SUB_CMD_UNKNOWN;
+	}
+
+	if (matches (vec[0], "set") == 0)
+		editor_cmd = NMC_EDITOR_SUB_CMD_SET;
+	else if (matches (vec[0], "add") == 0)
+		editor_cmd = NMC_EDITOR_SUB_CMD_ADD;
+	else if (matches (vec[0], "change") == 0)
+		editor_cmd = NMC_EDITOR_SUB_CMD_CHANGE;
+	else if (matches (vec[0], "remove") == 0)
+		editor_cmd = NMC_EDITOR_SUB_CMD_REMOVE;
+	else if (matches (vec[0], "describe") == 0)
+		editor_cmd = NMC_EDITOR_SUB_CMD_DESCRIBE;
+	else if (matches (vec[0], "print") == 0)
+		editor_cmd = NMC_EDITOR_SUB_CMD_PRINT;
+	else if (matches (vec[0], "back") == 0)
+		editor_cmd = NMC_EDITOR_SUB_CMD_BACK;
+	else if (matches (vec[0], "help") == 0 || strcmp (vec[0], "?") == 0)
+		editor_cmd = NMC_EDITOR_SUB_CMD_HELP;
+	else if (matches (vec[0], "quit") == 0)
+		editor_cmd = NMC_EDITOR_SUB_CMD_QUIT;
+
+	/* set pointer to command argument */
+	if (cmd_arg)
+		*cmd_arg = g_strdup (vec[1]);
+
+	g_strfreev (vec);
+	return editor_cmd;
+}
+
+static void
+editor_sub_help (void)
+{
+	printf ("------------------------------------------------------------------------------\n");
+	/* TRANSLATORS: do not translate command names and keywords before ::
+	 *              However, you should translate terms enclosed in <>.
+	 */
+	printf (_("---[ Property menu ]---\n"
+	          "set      [<value>]               :: set new value\n"
+	          "add      [<value>]               :: add new option to the property\n"
+	          "change                           :: change current value\n"
+	          "remove   [<index> | <option>]    :: delete the value\n"
+	          "describe                         :: describe property\n"
+	          "print    [setting | connection]  :: print property (setting/connection) value(s)\n"
+	          "back                             :: go to upper level\n"
+	          "help/?   [<command>]             :: print this help or command description\n"
+	          "quit                             :: exit nmcli\n"));
+	printf ("------------------------------------------------------------------------------\n");
+}
+
+static void
+editor_sub_usage (const char *command)
+{
+
+	if (!command)
+		editor_sub_help ();
+	else {
+		/* detailed command descriptions */
+		NmcEditorSubCmd cmdsub = parse_editor_sub_cmd (command, NULL);
+
+		switch (cmdsub) {
+		case NMC_EDITOR_SUB_CMD_SET:
+			printf (_("set [<value>]  :: set new value\n\n"
+			          "This command sets provided <value> to this property\n"));
+			break;
+		case NMC_EDITOR_SUB_CMD_ADD:
+			printf (_("add [<value>]  :: append new value to the property\n\n"
+			          "This command adds provided <value> to this property, if "
+			          "the property is of a container type. For single-valued "
+			          "properties the property value is replaced (same as 'set').\n"));
+			break;
+		case NMC_EDITOR_SUB_CMD_CHANGE:
+			printf (_("change  :: change current value\n\n"
+			          "Displays current value and allows editing it.\n"));
+			break;
+		case NMC_EDITOR_SUB_CMD_REMOVE:
+			printf (_("remove [<value>|<index>|<option name>]  :: delete the value\n\n"
+			          "Removes the property value. For single-valued properties, this sets the\n"
+			          "property back to its default value. For container-type properties, this removes\n"
+			          "all the values of that property, or you can specify an argument to remove just\n"
+			          "a single item or option. The argument is either a value or index of the item to\n"
+			          "remove, or an option name (for properties with named options).\n\n"
+			          "Examples: nmcli ipv4.dns> remove 8.8.8.8\n"
+			          "          nmcli ipv4.dns> remove 2\n"
+			          "          nmcli bond.options> remove downdelay\n\n"));
+			break;
+		case NMC_EDITOR_SUB_CMD_DESCRIBE:
+			printf (_("describe  :: describe property\n\n"
+			          "Shows property description. You can consult nm-settings(5) "
+			          "manual page to see all NM settings and properties.\n"));
+			break;
+		case NMC_EDITOR_SUB_CMD_PRINT:
+			printf (_("print [property|setting|connection]  :: print property (setting, connection) value(s)\n\n"
+			          "Shows property value. Providing an argument you can also display "
+			          "values for the whole setting or connection.\n"));
+			break;
+		case NMC_EDITOR_SUB_CMD_BACK:
+			printf (_("back  :: go to upper menu level\n\n"));
+			break;
+		case NMC_EDITOR_SUB_CMD_HELP:
+			printf (_("help/? [<command>]  :: help for nmcli commands\n\n"));
+			break;
+		case NMC_EDITOR_SUB_CMD_QUIT:
+			printf (_("quit  :: exit nmcli\n\n"
+			          "This command exits nmcli. When the connection being edited "
+			          "is not saved, the user is asked to confirm the action.\n"));
+			break;
+		default:
+			printf (_("Unknown command: '%s'\n"), command);
+			break;
+		}
+	}
+}
+
+/*----------------------------------------------------------------------------*/
+
+typedef struct {
+	NMDevice *device;
+	NMActiveConnection *ac;
+	guint monitor_id;
+} MonitorACInfo;
+
+static gboolean nmc_editor_cb_called;
+static GError *nmc_editor_error;
+static MonitorACInfo *nmc_editor_monitor_ac;
+static GMutex nmc_editor_mutex;
+static GCond nmc_editor_cond;
+
+/*
+ * Store 'error' to shared 'nmc_editor_error' and monitoring info to
+ * 'nmc_editor_monitor_ac' and signal the condition so that
+ * the 'editor-thread' thread could process that.
+ */
+static void
+set_info_and_signal_editor_thread (GError *error, MonitorACInfo *monitor_ac_info)
+{
+	g_mutex_lock (&nmc_editor_mutex);
+	nmc_editor_cb_called = TRUE;
+	nmc_editor_error = error ? g_error_copy (error) : NULL;
+	nmc_editor_monitor_ac = monitor_ac_info;
+	g_cond_signal (&nmc_editor_cond);
+	g_mutex_unlock (&nmc_editor_mutex);
+}
+
+static void
+add_connection_editor_cb (NMRemoteSettings *settings,
+                          NMRemoteConnection *connection,
+                          GError *error,
+                          gpointer user_data)
+{
+	set_info_and_signal_editor_thread (error, NULL);
+}
+
+static void
+update_connection_editor_cb (NMRemoteConnection *connection,
+                             GError *error,
+                             gpointer user_data)
+{
+	set_info_and_signal_editor_thread (error, NULL);
+}
+
+static gboolean
+progress_activation_editor_cb (gpointer user_data)
+{
+	MonitorACInfo *info = (MonitorACInfo *) user_data;
+	NMDevice *device = info->device;
+	NMActiveConnection *ac = info->ac;
+	NMActiveConnectionState ac_state;
+	NMDeviceState dev_state;
+
+	if (!device || !ac)
+		goto finish;
+
+	ac_state = nm_active_connection_get_state (ac);
+	dev_state = nm_device_get_state (device);
+
+	nmc_terminal_show_progress (nmc_device_state_to_string (dev_state));
+
+	if (   ac_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED
+	    || dev_state == NM_DEVICE_STATE_ACTIVATED) {
+		nmc_terminal_erase_line ();
+		printf (_("Connection successfully activated (D-Bus active path: %s)\n"),
+		        nm_object_get_path (NM_OBJECT (ac)));
+		goto finish; /* we are done */
+	} else if (   ac_state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED
+	           || dev_state == NM_DEVICE_STATE_FAILED) {
+		nmc_terminal_erase_line ();
+		printf (_("Error: Connection activation failed.\n"));
+		goto finish; /* we are done */
+	}
+
+	return TRUE;
+
+finish:
+	if (device)
+		g_object_unref (device);
+	if (ac)
+		g_object_unref (ac);
+	return FALSE;
+}
+
+static void
+activate_connection_editor_cb (NMClient *client,
+                               NMActiveConnection *active,
+                               GError *error,
+                               gpointer user_data)
+{
+	ActivateConnectionInfo *info = (ActivateConnectionInfo *) user_data;
+	NMDevice *device = info->device;
+	const GPtrArray *ac_devs;
+	MonitorACInfo *monitor_ac_info = NULL;
+
+	if (!error) {
+		if (!device) {
+			ac_devs = nm_active_connection_get_devices (active);
+			device = ac_devs && ac_devs->len > 0 ? g_ptr_array_index (ac_devs, 0) : NULL;
+		}
+		if (device) {
+			monitor_ac_info = g_malloc0 (sizeof (AddConnectionInfo));
+			monitor_ac_info->device = g_object_ref (device);
+			monitor_ac_info->ac = active ? g_object_ref (active) : NULL;
+			monitor_ac_info->monitor_id = g_timeout_add (120, progress_activation_editor_cb, monitor_ac_info);
+		}
+	}
+	set_info_and_signal_editor_thread (error, monitor_ac_info);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static void
+print_property_description (NMSetting *setting, const char *prop_name)
+{
+	char *desc;
+
+	desc = nmc_setting_get_property_desc (setting, prop_name);
+	printf ("\n=== [%s] ===\n%s\n", prop_name, desc);
+	g_free (desc);
+}
+
+static void
+print_setting_description (NMSetting *setting)
+{
+	/* Show description of all properties */
+	char **all_props;
+	int i;
+
+	all_props = nmc_setting_get_valid_properties (setting);
+	printf (("<<< %s >>>\n"), nm_setting_get_name (setting));
+	for (i = 0; all_props && all_props[i]; i++)
+		print_property_description (setting, all_props[i]);
+	g_strfreev (all_props);
+}
+
+static gboolean
+connection_remove_setting (NMConnection *connection, NMSetting *setting)
+{
+	gboolean mandatory;
+
+	g_return_val_if_fail (setting, FALSE);
+
+	mandatory = is_setting_mandatory (connection, setting);
+	if (!mandatory) {
+		nm_connection_remove_setting (connection, G_OBJECT_TYPE (setting));
+		return TRUE;
+	}
+	printf (_("Error: setting '%s' is mandatory and cannot be removed.\n"),
+	        nm_setting_get_name (setting));
+	return FALSE;
+}
+
+static void
+editor_show_status_line (NMConnection *connection, gboolean dirty, gboolean temp)
+{
+	NMSettingConnection *s_con;
+	const char *con_type, *con_id, *con_uuid;
+
+	s_con = nm_connection_get_setting_connection (connection);
+	g_assert (s_con);
+	con_type = nm_setting_connection_get_connection_type (s_con);
+	con_id = nm_connection_get_id (connection);
+	con_uuid = nm_connection_get_uuid (connection);
+
+	/* TRANSLATORS: status line in nmcli connection editor */
+	printf (_("[ Type: %s | Name: %s | UUID: %s | Dirty: %s | Temp: %s ]\n"),
+	        con_type, con_id, con_uuid,
+	        dirty ? _("yes") : _("no"),
+	        temp ? _("yes") : _("no"));
+}
+
+static gboolean
+refresh_remote_connection (GWeakRef *weak, NMRemoteConnection **remote)
+{
+	gboolean previous;
+
+	g_return_val_if_fail (remote != NULL, FALSE);
+
+	previous = (*remote != NULL);
+	if (*remote)
+		g_object_unref (*remote);
+	*remote = g_weak_ref_get (weak);
+
+	return (previous && !*remote);
+}
+
+static gboolean
+is_connection_dirty (NMConnection *connection, NMRemoteConnection *remote)
+{
+	return !nm_connection_compare (connection,
+	                               remote ? NM_CONNECTION (remote) : NULL,
+	                               NM_SETTING_COMPARE_FLAG_EXACT);
+}
+
+static gboolean
+confirm_quit (void)
+{
+	char *answer;
+	gboolean want_quit = FALSE;
+
+	answer = nmc_readline (_("The connection is not saved. "
+	                         "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) == 0)
+		want_quit = TRUE;
+
+	g_free (answer);
+	return want_quit;
+}
+
+/*
+ * Submenu for detailed property editing
+ * Return: TRUE - continue;  FALSE - should quit
+ */
+static gboolean
+property_edit_submenu (NmCli *nmc,
+                       NMConnection *connection,
+                       NMRemoteConnection **rem_con,
+                       GWeakRef *rem_con_weak,
+                       NMSetting *curr_setting,
+                       const char *prop_name)
+{
+	NmcEditorSubCmd cmdsub;
+	gboolean cmd_property_loop = TRUE;
+	gboolean should_quit = FALSE;
+	char *prop_val_user;
+	gboolean set_result;
+	GError *tmp_err = NULL;
+	char *prompt;
+	gboolean dirty;
+	GValue prop_g_value = G_VALUE_INIT;
+	gboolean temp_changes;
+	gboolean removed;
+
+	prompt = nmc_colorize (nmc->editor_prompt_color, "nmcli %s.%s> ",
+	                       nm_setting_get_name (curr_setting), prop_name);
+
+	while (cmd_property_loop) {
+		char *cmd_property_user;
+		char *cmd_property_arg;
+
+		/* Get the remote connection again, it may have disapeared */
+		removed = refresh_remote_connection (rem_con_weak, rem_con);
+		if (removed)
+			printf (_("The connection profile has been removed from another client. "
+			          "You may type 'save' in the main menu to restore it.\n"));
+
+		/* 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;
+		if (nmc->editor_status_line)
+			editor_show_status_line (connection, dirty, temp_changes);
+
+		cmd_property_user = nmc_readline ("%s", prompt);
+		if (!cmd_property_user || *cmd_property_user == '\0')
+			continue;
+		cmdsub = parse_editor_sub_cmd (g_strstrip (cmd_property_user), &cmd_property_arg);
+
+		switch (cmdsub) {
+		case NMC_EDITOR_SUB_CMD_SET:
+		case NMC_EDITOR_SUB_CMD_ADD:
+			/* list, arrays,...: SET replaces the whole property value
+			 *                   ADD adds the new value(s)
+			 * single values:  : both SET and ADD sets the new value
+			 */
+			if (!cmd_property_arg)
+				prop_val_user = nmc_readline (_("Enter '%s' value: "), prop_name);
+			else
+				prop_val_user = g_strdup (cmd_property_arg);
+
+			/* nmc_setting_set_property() only adds new value, thus we have to
+			 * remove the original value and save it for error cases.
+			 */
+			if (cmdsub == NMC_EDITOR_SUB_CMD_SET) {
+				nmc_property_get_gvalue (curr_setting, prop_name, &prop_g_value);
+				nmc_property_set_default_value (curr_setting, prop_name);
+			}
+
+			set_result = nmc_setting_set_property (curr_setting, prop_name, prop_val_user, &tmp_err);
+			g_free (prop_val_user);
+			if (!set_result) {
+				printf (_("Error: failed to set '%s' property: %s\n"), prop_name, tmp_err->message);
+				g_clear_error (&tmp_err);
+				if (cmdsub == NMC_EDITOR_SUB_CMD_SET)
+					nmc_property_set_gvalue (curr_setting, prop_name, &prop_g_value);
+			}
+			if (G_IS_VALUE (&prop_g_value))
+				g_value_unset (&prop_g_value);
+			break;
+
+		case NMC_EDITOR_SUB_CMD_CHANGE:
+			rl_startup_hook = set_deftext;
+			pre_input_deftext = nmc_setting_get_property_out2in (curr_setting, prop_name, NULL);
+			prop_val_user = nmc_readline (_("Edit '%s' value: "), prop_name);
+
+			nmc_property_get_gvalue (curr_setting, prop_name, &prop_g_value);
+			nmc_property_set_default_value (curr_setting, prop_name);
+
+			if (!nmc_setting_set_property (curr_setting, prop_name, prop_val_user, &tmp_err)) {
+				printf (_("Error: failed to set '%s' property: %s\n"), prop_name, tmp_err->message);
+				g_clear_error (&tmp_err);
+				nmc_property_set_gvalue (curr_setting, prop_name, &prop_g_value);
+			}
+			g_free (prop_val_user);
+			if (G_IS_VALUE (&prop_g_value))
+				g_value_unset (&prop_g_value);
+			break;
+
+		case NMC_EDITOR_SUB_CMD_REMOVE:
+			if (cmd_property_arg) {
+				unsigned long val_int = G_MAXUINT32;
+				char *option = NULL;
+
+				if (!nmc_string_to_uint (cmd_property_arg, TRUE, 0, G_MAXUINT32, &val_int))
+					option = g_strdup (cmd_property_arg);
+
+				if (!nmc_setting_remove_property_option (curr_setting, prop_name,
+				                                         option ? g_strstrip (option) : NULL,
+				                                         (guint32) val_int,
+				                                         &tmp_err)) {
+					printf (_("Error: %s\n"), tmp_err->message);
+					g_clear_error (&tmp_err);
+				}
+				g_free (option);
+			} else {
+				if (!nmc_setting_reset_property (curr_setting, prop_name, &tmp_err)) {
+					printf (_("Error: failed to remove value of '%s': %s\n"), prop_name,
+					        tmp_err->message);
+					g_clear_error (&tmp_err);
+				}
+			}
+			break;
+
+		case NMC_EDITOR_SUB_CMD_DESCRIBE:
+			/* Show property description */
+			print_property_description (curr_setting, prop_name);
+			break;
+
+		case NMC_EDITOR_SUB_CMD_PRINT:
+			/* Print current connection settings/properties */
+			if (cmd_property_arg) {
+				if (matches (cmd_property_arg, "setting") == 0)
+					editor_show_setting (curr_setting, nmc);
+				else if (   matches (cmd_property_arg, "connection") == 0
+				         || matches (cmd_property_arg, "all") == 0)
+					editor_show_connection (connection, nmc);
+				else
+					printf (_("Unknown command argument: '%s'\n"), cmd_property_arg);
+			} else {
+				char *prop_val =  nmc_setting_get_property (curr_setting, prop_name, NULL);
+				printf ("%s: %s\n", prop_name, prop_val);
+				g_free (prop_val);
+			}
+			break;
+
+		case NMC_EDITOR_SUB_CMD_BACK:
+			cmd_property_loop = FALSE;
+			break;
+
+		case NMC_EDITOR_SUB_CMD_HELP:
+			editor_sub_usage (cmd_property_arg);
+			break;
+
+		case NMC_EDITOR_SUB_CMD_QUIT:
+			if (is_connection_dirty (connection, *rem_con)) {
+				if (confirm_quit ()) {
+					cmd_property_loop = FALSE;
+					should_quit = TRUE;  /* we will quit nmcli */
+				}
+			} else {
+				cmd_property_loop = FALSE;
+				should_quit = TRUE;  /* we will quit nmcli */
+			}
+			break;
+
+		case NMC_EDITOR_SUB_CMD_UNKNOWN:
+		default:
+			printf (_("Unknown command: '%s'\n"), cmd_property_user);
+			break;
+		}
+		g_free (cmd_property_user);
+		g_free (cmd_property_arg);
+	}
+	g_free (prompt);
+
+	return !should_quit;
+}
+
+/*
+ * Split 'str' in the following format:  [[[setting.]property] [value]]
+ * and return the components in 'setting', 'property' and 'value'
+ * Use g_free() to deallocate the returned strings.
+ */
+static void
+split_editor_main_cmd_args (const char *str, char **setting, char **property, char **value)
+{
+	char **args, **items;
+
+	if (!str)
+		return;
+
+	args = nmc_strsplit_set (str, " \t", 2);
+	if (args[0]) {
+		items = nmc_strsplit_set (args[0], ".", 2);
+		if (g_strv_length (items) == 2) {
+			if (setting)
+				*setting = g_strdup (items[0]);
+			if (property)
+				*property = g_strdup (items[1]);
 		} else {
-			g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
-			nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
+			if (property)
+				*property = g_strdup (items[0]);
 		}
-		goto error;
+		g_strfreev (items);
+
+		if (value && args[1])
+			*value = g_strstrip (g_strdup (args[1]));
 	}
+	g_strfreev (args);
+}
 
-	/* create NMClient */
-	nmc->get_client (nmc);
+static NMSetting *
+is_setting_valid (NMConnection *connection, const NameItem *valid_settings, char *setting)
+{
+	const char *setting_name;
 
-	con_path = nm_connection_get_path (connection);
+	if (!(setting_name = check_valid_name (setting, valid_settings, NULL)))
+		return NULL;
+	return nm_connection_get_setting_by_name (connection, setting_name);
+}
 
-	active_cons = nm_client_get_active_connections (nmc->client);
-	for (i = 0; active_cons && (i < active_cons->len); i++) {
-		NMActiveConnection *candidate = g_ptr_array_index (active_cons, i);
+static char *
+is_property_valid (NMSetting *setting, const char *property, GError **error)
+{
+	char **valid_props = NULL;
+	const char *prop_name;
+	char *ret;
+
+	valid_props = nmc_setting_get_valid_properties (setting);
+	prop_name = nmc_string_is_valid (property, (const char **) valid_props, error);
+	ret = prop_name ? g_strdup (prop_name) : NULL;
+	g_strfreev (valid_props);
+	return ret;
+}
 
-		active_path = nm_active_connection_get_connection (candidate);
-		if (!strcmp (active_path, con_path)) {
-			active = candidate;
+static NMSetting *
+create_setting_by_name (const char *name, const NameItem *valid_settings)
+{
+	const char *setting_name;
+	NMSetting *setting = NULL;
+
+	/* Get a valid setting name */
+	setting_name = check_valid_name (name, valid_settings, 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);
+	}
+	return setting;
+}
+
+static const char *
+ask_check_setting (const char *arg,
+                   const NameItem *valid_settings_arr,
+                   const char *valid_settings_str)
+{
+	char *setting_name_user;
+	const char *setting_name;
+	GError *err = NULL;
+
+	if (!arg) {
+		printf (_("Available settings: %s\n"), valid_settings_str);
+		setting_name_user = nmc_readline (EDITOR_PROMPT_SETTING);
+	} else
+		setting_name_user = g_strdup (arg);
+
+	if (setting_name_user)
+		g_strstrip (setting_name_user);
+
+	if (!(setting_name = check_valid_name (setting_name_user, valid_settings_arr, &err))) {
+		printf (_("Error: invalid setting name; %s\n"), err->message);
+		g_clear_error (&err);
+	}
+	g_free (setting_name_user);
+	return setting_name;
+}
+
+static const char *
+ask_check_property (const char *arg,
+                    const char **valid_props,
+                    const char *valid_props_str)
+{
+	char *prop_name_user;
+	const char *prop_name;
+	GError *tmp_err = NULL;
+
+	if (!arg) {
+		printf (_("Available properties: %s\n"), valid_props_str);
+		prop_name_user = nmc_readline (EDITOR_PROMPT_PROPERTY);
+		if (prop_name_user)
+			g_strstrip (prop_name_user);
+	} else
+		prop_name_user = g_strdup (arg);
+
+	if (!(prop_name = nmc_string_is_valid (prop_name_user, valid_props, &tmp_err))) {
+		printf (_("Error: property %s\n"), tmp_err->message);
+		g_clear_error (&tmp_err);
+	}
+	g_free (prop_name_user);
+	return prop_name;
+}
+
+/* Copy timestamp from src do dst */
+static void
+update_connection_timestamp (NMConnection *src, NMConnection *dst)
+{
+	NMSettingConnection *s_con_src, *s_con_dst;
+
+	s_con_src = nm_connection_get_setting_connection (src);
+	s_con_dst = nm_connection_get_setting_connection (dst);
+	if (s_con_src && s_con_dst) {
+		guint64 timestamp = nm_setting_connection_get_timestamp (s_con_src);
+		g_object_set (s_con_dst, NM_SETTING_CONNECTION_TIMESTAMP, timestamp, NULL);
+	}
+}
+
+static gboolean
+confirm_connection_saving (NMConnection *local, NMConnection *remote)
+{
+	NMSettingConnection *s_con_loc, *s_con_rem;
+	gboolean ac_local, ac_remote;
+	gboolean confirmed = TRUE;
+
+	s_con_loc = nm_connection_get_setting_connection (local);
+	g_assert (s_con_loc);
+	ac_local = nm_setting_connection_get_autoconnect (s_con_loc);
+
+	if (remote) {
+		s_con_rem = nm_connection_get_setting_connection (remote);
+		g_assert (s_con_rem);
+		ac_remote = nm_setting_connection_get_autoconnect (s_con_rem);
+	} else
+		ac_remote = FALSE;
+
+	if (ac_local && !ac_remote) {
+		char *answer;
+		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;
+		g_free (answer);
+	}
+	return confirmed;
+}
+
+typedef	struct {
+	guint level;
+	char *main_prompt;
+	NMSetting *curr_setting;
+	char **valid_props;
+	char *valid_props_str;
+} NmcEditorMenuContext;
+
+static void
+menu_switch_to_level0 (NmcEditorMenuContext *menu_ctx,
+                       const char *prompt,
+                       NmcTermColor prompt_color)
+{
+	menu_ctx->level = 0;
+	g_free (menu_ctx->main_prompt);
+	menu_ctx->main_prompt = nmc_colorize (prompt_color, "%s", prompt);
+	menu_ctx->curr_setting = NULL;
+	g_strfreev (menu_ctx->valid_props);
+	menu_ctx->valid_props = NULL;
+	g_free (menu_ctx->valid_props_str);
+	menu_ctx->valid_props_str = NULL;
+}
+
+static void
+menu_switch_to_level1 (NmcEditorMenuContext *menu_ctx,
+                       NMSetting *setting,
+                       const char *setting_name,
+                       NmcTermColor prompt_color)
+{
+	menu_ctx->level = 1;
+	g_free (menu_ctx->main_prompt);
+	menu_ctx->main_prompt = nmc_colorize (prompt_color, "nmcli %s> ", setting_name);
+	menu_ctx->curr_setting = setting;
+	g_strfreev (menu_ctx->valid_props);
+	menu_ctx->valid_props = nmc_setting_get_valid_properties (menu_ctx->curr_setting);
+	g_free (menu_ctx->valid_props_str);
+	menu_ctx->valid_props_str = g_strjoinv (", ", menu_ctx->valid_props);
+}
+
+static gboolean
+editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_type)
+{
+	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 char *BASE_PROMPT = "nmcli> ";
+	const NameItem *valid_settings_arr = NULL;
+	char *valid_settings_str = NULL;
+	AddConnectionInfo *info = NULL;
+	gboolean dirty;
+	gboolean temp_changes;
+	GError *err1 = NULL;
+	NmcEditorMenuContext menu_ctx;
+
+	valid_settings_arr = get_valid_settings_array (connection_type);
+	valid_settings_str = get_valid_options_string (valid_settings_arr);
+	printf (_("You may edit the following settings: %s\n"), valid_settings_str);
+
+	menu_ctx.level = 0;
+	menu_ctx.main_prompt = nmc_colorize (nmc->editor_prompt_color, BASE_PROMPT);
+	menu_ctx.curr_setting = NULL;
+	menu_ctx.valid_props = NULL;
+	menu_ctx.valid_props_str = NULL;
+
+	/* Get remote connection */
+	con_tmp = nm_remote_settings_get_connection_by_uuid (nmc->system_settings,
+	                                                     nm_connection_get_uuid (connection));
+	g_weak_ref_init (&weak, con_tmp);
+	rem_con = g_weak_ref_get (&weak);
+
+	while (cmd_loop) {
+		/* 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;
+		if (nmc->editor_status_line)
+			editor_show_status_line (connection, dirty, temp_changes);
+
+		/* Read user input */
+		cmd_user = nmc_readline ("%s", menu_ctx.main_prompt);
+
+		/* Get the remote connection again, it may have disapeared */
+		removed = refresh_remote_connection (&weak, &rem_con);
+		if (removed)
+			printf (_("The connection profile has been removed from another client. "
+			          "You may type 'save' to restore it.\n"));
+
+		if (!cmd_user || *cmd_user == '\0')
+			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) {
+					const char *prop_name;
+					char *prop_val_user = NULL;
+					const char *avals;
+					GError *tmp_err = NULL;
+
+					prop_name = ask_check_property (cmd_arg,
+					                                (const char **) menu_ctx.valid_props,
+					                                menu_ctx.valid_props_str);
+					if (!prop_name)
+						break;
+
+					avals = nmc_setting_get_property_allowed_values (menu_ctx.curr_setting, prop_name);
+					if (avals)
+						printf (_("Allowed values for '%s' property: %s\n"), prop_name, avals);
+
+					prop_val_user = nmc_readline (_("Enter '%s' value: "), prop_name);
+
+					/* Set property value */
+					if (!nmc_setting_set_property (menu_ctx.curr_setting, prop_name, prop_val_user, &tmp_err)) {
+						printf (_("Error: failed to set '%s' property: %s\n"), prop_name, tmp_err->message);
+						g_clear_error (&tmp_err);
+					}
+				} else {
+					printf (_("Error: no setting selected; valid are [%s]\n"), valid_settings_str);
+					printf (_("use 'goto <setting>' first, or 'set <setting>.<property>'\n"));
+				}
+			} else {
+				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_arr, cmd_arg_s);
+					if (!ss) {
+						ss = create_setting_by_name (cmd_arg_s, valid_settings_arr);
+						if (!ss) {
+							printf (_("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)
+						ss = menu_ctx.curr_setting;
+					else {
+						printf (_("Error: missing setting for '%s' property\n"), cmd_arg_p);
+						break;
+					}
+				}
+
+				prop_name = is_property_valid (ss, cmd_arg_p, &tmp_err);
+				if (!prop_name) {
+					printf (_("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);
+					if (avals)
+						printf (_("Allowed values for '%s' property: %s\n"), prop_name, avals);
+
+					cmd_arg_v = nmc_readline (_("Enter '%s' value: "), prop_name);
+				}
+
+				/* Set property value */
+				if (!nmc_setting_set_property (ss, prop_name, cmd_arg_v, &tmp_err)) {
+					printf (_("Error: failed to set '%s' property: %s\n"),
+					        prop_name, tmp_err->message);
+					g_clear_error (&tmp_err);
+				}
+
+				if (created_ss)
+					nm_connection_add_setting (connection, ss);
+				g_free (prop_name);
+			}
+			break;
+
+		case NMC_EDITOR_MAIN_CMD_GOTO:
+			/* cmd_arg_s != NULL means 'setting.property' argument */
+			if (menu_ctx.level == 0 || cmd_arg_s) {
+				/* in top level - no setting selected yet */
+				const char *setting_name;
+				NMSetting *setting;
+				const char *user_arg = cmd_arg_s ? cmd_arg_s : cmd_arg_p;
+
+				setting_name = ask_check_setting (user_arg, valid_settings_arr, 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) {
+						printf (_("Error: unknown setting '%s'\n"), setting_name);
+						break;
+					}
+					nmc_setting_custom_init (setting);
+					nm_connection_add_setting (connection, setting);
+				}
+				/* Set global variable for use in TAB completion */
+				nmc_tab_completion.setting = setting;
+
+				/* Switch to level 1 */
+				menu_switch_to_level1 (&menu_ctx, setting, setting_name, nmc->editor_prompt_color);
+
+				if (!cmd_arg_s) {
+					printf (_("You may edit the following properties: %s\n"), menu_ctx.valid_props_str);
+					break;
+				}
+			}
+			if (menu_ctx.level == 1 || cmd_arg_s) {
+				/* level 1 - setting selected */
+				const char *prop_name;
+
+				prop_name = ask_check_property (cmd_arg_p,
+				                                (const char **) menu_ctx.valid_props,
+				                                menu_ctx.valid_props_str);
+				if (!prop_name)
+					break;
+
+				/* submenu - level 2 - editing properties */
+				cmd_loop = property_edit_submenu (nmc,
+				                                  connection,
+				                                  &rem_con,
+				                                  &weak,
+				                                  menu_ctx.curr_setting,
+				                                  prop_name);
+			}
+			break;
+
+		case NMC_EDITOR_MAIN_CMD_REMOVE:
+			/* Remove setting from connection, or delete value of a property */
+			if (!cmd_arg) {
+				if (menu_ctx.level == 1) {
+					GError *tmp_err = NULL;
+					const char *prop_name;
+
+					prop_name = ask_check_property (cmd_arg,
+					                                (const char **) menu_ctx.valid_props,
+					                                menu_ctx.valid_props_str);
+					if (!prop_name)
+						break;
+
+					/* Delete property value */
+					if (!nmc_setting_reset_property (menu_ctx.curr_setting, prop_name, &tmp_err)) {
+						printf (_("Error: failed to remove value of '%s': %s\n"), prop_name,
+						        tmp_err->message);
+						g_clear_error (&tmp_err);
+					}
+				} else
+					printf (_("Error: no argument given; valid are [%s]\n"), valid_settings_str);
+			} else {
+				NMSetting *ss = NULL;
+				gboolean descr_all;
+				char *user_s;
+
+				/* cmd_arg_s != NULL means argument is "setting.property" */
+				descr_all = !cmd_arg_s && !menu_ctx.curr_setting;
+				user_s = descr_all ? cmd_arg_p : cmd_arg_s ? cmd_arg_s : NULL;
+				if (user_s) {
+					ss = is_setting_valid (connection, valid_settings_arr, user_s);
+					if (!ss) {
+						if (check_valid_name (user_s, valid_settings_arr, NULL))
+							printf (_("Setting '%s' is not present in the connection.\n"), user_s);
+						else
+							printf (_("Error: invalid setting argument '%s'; valid are [%s]\n"),
+							        user_s, valid_settings_str);
+						break;
+					}
+				} else
+					ss = menu_ctx.curr_setting;
+
+				if (descr_all) {
+					/* Remove setting from the 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 (&menu_ctx, BASE_PROMPT, nmc->editor_prompt_color);
+						nmc_tab_completion.setting = NULL;  /* for TAB completion */
+					}
+				} else {
+					GError *tmp_err = NULL;
+					char *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)) {
+							printf (_("Error: failed to remove value of '%s': %s\n"), prop_name,
+							        tmp_err->message);
+							g_clear_error (&tmp_err);
+						}
+					} else {
+						/* If the string is not a property, try it as a setting */
+						NMSetting *s_tmp;
+						s_tmp = is_setting_valid (connection, valid_settings_arr, 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 (&menu_ctx, BASE_PROMPT, nmc->editor_prompt_color);
+								nmc_tab_completion.setting = NULL;  /* for TAB completion */
+							}
+						} else
+							printf (_("Error: %s properties, nor it is a setting name.\n"),
+							        tmp_err->message);
+						g_clear_error (&tmp_err);
+					}
+					g_free (prop_name);
+				}
+			}
+			break;
+
+		case NMC_EDITOR_MAIN_CMD_DESCRIBE:
+			/* Print property description */
+			if (!cmd_arg) {
+				if (menu_ctx.level == 1) {
+					const char *prop_name;
+
+					prop_name = ask_check_property (cmd_arg,
+					                                (const char **) menu_ctx.valid_props,
+					                                menu_ctx.valid_props_str);
+					if (!prop_name)
+						break;
+
+					/* Show property description */
+					print_property_description (menu_ctx.curr_setting, prop_name);
+				} else {
+					printf (_("Error: no setting selected; valid are [%s]\n"), valid_settings_str);
+					printf (_("use 'goto <setting>' first, or 'describe <setting>.<property>'\n"));
+				}
+			} else {
+				NMSetting *ss = NULL;
+				gboolean unref_ss = FALSE;
+				gboolean descr_all;
+				char *user_s;
+
+				/* cmd_arg_s != NULL means argument is "setting.property" */
+				descr_all = !cmd_arg_s && !menu_ctx.curr_setting;
+				user_s = descr_all ? cmd_arg_p : cmd_arg_s ? cmd_arg_s : NULL;
+				if (user_s) {
+					ss = is_setting_valid (connection, valid_settings_arr, user_s);
+					if (!ss) {
+						ss = create_setting_by_name (user_s, valid_settings_arr);
+						if (!ss) {
+							printf (_("Error: invalid setting argument '%s'; valid are [%s]\n"),
+							        user_s, valid_settings_str);
+							break;
+						}
+						unref_ss = TRUE;
+					}
+				} else
+					ss = menu_ctx.curr_setting;
+
+				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);
+					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_arr, cmd_arg_p);
+						if (s_tmp)
+							print_setting_description (s_tmp);
+						else
+							printf (_("Error: invalid property: %s, "
+							          "neither a valid setting name.\n"),
+							        tmp_err->message);
+						g_clear_error (&tmp_err);
+					}
+					g_free (prop_name);
+				}
+				if (unref_ss)
+					g_object_unref (ss);
+			}
+			break;
+
+		case NMC_EDITOR_MAIN_CMD_PRINT:
+			/* Print current connection settings/properties */
+			if (cmd_arg) {
+				if (strcmp (cmd_arg, "all") == 0)
+					editor_show_connection (connection, nmc);
+				else {
+					NMSetting *ss = NULL;
+					gboolean whole_setting;
+					char *user_s;
+
+					/* cmd_arg_s != NULL means argument is "setting.property" */
+					whole_setting = !cmd_arg_s && !menu_ctx.curr_setting;
+					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_arr, NULL);
+						if (!s_name) {
+							printf (_("Error: unknown setting: '%s'\n"), user_s);
+							break;
+						}
+						ss = nm_connection_get_setting_by_name (connection, s_name);
+						if (!ss) {
+							printf (_("Error: '%s' setting not present in the connection\n"), s_name);
+							break;
+						}
+					} else
+						ss = menu_ctx.curr_setting;
+
+					if (whole_setting) {
+						/* Print the whole setting */
+						editor_show_setting (ss, nmc);
+					} else {
+						GError *err = NULL;
+						char *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);
+							printf ("%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_arr, cmd_arg_p);
+							if (s_tmp) {
+								/* Print the whole setting */
+								editor_show_setting (s_tmp, nmc);
+							} else
+								printf (_("Error: invalid property: %s%s\n"),
+								        err->message,
+								        cmd_arg_s ? "" : _(", neither a valid setting name"));
+							g_clear_error (&err);
+						}
+						g_free (prop_name);
+					}
+				}
+			} else {
+				if (menu_ctx.curr_setting)
+					editor_show_setting (menu_ctx.curr_setting, nmc);
+				else
+					editor_show_connection (connection, nmc);
+			}
+			break;
+
+		case NMC_EDITOR_MAIN_CMD_VERIFY:
+			/* Verify current setting or the whole connection */
+			if (   menu_ctx.curr_setting
+			    && (!cmd_arg || strcmp (cmd_arg, "all") != 0)) {
+				GError *tmp_err = NULL;
+				(void) nm_setting_verify (menu_ctx.curr_setting, NULL, &tmp_err);
+				printf (_("Verify setting '%s': %s\n"),
+				        nm_setting_get_name (menu_ctx.curr_setting),
+				        tmp_err ? tmp_err->message : "OK");
+				g_clear_error (&tmp_err);
+			} else {
+				GError *tmp_err = NULL;
+				(void) nm_connection_verify (connection, &tmp_err);
+				printf (_("Verify connection: %s\n"),
+				        tmp_err ? tmp_err->message : "OK");
+				g_clear_error (&tmp_err);
+			}
+			break;
+
+		case NMC_EDITOR_MAIN_CMD_SAVE:
+			/* Save the connection */
+			if (nm_connection_verify (connection, &err1)) {
+				gboolean persistent = TRUE;
+
+				/* parse argument */
+				if (cmd_arg) {
+					if (matches (cmd_arg, "temporary") == 0)
+						persistent = FALSE;
+					else if (matches (cmd_arg, "persistent") == 0)
+						persistent = TRUE;
+					else {
+						printf (_("Error: invalid argument '%s'\n"), cmd_arg);
+						break;
+					}
+				}
+
+				/* Ask for save confirmation if the connection changes to autoconnect=yes */
+				if (nmc->editor_save_confirmation)
+					if (!confirm_connection_saving (connection, NM_CONNECTION (rem_con)))
+						break;
+
+				if (!rem_con) {
+					/* Tell the settings service to add the new connection */
+					info = g_malloc0 (sizeof (AddConnectionInfo));
+					info->nmc = nmc;
+					info->con_name = g_strdup (nm_connection_get_id (connection));
+					add_new_connection (persistent,
+					                    nmc->system_settings,
+					                    connection,
+					                    add_connection_editor_cb,
+					                    info);
+				} else {
+					/* Save/update already saved (existing) connection */
+					nm_connection_replace_settings_from_connection (NM_CONNECTION (rem_con),
+					                                                connection,
+					                                                NULL);
+					update_connection (persistent, rem_con, update_connection_editor_cb, NULL);
+				}
+
+				g_mutex_lock (&nmc_editor_mutex);
+				//FIXME: add also a timeout for cases the callback is not called
+				while (!nmc_editor_cb_called)
+					g_cond_wait (&nmc_editor_cond, &nmc_editor_mutex);
+
+				if (nmc_editor_error) {
+					printf (_("Error: Failed to save '%s' (%s) connection: (%d) %s\n"),
+					        nm_connection_get_id (connection),
+					        nm_connection_get_uuid (connection),
+					        nmc_editor_error->code, nmc_editor_error->message);
+
+					g_error_free (nmc_editor_error);
+				} else {
+					printf (!rem_con ?
+					        _("Connection '%s' (%s) successfully saved.\n") :
+					        _("Connection '%s' (%s) successfully updated.\n"),
+					        nm_connection_get_id (connection),
+					        nm_connection_get_uuid (connection));
+
+					con_tmp = nm_remote_settings_get_connection_by_uuid (nmc->system_settings,
+					                                                     nm_connection_get_uuid (connection));
+					g_weak_ref_set (&weak, con_tmp);
+					refresh_remote_connection (&weak, &rem_con);
+
+					/* Replace local connection with the remote one to be sure they are equal.
+					 * This mitigates problems with plugins not preserving some properties or
+					 * adding ipv{4,6} settings when not present.
+					 */
+					if (con_tmp) {
+						char *s_name = NULL;
+						if (menu_ctx.curr_setting)
+							s_name = g_strdup (nm_setting_get_name (menu_ctx.curr_setting));
+
+						/* Update settings in the local connection */
+						nm_connection_replace_settings_from_connection (connection,
+						                                                NM_CONNECTION (con_tmp),
+						                                                NULL);
+
+						/* 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);
+					}
+				}
+
+				nmc_editor_cb_called = FALSE;
+				nmc_editor_error = NULL;
+				g_mutex_unlock (&nmc_editor_mutex);
+			} else
+				printf (_("Error: connection verification failed: %s\n"),
+				        err1 ? err1->message : _("(unknown error)"));
+
+			g_clear_error (&err1);
 			break;
+
+		case NMC_EDITOR_MAIN_CMD_ACTIVATE:
+			{
+			GError *tmp_err = NULL;
+			const char *ifname = cmd_arg_p;
+			const char *ap_nsp = cmd_arg_v;
+
+			/* When only AP/NSP is specified it is prepended with '/' */
+			if (!cmd_arg_v) {
+				if (ifname && ifname[0] == '/') {
+					ap_nsp = ifname + 1;
+					ifname = NULL;
+				}
+			} else
+				ap_nsp = ap_nsp && ap_nsp[0] == '/' ? ap_nsp + 1 : ap_nsp;
+
+			if (is_connection_dirty (connection, rem_con)) {
+				printf (_("Error: connection is not saved. Type 'save' first.\n"));
+				break;
+			}
+			if (!nm_connection_verify (NM_CONNECTION (rem_con), &tmp_err)) {
+				printf (_("Error: connection is not valid: %s\n"), tmp_err->message);
+				g_clear_error (&tmp_err);
+				break;
+			}
+			nmc->get_client (nmc);
+
+			nmc->nowait_flag = FALSE;
+			nmc->should_wait = TRUE;
+			nmc->print_output = NMC_PRINT_PRETTY;
+			if (!nmc_activate_connection (nmc, NM_CONNECTION (rem_con), ifname, ap_nsp, ap_nsp,
+			                              activate_connection_editor_cb, &tmp_err)) {
+				printf (_("Error: Cannot activate connection: %s.\n"), tmp_err->message);
+				g_clear_error (&tmp_err);
+				break;
+			}
+
+			g_mutex_lock (&nmc_editor_mutex);
+			while (!nmc_editor_cb_called)
+				g_cond_wait (&nmc_editor_cond, &nmc_editor_mutex);
+
+			if (nmc_editor_error) {
+				printf (_("Error: Failed to activate '%s' (%s) connection: (%d) %s\n"),
+				        nm_connection_get_id (connection),
+				        nm_connection_get_uuid (connection),
+				        nmc_editor_error->code, nmc_editor_error->message);
+				g_error_free (nmc_editor_error);
+			} else {
+				printf (_("Monitoring connection activation (press any key to continue)\n"));
+				nmc_get_user_input ("");
+			}
+
+			if (nmc_editor_monitor_ac) {
+				if (nmc_editor_monitor_ac->monitor_id)
+					g_source_remove (nmc_editor_monitor_ac->monitor_id);
+				g_free (nmc_editor_monitor_ac);
+			}
+			nmc_editor_cb_called = FALSE;
+			nmc_editor_error = NULL;
+			nmc_editor_monitor_ac = NULL;
+			g_mutex_unlock (&nmc_editor_mutex);
+
+			/* Update timestamp in local connection */
+			update_connection_timestamp (NM_CONNECTION (rem_con), connection);
+
+			}
+			break;
+
+		case NMC_EDITOR_MAIN_CMD_BACK:
+			/* Go back (up) an the menu */
+			if (menu_ctx.level == 1) {
+				menu_switch_to_level0 (&menu_ctx, BASE_PROMPT, nmc->editor_prompt_color);
+				nmc_tab_completion.setting = NULL;  /* for TAB completion */
+			}
+			break;
+
+		case NMC_EDITOR_MAIN_CMD_HELP:
+			/* Print command help */
+			editor_main_help (cmd_arg);
+			break;
+
+		case NMC_EDITOR_MAIN_CMD_NMCLI:
+			if (cmd_arg_p && matches (cmd_arg_p, "status-line") == 0) {
+				GError *tmp_err = NULL;
+				gboolean bb;
+				if (!nmc_string_to_bool (cmd_arg_v ? g_strstrip (cmd_arg_v) : "", &bb, &tmp_err)) {
+					printf (_("Error: status-line: %s\n"), tmp_err->message);
+					g_clear_error (&tmp_err);
+				} else
+					nmc->editor_status_line = bb;
+			} else if (cmd_arg_p && matches (cmd_arg_p, "save-confirmation") == 0) {
+				GError *tmp_err = NULL;
+				gboolean bb;
+				if (!nmc_string_to_bool (cmd_arg_v ? g_strstrip (cmd_arg_v) : "", &bb, &tmp_err)) {
+					printf (_("Error: save-confirmation: %s\n"), tmp_err->message);
+					g_clear_error (&tmp_err);
+				} else
+					nmc->editor_save_confirmation = bb;
+			} else if (cmd_arg_p && matches (cmd_arg_p, "prompt-color") == 0) {
+				unsigned long color;
+				if (!nmc_string_to_uint (cmd_arg_v ? g_strstrip (cmd_arg_v) : "X",
+				                         TRUE, 0, 8, &color))
+					printf (_("Error: bad color number: '%s'; use <0-8>\n"),
+					        cmd_arg_v ? cmd_arg_v : "");
+				else {
+					nmc->editor_prompt_color = color;
+					g_free (menu_ctx.main_prompt);
+					if (menu_ctx.level == 0)
+						menu_ctx.main_prompt = nmc_colorize (nmc->editor_prompt_color, BASE_PROMPT);
+					else
+						menu_ctx.main_prompt = nmc_colorize (nmc->editor_prompt_color, "nmcli %s> ",
+						                                     nm_setting_get_name (menu_ctx.curr_setting));
+				}
+			} else if (!cmd_arg_p) {
+				printf (_("Current nmcli configuration:\n"));
+				printf ("status-line: %s\n"
+				        "save-confirmation: %s\n"
+				        "prompt-color: %d\n",
+				        nmc->editor_status_line ? "yes" : "no",
+				        nmc->editor_save_confirmation ? "yes" : "no",
+				        nmc->editor_prompt_color);
+			} else
+				printf (_("Invalid configuration option '%s'; allowed [%s]\n"),
+				        cmd_arg_v ? cmd_arg_v : "", "status-line, save-confirmation, prompt-color");
+
+			break;
+
+		case NMC_EDITOR_MAIN_CMD_QUIT:
+			if (is_connection_dirty (connection, rem_con)) {
+				if (confirm_quit ())
+					cmd_loop = FALSE;  /* quit command loop */
+			} else
+				cmd_loop = FALSE;  /* quit command loop */
+			break;
+
+		case NMC_EDITOR_MAIN_CMD_UNKNOWN:
+		default:
+			printf (_("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 */
+	save_history_cmds (nm_connection_get_uuid (connection));
+
+	return TRUE;
+}
+
+static const char *
+get_ethernet_device_name (NmCli *nmc)
+{
+	const GPtrArray *devices;
+	int i;
+
+	nmc->get_client (nmc);
+	devices = nm_client_get_devices (nmc->client);
+	for (i = 0; devices && (i < devices->len); i++) {
+		NMDevice *dev = g_ptr_array_index (devices, i);
+		if (NM_IS_DEVICE_ETHERNET (dev))
+			return nm_device_get_iface (dev);
+	}
+	return NULL;
+}
+
+static void
+editor_init_new_connection (NmCli *nmc, NMConnection *connection)
+{
+	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);
+	con_type = nm_setting_connection_get_connection_type (s_con);
+
+	/* Initialize new connection according to its type using sensible defaults. */
+
+	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);
+
+		/* For bond/team/bridge slaves add 'wired' setting */
+		setting = nm_setting_wired_new ();
+		nm_connection_add_setting (connection, setting);
+
+		g_object_set (s_con,
+		              NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME,
+		              NM_SETTING_CONNECTION_MASTER, dev_ifname ? dev_ifname : "eth0",
+		              NM_SETTING_CONNECTION_SLAVE_TYPE, slave_type,
+		              NULL);
+	} else {
+		/* Add a "base" setting to the connection by default */
+		base_setting = nmc_setting_new_for_name (con_type);
+		if (!base_setting)
+			return;
+		nm_connection_add_setting (connection, base_setting);
+
+		/* Set a sensible bond/team/bridge interface name by default */
+		if (g_strcmp0 (con_type, NM_SETTING_BOND_SETTING_NAME) == 0)
+			g_object_set (NM_SETTING_BOND (base_setting),
+			              NM_SETTING_BOND_INTERFACE_NAME, "nm-bond",
+			              NULL);
+		if (g_strcmp0 (con_type, NM_SETTING_TEAM_SETTING_NAME) == 0)
+			g_object_set (NM_SETTING_TEAM (base_setting),
+			              NM_SETTING_TEAM_INTERFACE_NAME, "nm-team",
+			              NULL);
+		if (g_strcmp0 (con_type, NM_SETTING_BRIDGE_SETTING_NAME) == 0)
+			g_object_set (NM_SETTING_BRIDGE (base_setting),
+			              NM_SETTING_BRIDGE_INTERFACE_NAME, "nm-bridge",
+			              NULL);
+
+		/* Set sensible initial VLAN values */
+		if (g_strcmp0 (con_type, NM_SETTING_VLAN_SETTING_NAME) == 0) {
+			const char *dev_ifname = get_ethernet_device_name (nmc);
+
+			g_object_set (NM_SETTING_VLAN (base_setting),
+			              NM_SETTING_VLAN_PARENT, dev_ifname ? dev_ifname : "eth0",
+			              NM_SETTING_VLAN_ID, 1,
+			              NULL);
+			g_object_set (s_con,
+			              NM_SETTING_CONNECTION_MASTER, dev_ifname ? dev_ifname : "eth0",
+			              NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_VLAN_SETTING_NAME,
+			              NULL);
+		}
+
+		/* Initialize 'transport-mode' so that 'infiniband' is valid */
+		if (g_strcmp0 (con_type, NM_SETTING_INFINIBAND_SETTING_NAME) == 0)
+			g_object_set (NM_SETTING_INFINIBAND (base_setting),
+			              NM_SETTING_INFINIBAND_TRANSPORT_MODE, "datagram",
+			              NULL);
+
+		/* Initialize 'number' so that 'cdma' is valid */
+		if (g_strcmp0 (con_type, NM_SETTING_CDMA_SETTING_NAME) == 0)
+			g_object_set (NM_SETTING_CDMA (base_setting),
+			              NM_SETTING_CDMA_NUMBER, "#777",
+			              NULL);
+
+		/* Initialize 'number' so that 'gsm' is valid */
+		if (g_strcmp0 (con_type, NM_SETTING_GSM_SETTING_NAME) == 0)
+			g_object_set (NM_SETTING_GSM (base_setting),
+			              NM_SETTING_GSM_NUMBER, "*99#",
+			              NULL);
+
+		/* Wi-Fi */
+		if (g_strcmp0 (con_type, NM_SETTING_WIRELESS_SETTING_NAME) == 0) {
+			/* For Wi-Fi set mode to "infrastructure". Even though mode == NULL
+			 * is regarded as "infrastructure", explicit value makes no doubts.
+			 */
+			g_object_set (NM_SETTING_WIRELESS (base_setting),
+			              NM_SETTING_WIRELESS_MODE, NM_SETTING_WIRELESS_MODE_INFRA,
+			              NULL);
+
+			/* Do custom initialization for wifi setting */
+			nmc_setting_custom_init (base_setting);
+		}
+
+		/* Always add IPv4 and IPv6 settings for non-slave connections */
+		setting = nm_setting_ip4_config_new ();
+		nmc_setting_custom_init (setting);
+		nm_connection_add_setting (connection, setting);
+
+		setting = nm_setting_ip6_config_new ();
+		nmc_setting_custom_init (setting);
+		nm_connection_add_setting (connection, setting);
+	}
+}
+
+static void
+editor_init_existing_connection (NMConnection *connection)
+{
+	NMSettingIP4Config *s_ip4;
+	NMSettingIP6Config *s_ip6;
+	NMSettingWireless *s_wireless;
+
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
+	s_ip6 = nm_connection_get_setting_ip6_config (connection);
+	s_wireless = nm_connection_get_setting_wireless (connection);
+
+	if (s_ip4)
+		nmc_setting_ip4_connect_handlers (s_ip4);
+	if (s_ip6)
+		nmc_setting_ip6_connect_handlers (s_ip6);
+	if (s_wireless)
+		nmc_setting_wireless_connect_handlers (s_wireless);
+}
+
+static NMCResultCode
+do_connection_edit (NmCli *nmc, int argc, char **argv)
+{
+	NMConnection *connection = NULL;
+	NMSettingConnection *s_con;
+	const char *connection_type;
+	char *uuid;
+	char *default_name = NULL;
+	const char *type = NULL;
+	char *type_ask = NULL;
+	const char *con_name = NULL;
+	const char *con = NULL;
+	const char *con_id = NULL;
+	const char *con_uuid = NULL;
+	const char *con_path = NULL;
+	const char *selector = NULL;
+	char *tmp_str;
+	GError *error = NULL;
+	GError *err1 = NULL;
+	nmc_arg_t exp_args[] = { {"type",     TRUE, &type,     FALSE},
+	                         {"con-name", TRUE, &con_name, FALSE},
+	                         {"id",       TRUE, &con_id,   FALSE},
+	                         {"uuid",     TRUE, &con_uuid, FALSE},
+	                         {"path",     TRUE, &con_path, FALSE},
+	                         {NULL} };
+
+	nmc->return_value = NMC_RESULT_SUCCESS;
+
+	if (argc == 1)
+		con = *argv;
+	else {
+		if (!nmc_parse_args (exp_args, TRUE, &argc, &argv, &error)) {
+			g_string_assign (nmc->return_text, error->message);
+			nmc->return_value = error->code;
+			g_clear_error (&error);
+			goto error;
+		}
+	}
+
+	/* Setup some readline completion stuff */
+	/* Set a pointer to an alternative function to create matches */
+	rl_attempted_completion_function = (rl_completion_func_t *) nmcli_editor_tab_completion;
+	/* Use ' ' and '.' as word break characters */
+	rl_completer_word_break_characters = ". ";
+
+	if (!con) {
+		if (con_id && !con_uuid && !con_path) {
+			con = con_id;
+			selector = "id";
+		} else if (con_uuid && !con_id && !con_path) {
+			con = con_uuid;
+			selector = "uuid";
+		} else if (con_path && !con_id && !con_uuid) {
+			con = con_path;
+			selector = "path";
+		} else if (!con_path && !con_id && !con_uuid) {
+			/* no-op */
+		} else {
+			g_string_printf (nmc->return_text,
+			                 _("Error: only one of 'id', uuid, or 'path' can be provided."));
+			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+			goto error;
+		}
+	}
+
+	if (con) {
+		/* Existing connection */
+		NMConnection *found_con;
+
+		found_con = nmc_find_connection (nmc->system_connections, selector, con, NULL);
+		if (!found_con) {
+			g_string_printf (nmc->return_text, _("Error: Unknown connection '%s'."), con);
+			nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
+			goto error;
+		}
+
+		/* Duplicate the connection and use that so that we need not
+		 * differentiate existing vs. new later
+		 */
+		connection = nm_connection_duplicate (found_con);
+
+		s_con = nm_connection_get_setting_connection (connection);
+		g_assert (s_con);
+		connection_type = nm_setting_connection_get_connection_type (s_con);
+
+		if (type)
+			printf (_("Warning: editing existing connection '%s'; 'type' argument is ignored\n"),
+			        nm_connection_get_id (connection));
+		if (con_name)
+			printf (_("Warning: editing existing connection '%s'; 'con-name' argument is ignored\n"),
+			        nm_connection_get_id (connection));
+
+		/* Load previously saved history commands for the connection */
+		load_history_cmds (nm_connection_get_uuid (connection));
+
+		editor_init_existing_connection (connection);
+	} else {
+		/* New connection */
+		connection_type = check_valid_name (type, nmc_valid_connection_types, &err1);
+		tmp_str = get_valid_options_string (nmc_valid_connection_types);
+
+		while (!connection_type) {
+			if (!type)
+				printf (_("Valid connection types: %s\n"), tmp_str);
+			else
+				printf (_("Error: invalid connection type; %s\n"), err1->message);
+			g_clear_error (&err1);
+
+			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, &err1);
+			g_free (type_ask);
 		}
+		g_free (tmp_str);
+
+		/* Create a new connection object */
+		connection = nm_connection_new ();
+
+		/* Build up the 'connection' setting */
+		s_con = (NMSettingConnection *) nm_setting_connection_new ();
+		uuid = nm_utils_uuid_generate ();
+		if (con_name)
+			default_name = g_strdup (con_name);
+		else
+			default_name = unique_connection_name (nmc->system_connections,
+			                                       get_name_alias (connection_type, nmc_valid_connection_types));
+
+		g_object_set (s_con,
+		              NM_SETTING_CONNECTION_ID, default_name,
+		              NM_SETTING_CONNECTION_UUID, uuid,
+		              NM_SETTING_CONNECTION_TYPE, connection_type,
+		              NULL);
+		g_free (uuid);
+		g_free (default_name);
+		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);
 	}
 
-	if (active)
-		nm_client_deactivate_connection (nmc->client, active);
+	printf ("\n");
+	printf (_("===| nmcli interactive connection editor |==="));
+	printf ("\n\n");
+	if (con)
+		printf (_("Editing existing '%s' connection: '%s'"), connection_type, con);
 	else
-		fprintf (stderr, _("Warning: Connection not active\n"));
-	sleep (1);  /* Don't quit immediatelly and give NM time to check our permissions */
+		printf (_("Adding a new '%s' connection"), connection_type);
+	printf ("\n\n");
+	printf (_("Type 'help' or '?' for available commands."));
+	printf ("\n");
+	printf (_("Type 'describe [<setting>.<prop>]' for detailed property description."));
+	printf ("\n\n");
+
+	/* Set global variables for use in TAB completion */
+	nmc_tab_completion.nmc = nmc;
+	nmc_tab_completion.con_type = g_strdup (connection_type);
+	nmc_tab_completion.connection = connection;
+
+	/* Run menu loop */
+	editor_menu_main (nmc, connection, connection_type);
+
+	if (connection)
+		g_object_unref (connection);
+	g_free (nmc_tab_completion.con_type);
+
+	nmc->should_wait = TRUE;
+	return nmc->return_value;
 
 error:
+	g_assert (!connection);
+	g_free (type_ask);
+
 	nmc->should_wait = FALSE;
 	return nmc->return_value;
 }
 
+
 static void
-delete_cb (NMRemoteConnection *con, GError *err, gpointer user_data)
+modify_connection_cb (NMRemoteConnection *connection,
+                      GError *error,
+                      gpointer user_data)
 {
 	NmCli *nmc = (NmCli *) user_data;
 
-	if (err) {
-		g_string_printf (nmc->return_text, _("Error: Connection deletion failed: %s"), err->message);
-		nmc->return_value = NMC_RESULT_ERROR_CON_DEL;
+        if (error) {
+		g_string_printf (nmc->return_text,
+		                 _("Error: Failed to modify connection '%s': (%d) %s"),
+		                 nm_connection_get_id (NM_CONNECTION (connection)),
+		                 error->code, error->message);
+		nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+	} else {
+		if (nmc->print_output == NMC_PRINT_PRETTY)
+			printf (_("Connection '%s' (%s) successfully modified.\n"),
+		                nm_connection_get_id (NM_CONNECTION (connection)),
+		                nm_connection_get_uuid (NM_CONNECTION (connection)));
 	}
 	quit ();
 }
 
+static NMCResultCode
+do_connection_modify (NmCli *nmc,
+                      gboolean temporary,
+                      int argc,
+                      char **argv)
+{
+	NMConnection *connection = NULL;
+	NMRemoteConnection *rc = NULL;
+	NMSetting *setting;
+	NMSettingConnection *s_con;
+	const char *con_type;
+	const char *name;
+	const char *selector = NULL;
+	const char *s_dot_p;
+	const char *value;
+	char **strv = NULL;
+	const char *setting_name;
+	char *property_name = NULL;
+	gboolean append = FALSE;
+	gboolean remove = FALSE;
+	GError *error = NULL;
+
+	nmc->should_wait = FALSE;
+
+	/* create NMClient */
+	nmc->get_client (nmc);
+
+	if (!nm_client_get_manager_running (nmc->client)) {
+		g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
+		nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
+		goto finish;
+	}
+
+	if (argc == 0) {
+		g_string_printf (nmc->return_text, _("Error: No arguments provided."));
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		goto finish;
+	}
+	if (   strcmp (*argv, "id") == 0
+	    || strcmp (*argv, "uuid") == 0
+	    || strcmp (*argv, "path") == 0) {
+
+		selector = *argv;
+		if (next_arg (&argc, &argv) != 0) {
+			g_string_printf (nmc->return_text, _("Error: %s argument is missing."),
+			                 selector);
+			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+			goto finish;
+		}
+		name = *argv;
+	}
+	name = *argv;
+	if (!name) {
+		g_string_printf (nmc->return_text, _("Error: connection ID is missing."));
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		goto finish;
+	}
+	connection = nmc_find_connection (nmc->system_connections, selector, name, NULL);
+	if (!connection) {
+		g_string_printf (nmc->return_text, _("Error: Unknown connection '%s'."), name);
+		nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
+		goto finish;
+	}
+	rc = nm_remote_settings_get_connection_by_uuid (nmc->system_settings,
+	                                                nm_connection_get_uuid (connection));
+	if (!rc) {
+		g_string_printf (nmc->return_text, _("Error: Unknown connection '%s'."), name);
+		nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
+		goto finish;
+	}
+	s_con = nm_connection_get_setting_connection (NM_CONNECTION (rc));
+	g_assert (s_con);
+	con_type = nm_setting_connection_get_connection_type (s_con);
+
+	if (next_arg (&argc, &argv) != 0) {
+		g_string_printf (nmc->return_text, _("Error: <setting>.<property> argument is missing."));
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		goto finish;
+	}
+
+	/* Go through arguments and set properties */
+	while (argc) {
+		s_dot_p = *argv;
+		next_arg (&argc, &argv);
+		value = *argv;
+		next_arg (&argc, &argv);
+
+		if (!s_dot_p) {
+			g_string_printf (nmc->return_text, _("Error: <setting>.<property> argument is missing."));
+			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+			goto finish;
+		}
+		if (!value) {
+			g_string_printf (nmc->return_text, _("Error: value for '%s' is missing."), s_dot_p);
+			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+			goto finish;
+		}
+		/* Empty string will reset the value to default */
+		if (value[0] == '\0')
+			value = NULL;
+
+		if (s_dot_p[0] == '+') {
+			s_dot_p++;
+			append = TRUE;
+		} else if (s_dot_p[0] == '-') {
+			s_dot_p++;
+			remove = TRUE;
+		}
+
+		strv = g_strsplit (s_dot_p, ".", 2);
+		if (g_strv_length (strv) != 2) {
+			g_string_printf (nmc->return_text, _("Error: invalid <setting>.<property> '%s'."),
+			                 s_dot_p);
+			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+			goto finish;
+		}
+
+		setting_name = check_valid_name (strv[0], get_valid_settings_array (con_type), &error);
+		if (!setting_name) {
+			g_string_printf (nmc->return_text, _("Error: invalid or not allowed setting '%s': %s."),
+			                 strv[0], error->message);
+			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+			goto finish;
+		}
+		setting = nm_connection_get_setting_by_name (NM_CONNECTION (rc), setting_name);
+		if (!setting) {
+			setting = nmc_setting_new_for_name (setting_name);
+			if (!setting) {
+				/* This should really not happen */
+				g_string_printf (nmc->return_text,
+				                 "Error: don't know how to create '%s' setting.",
+				                  setting_name);
+				nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+				goto finish;
+			}
+			nm_connection_add_setting (NM_CONNECTION (rc), setting);
+		}
+
+		property_name = is_property_valid (setting, strv[1], &error);
+		if (!property_name) {
+			g_string_printf (nmc->return_text, _("Error: invalid property '%s': %s."),
+			                 strv[1], error->message);
+			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+			goto finish;
+		}
+
+		if (!remove) {
+			/* Set/add value */
+			if (!append)
+				nmc_setting_reset_property (setting, property_name, NULL);
+			if (!nmc_setting_set_property (setting, property_name, value, &error)) {
+				g_string_printf (nmc->return_text, _("Error: failed to modify %s.%s: %s."),
+				                 strv[0], strv[1], error->message);
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				goto finish;
+			}
+		} else {
+			/* Remove value
+			 * - either empty: remove whole value
+			 * - or specified by index <0-n>: remove item at the index
+			 * - or option name: remove item with the option name
+			 */
+			if (value) {
+				unsigned long idx;
+				if (nmc_string_to_uint (value, TRUE, 0, G_MAXUINT32, &idx))
+					nmc_setting_remove_property_option (setting, property_name, NULL, idx, &error);
+				else
+					nmc_setting_remove_property_option (setting, property_name, value, 0, &error);
+				if (error) {
+					g_string_printf (nmc->return_text, _("Error: failed to remove a value from %s.%s: %s."),
+					                 strv[0], strv[1], error->message);
+					nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+					goto finish;
+				}
+			} else
+				nmc_setting_reset_property (setting, property_name, NULL);
+		}
+
+		g_strfreev (strv);
+		strv = NULL;
+	}
+
+	update_connection (!temporary, rc, modify_connection_cb, nmc);
+
+finish:
+	nmc->should_wait = (nmc->return_value == NMC_RESULT_SUCCESS);
+	g_free (property_name);
+	if (strv)
+		g_strfreev (strv);
+	g_clear_error (&error);
+	return nmc->return_value;
+}
+
+
+typedef struct {
+	NmCli *nmc;
+	int counter;
+} DeleteStateInfo;
+
 static void
-connection_removed_cb (NMRemoteConnection *con, gpointer user_data)
+delete_cb (NMRemoteConnection *con, GError *err, gpointer user_data)
 {
-	NmCli *nmc = (NmCli *) user_data;
+	DeleteStateInfo *info = (DeleteStateInfo *) user_data;
 
-	nmc->return_value = NMC_RESULT_SUCCESS;
-	quit ();
+	if (err) {
+		g_string_printf (info->nmc->return_text, _("Error: Connection deletion failed: %s"), err->message);
+		info->nmc->return_value = NMC_RESULT_ERROR_CON_DEL;
+	}
+
+	info->counter--;
+	if (info->counter == 0) {
+		g_free (info);
+		quit ();
+	}
 }
 
 static NMCResultCode
 do_connection_delete (NmCli *nmc, int argc, char **argv)
 {
 	NMConnection *connection = NULL;
-	const char *selector = NULL;
-	const char *id = NULL;
-	GError *error = NULL;
+	DeleteStateInfo *del_info = NULL;
+	char *line = NULL;
+	char **arg_arr = NULL;
+	char **arg_ptr = argv;
+	int arg_num = argc;
+	GString *invalid_cons = NULL;
+	gboolean del_info_free = FALSE;
+	GSList *pos = NULL;
 
-	while (argc > 0) {
-		if (strcmp (*argv, "id") == 0 || strcmp (*argv, "uuid") == 0) {
-			selector = *argv;
-			if (next_arg (&argc, &argv) != 0) {
-				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
+	nmc->return_value = NMC_RESULT_SUCCESS;
+	nmc->should_wait = FALSE;
+
+	/* create NMClient */
+	nmc->get_client (nmc);
+
+	if (!nm_client_get_manager_running (nmc->client)) {
+		g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
+		nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
+		goto finish;
+	}
+
+	if (argc == 0) {
+		if (nmc->ask) {
+			line = nmc_readline (PROMPT_CONNECTION);
+			nmc_string_to_arg_array (line, "", &arg_arr, &arg_num);
+			arg_ptr = arg_arr;
+		}
+		if (arg_num == 0) {
+			g_string_printf (nmc->return_text, _("Error: No connection specified."));
+			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+			goto finish;
+		}
+	}
+
+	del_info = g_malloc0 (sizeof (DeleteStateInfo));
+	del_info->nmc = nmc;
+	del_info->counter = 0;
+	del_info_free = TRUE;
+
+	while (arg_num > 0) {
+		const char *selector = NULL;
+
+		if (   strcmp (*arg_ptr, "id") == 0
+		    || strcmp (*arg_ptr, "uuid") == 0
+		    || strcmp (*arg_ptr, "path") == 0) {
+			selector = *arg_ptr;
+			if (next_arg (&arg_num, &arg_ptr) != 0) {
+				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), selector);
 				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-				goto error;
+				goto finish;
 			}
-			id = *argv;
 		}
-		else
-			fprintf (stderr, _("Unknown parameter: %s\n"), *argv);
 
-		argc--;
-		argv++;
+		connection = nmc_find_connection (nmc->system_connections, selector, *arg_ptr, &pos);
+		if (!connection) {
+			if (nmc->print_output != NMC_PRINT_TERSE)
+				printf (_("Error: unknown connection: %s\n"), *arg_ptr);
+
+			if (!invalid_cons)
+				invalid_cons = g_string_new (NULL);
+			g_string_append_printf (invalid_cons, "'%s', ", *arg_ptr);
+
+			/* take the next argument and continue */
+			next_arg (&arg_num, &arg_ptr);
+			continue;
+		}
+
+		/* We need to wait a bit so that nmcli's permissions can be checked.
+		 * We will exit when D-Bus return (error) messages are received.
+		 */
+		nmc->should_wait = TRUE;
+
+		/* del_info deallocation is handled in delete_cb() */
+		del_info_free = FALSE;
+
+		del_info->counter++;
+
+		/* Delete the connection */
+		nm_remote_connection_delete (NM_REMOTE_CONNECTION (connection), delete_cb, del_info);
+
+		/* Take next argument (if there's no other connection of the same name) */
+		if (!pos)
+			next_arg (&arg_num, &arg_ptr);
 	}
 
-	if (!id) {
-		g_string_printf (nmc->return_text, _("Error: id or uuid has to be specified."));
-		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-		goto error;
+finish:
+	if (del_info_free)
+		g_free (del_info);
+	g_strfreev (arg_arr);
+
+	if (invalid_cons) {
+		g_string_truncate (invalid_cons, invalid_cons->len-2);  /* truncate trailing ", " */
+		g_string_printf (nmc->return_text, _("Error: cannot delete unknown connection(s): %s."),
+		                 invalid_cons->str);
+		nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
+		g_string_free (invalid_cons, TRUE);
 	}
+	return nmc->return_value;
+}
 
-	if (!nmc_is_nm_running (nmc, &error)) {
-		if (error) {
-			g_string_printf (nmc->return_text, _("Error: Can't find out if NetworkManager is running: %s."), error->message);
-			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
-			g_error_free (error);
-		} else {
-			g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
+static NMCResultCode
+do_connection_reload (NmCli *nmc, int argc, char **argv)
+{
+	GError *error = NULL;
+
+	nmc->return_value = NMC_RESULT_SUCCESS;
+	nmc->should_wait = FALSE;
+
+	if (!nm_client_get_manager_running (nmc->client)) {
+		g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
+		nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
+		return nmc->return_value;
+	}
+
+	if (!nm_remote_settings_reload_connections (nmc->system_settings, &error)) {
+		g_string_printf (nmc->return_text, _("Error: %s."), error->message);
+		if (error->code == NM_REMOTE_SETTINGS_ERROR_SERVICE_UNAVAILABLE)
 			nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
-		}
-		goto error;
+		else
+			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+		g_clear_error (&error);
 	}
 
-	connection = find_connection (nmc->system_connections, selector, id);
+	return nmc->return_value;
+}
 
-	if (!connection) {
-		g_string_printf (nmc->return_text, _("Error: Unknown connection: %s."), id);
-		nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
-		goto error;
+static NMCResultCode
+do_connection_load (NmCli *nmc, int argc, char **argv)
+{
+	GError *error = NULL;
+	char **filenames, **failures = NULL;
+	int i;
+
+	nmc->return_value = NMC_RESULT_SUCCESS;
+	nmc->should_wait = FALSE;
+
+	if (!nm_client_get_manager_running (nmc->client)) {
+		g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
+		nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
+		return nmc->return_value;
 	}
 
-	/* We need to wait a bit so that nmcli's permissions can be queried.
-	 * We will exit either on "Removed" signal or when D-Bus return (error)
-	 * message is received.
-	 */
-	nmc->should_wait = TRUE;
+	if (argc == 0) {
+		g_string_printf (nmc->return_text, _("Error: No connection specified."));
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		return nmc->return_value;
+	}
 
-	/* Connect to "Removed" signal to be able to exit when connection was removed */
-	g_signal_connect (connection, NM_REMOTE_CONNECTION_REMOVED, G_CALLBACK (connection_removed_cb), nmc);
+	filenames = g_new (char *, argc + 1);
+	for (i = 0; i < argc; i++)
+		filenames[i] = argv[i];
+	filenames[i] = NULL;
 
-	/* Delete the connection */
-	nm_remote_connection_delete (NM_REMOTE_CONNECTION (connection), delete_cb, nmc);
+	nm_remote_settings_load_connections (nmc->system_settings, filenames, &failures, &error);
+	g_free (filenames);
+	if (error) {
+		g_string_printf (nmc->return_text, _("Error: %s."), error->message);
+		nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+		g_error_free (error);
+	}
 
-	return nmc->return_value;
+	if (failures) {
+		for (i = 0; failures[i]; i++)
+			fprintf (stderr, _("Could not load file '%s'\n"), failures[i]);
+		g_strfreev (failures);
+	}
 
-error:
-	nmc->should_wait = FALSE;
 	return nmc->return_value;
 }
 
+
+typedef struct {
+	NmCli *nmc;
+	int argc;
+	char **argv;
+} NmcEditorThreadData;
+
+static GThread *editor_thread;
+static NmcEditorThreadData editor_thread_data;
+
+/*
+ * We need to run do_connection_edit() in a thread so that
+ * glib main loop is not blocked and could receive and process D-Bus
+ * return messages.
+ */
+static gpointer
+connection_editor_thread_func (gpointer data)
+{
+	NmcEditorThreadData *td = (NmcEditorThreadData *) data;
+
+	/* run editor for editing/adding connections */
+	td->nmc->return_value = do_connection_edit (td->nmc, td->argc, td->argv);
+
+	/* quit glib main loop now that we are done with this thread */
+	quit ();
+
+	return NULL;
+}
+
+static char *
+gen_func_connection_names (const char *text, int state)
+{
+	int i = 0;
+	GSList *iter;
+	const char **connections;
+	char *ret;
+
+	if (!nm_cli.system_connections)
+		return NULL;
+
+	connections = g_new (const char *, g_slist_length (nm_cli.system_connections) + 1);
+	for (iter = nm_cli.system_connections; iter; iter = g_slist_next (iter)) {
+		NMConnection *con = NM_CONNECTION (iter->data);
+		const char *id = nm_connection_get_id (con);
+		connections[i++] = id;
+	}
+	connections[i] = NULL;
+
+	ret = nmc_rl_gen_func_basic (text, state, connections);
+
+	g_free (connections);
+	return ret;
+}
+
+static char **
+nmcli_con_tab_completion (const char *text, int start, int end)
+{
+	char **match_array = NULL;
+	rl_compentry_func_t *generator_func = NULL;
+
+	/* Disable readline's default filename completion */
+	rl_attempted_completion_over = 1;
+
+	/* Disable appending space after completion */
+	rl_completion_append_character = '\0';
+
+	if (!is_single_word (rl_line_buffer))
+		return NULL;
+
+	if (g_strcmp0 (rl_prompt, PROMPT_CONNECTION) == 0)
+		generator_func = gen_func_connection_names;
+
+	if (generator_func)
+		match_array = rl_completion_matches (text, generator_func);
+
+	return match_array;
+}
+
 static NMCResultCode
 parse_cmd (NmCli *nmc, int argc, char **argv)
 {
 	GError *error = NULL;
 
+	rl_attempted_completion_function = (rl_completion_func_t *) nmcli_con_tab_completion;
+
 	if (argc == 0) {
 		if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error))
 			goto opt_error;
-		nmc->return_value = do_connections_list (nmc, argc, argv);
+		nmc->return_value = do_connections_show (nmc, FALSE, argc, argv);
 	} else {
-
-		if (matches (*argv, "list") == 0) {
-			nmc->return_value = do_connections_list (nmc, argc-1, argv+1);
+		if (nmc_arg_is_help (*argv)) {
+			usage ();
+			goto usage_exit;
 		}
-		else if (matches(*argv, "status") == 0) {
-			if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error))
-				goto opt_error;
-			nmc->return_value = do_connections_status (nmc, argc-1, argv+1);
+		else if (matches (*argv, "show") == 0) {
+			gboolean active = FALSE;
+
+			if (nmc_arg_is_help (*(argv+1))) {
+				usage_connection_show ();
+				goto usage_exit;
+			}
+
+			next_arg (&argc, &argv);
+			if (nmc_arg_is_option (*argv, "active")) {
+				active = TRUE;
+				next_arg (&argc, &argv);
+			}
+			nmc->return_value = do_connections_show (nmc, active, argc, argv);
 		}
 		else if (matches(*argv, "up") == 0) {
+			if (nmc_arg_is_help (*(argv+1))) {
+				usage_connection_up ();
+				goto usage_exit;
+			}
 			nmc->return_value = do_connection_up (nmc, argc-1, argv+1);
 		}
 		else if (matches(*argv, "down") == 0) {
+			if (nmc_arg_is_help (*(argv+1))) {
+				usage_connection_down ();
+				goto usage_exit;
+			}
 			nmc->return_value = do_connection_down (nmc, argc-1, argv+1);
 		}
+		else if (matches(*argv, "add") == 0) {
+			if (nmc_arg_is_help (*(argv+1))) {
+				usage_connection_add ();
+				goto usage_exit;
+			}
+			nmc->return_value = do_connection_add (nmc, argc-1, argv+1);
+		}
+		else if (matches(*argv, "edit") == 0) {
+			if (nmc_arg_is_help (*(argv+1))) {
+				usage_connection_edit ();
+				goto usage_exit;
+			}
+			editor_thread_data.nmc = nmc;
+			editor_thread_data.argc = argc - 1;
+			editor_thread_data.argv = argv + 1;
+			editor_thread = g_thread_new ("editor-thread", connection_editor_thread_func, &editor_thread_data);
+			g_thread_unref (editor_thread);
+		}
 		else if (matches(*argv, "delete") == 0) {
+			if (nmc_arg_is_help (*(argv+1))) {
+				usage_connection_delete ();
+				goto usage_exit;
+			}
 			nmc->return_value = do_connection_delete (nmc, argc-1, argv+1);
 		}
-		else if (   matches (*argv, "help") == 0
-		         || (g_str_has_prefix (*argv, "-")  && matches ((*argv)+1, "help") == 0)
-		         || (g_str_has_prefix (*argv, "--") && matches ((*argv)+2, "help") == 0)) {
-			usage ();
-			nmc->should_wait = FALSE;
+		else if (matches(*argv, "reload") == 0) {
+			if (nmc_arg_is_help (*(argv+1))) {
+				usage_connection_reload ();
+				goto usage_exit;
+			}
+			nmc->return_value = do_connection_reload (nmc, argc-1, argv+1);
+		}
+		else if (matches(*argv, "load") == 0) {
+			if (nmc_arg_is_help (*(argv+1))) {
+				usage_connection_load ();
+				goto usage_exit;
+			}
+			nmc->return_value = do_connection_load (nmc, argc-1, argv+1);
+		}
+		else if (matches (*argv, "modify") == 0) {
+			gboolean temporary = FALSE;
+
+			if (nmc_arg_is_help (*(argv+1))) {
+				usage_connection_modify ();
+				goto usage_exit;
+			}
+			next_arg (&argc, &argv);
+			if (nmc_arg_is_option (*argv, "temporary")) {
+				temporary = TRUE;
+				next_arg (&argc, &argv);
+			}
+			nmc->return_value = do_connection_modify (nmc, temporary, argc, argv);
 		}
 		else {
 			usage ();
-			g_string_printf (nmc->return_text, _("Error: 'con' command '%s' is not valid."), *argv);
+			g_string_printf (nmc->return_text, _("Error: '%s' is not valid 'connection' command."), *argv);
 			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
 			nmc->should_wait = FALSE;
 		}
@@ -1842,6 +8617,10 @@ parse_cmd (NmCli *nmc, int argc, char **argv)
 
 	return nmc->return_value;
 
+usage_exit:
+	nmc->should_wait = FALSE;
+	return nmc->return_value;
+
 opt_error:
 	g_string_printf (nmc->return_text, _("Error: %s."), error->message);
 	nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
@@ -1869,8 +8648,6 @@ get_connections_cb (NMRemoteSettings *settings, gpointer user_data)
 NMCResultCode
 do_connections (NmCli *nmc, int argc, char **argv)
 {
-	DBusGConnection *bus;
-	GError *error = NULL;
 	int i = 0;
 	gboolean real_cmd = FALSE;
 
@@ -1899,17 +8676,8 @@ do_connections (NmCli *nmc, int argc, char **argv)
 		args_info.argc = argc;
 		args_info.argv = argv;
 
-		/* connect to DBus' system bus */
-		bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
-		if (error || !bus) {
-			g_string_printf (nmc->return_text, _("Error: could not connect to D-Bus."));
-			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
-			nmc->should_wait = FALSE;
-			return nmc->return_value;
-		}
-
 		/* get system settings */
-		if (!(nmc->system_settings = nm_remote_settings_new (bus))) {
+		if (!(nmc->system_settings = nm_remote_settings_new (NULL))) {
 			g_string_printf (nmc->return_text, _("Error: Could not get system settings."));
 			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
 			nmc->should_wait = FALSE;
@@ -1930,9 +8698,6 @@ do_connections (NmCli *nmc, int argc, char **argv)
 		g_signal_connect (nmc->system_settings, NM_REMOTE_SETTINGS_CONNECTIONS_READ,
 				  G_CALLBACK (get_connections_cb), &args_info);
 
-
-		dbus_g_connection_unref (bus);
-
 		/* The rest will be done in get_connection_cb() callback.
 		 * We need to wait for signals that connections are read.
 		 */
diff --git a/cli/src/connections.h b/cli/src/connections.h
index a1ed1c1c..c7368597 100644
--- a/cli/src/connections.h
+++ b/cli/src/connections.h
@@ -14,7 +14,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * (C) Copyright 2010 Red Hat, Inc.
+ * (C) Copyright 2010 - 2014 Red Hat, Inc.
  */
 
 #ifndef NMC_CONNECTIONS_H
diff --git a/cli/src/devices.c b/cli/src/devices.c
index ffad9801..17492066 100644
--- a/cli/src/devices.c
+++ b/cli/src/devices.c
@@ -14,7 +14,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * (C) Copyright 2010 - 2012 Red Hat, Inc.
+ * (C) Copyright 2010 - 2014 Red Hat, Inc.
  */
 
 #include "config.h"
@@ -24,6 +24,7 @@
 #include <stdlib.h>
 #include <errno.h>
 #include <netinet/ether.h>
+#include <readline/readline.h>
 
 #include <glib.h>
 #include <glib/gi18n.h>
@@ -65,185 +66,203 @@
 #include "common.h"
 #include "devices.h"
 
+/* define some prompts */
+#define PROMPT_INTERFACE _("Interface: ")
 
-/* Available fields for 'dev status' */
+/* Available fields for 'device status' */
 static NmcOutputField nmc_fields_dev_status[] = {
-	{"DEVICE",    N_("DEVICE"),      10, NULL, 0},  /* 0 */
-	{"TYPE",      N_("TYPE"),        17, NULL, 0},  /* 1 */
-	{"STATE",     N_("STATE"),       13, NULL, 0},  /* 2 */
-	{"DBUS-PATH", N_("DBUS-PATH"),   43, NULL, 0},  /* 3 */
-	{NULL,        NULL,               0, NULL, 0}
+	{"DEVICE",     N_("DEVICE"),     10},  /* 0 */
+	{"TYPE",       N_("TYPE"),       17},  /* 1 */
+	{"STATE",      N_("STATE"),      13},  /* 2 */
+	{"DBUS-PATH",  N_("DBUS-PATH"),  43},  /* 3 */
+	{"CONNECTION", N_("CONNECTION"), 20},  /* 4 */
+	{"CON-UUID",   N_("CON-UUID"),   38},  /* 5 */
+	{"CON-PATH",   N_("CON-PATH"),   51},  /* 6 */
+	{NULL,         NULL,              0}
 };
-#define NMC_FIELDS_DEV_STATUS_ALL     "DEVICE,TYPE,STATE,DBUS-PATH"
-#define NMC_FIELDS_DEV_STATUS_COMMON  "DEVICE,TYPE,STATE"
-
-
-/* Available sections for 'dev list' */
-static NmcOutputField nmc_fields_dev_list_sections[] = {
-	{"GENERAL",           N_("GENERAL"),           0, NULL, 0},  /* 0 */
-	{"CAPABILITIES",      N_("CAPABILITIES"),      0, NULL, 0},  /* 1 */
-	{"WIFI-PROPERTIES",   N_("WIFI-PROPERTIES"),   0, NULL, 0},  /* 2 */
-	{"AP",                N_("AP"),                0, NULL, 0},  /* 3 */
-	{"WIRED-PROPERTIES",  N_("WIRED-PROPERTIES"),  0, NULL, 0},  /* 4 */
-	{"WIMAX-PROPERTIES",  N_("WIMAX-PROPERTIES"),  0, NULL, 0},  /* 5 */
-	{"NSP",               N_("NSP"),               0, NULL, 0},  /* 6 */
-	{"IP4",               N_("IP4"),               0, NULL, 0},  /* 7 */
-	{"DHCP4",             N_("DHCP4"),             0, NULL, 0},  /* 8 */
-	{"IP6",               N_("IP6"),               0, NULL, 0},  /* 9 */
-	{"DHCP6",             N_("DHCP6"),             0, NULL, 0},  /* 10 */
-	{"BOND",              N_("BOND"),              0, NULL, 0},  /* 11 */
-	{"VLAN",              N_("VLAN"),              0, NULL, 0},  /* 12 */
-	{"CONNECTIONS",       N_("CONNECTIONS"),       0, NULL, 0},  /* 13 */
-	{NULL,                NULL,                    0, NULL, 0}
+#define NMC_FIELDS_DEV_STATUS_ALL     "DEVICE,TYPE,STATE,DBUS-PATH,CONNECTION,CON-UUID,CON-PATH"
+#define NMC_FIELDS_DEV_STATUS_COMMON  "DEVICE,TYPE,STATE,CONNECTION"
+
+
+/* Available fields for 'device show' - GENERAL part */
+static NmcOutputField nmc_fields_dev_show_general[] = {
+	{"NAME",              N_("NAME"),              10},  /* 0 */
+	{"DEVICE",            N_("DEVICE"),            10},  /* 1 */
+	{"TYPE",              N_("TYPE"),              17},  /* 2 */
+	{"VENDOR",            N_("VENDOR"),            20},  /* 3 */
+	{"PRODUCT",           N_("PRODUCT"),           50},  /* 4 */
+	{"DRIVER",            N_("DRIVER"),             9},  /* 5 */
+	{"DRIVER-VERSION",    N_("DRIVER-VERSION"),    18},  /* 6 */
+	{"FIRMWARE-VERSION",  N_("FIRMWARE-VERSION"),  18},  /* 7 */
+	{"HWADDR",            N_("HWADDR"),            19},  /* 8 */
+	{"MTU",               N_("MTU"),               10},  /* 9 */
+	{"STATE",             N_("STATE"),             14},  /* 10 */
+	{"REASON",            N_("REASON"),            25},  /* 11 */
+	{"UDI",               N_("UDI"),               64},  /* 12 */
+	{"IP-IFACE",          N_("IP-IFACE"),          10},  /* 13 */
+	{"NM-MANAGED",        N_("NM-MANAGED"),        15},  /* 14 */
+	{"AUTOCONNECT",       N_("AUTOCONNECT"),       15},  /* 15 */
+	{"FIRMWARE-MISSING",  N_("FIRMWARE-MISSING"),  18},  /* 16 */
+	{"CONNECTION",        N_("CONNECTION"),        20},  /* 17 */
+	{"CON-UUID",          N_("CON-UUID"),          38},  /* 18 */
+	{"CON-PATH",          N_("CON-PATH"),          51},  /* 19 */
+	{NULL, NULL, 0}
 };
-#if WITH_WIMAX
-#define NMC_FIELDS_DEV_LIST_SECTIONS_ALL     "GENERAL,CAPABILITIES,BOND,VLAN,CONNECTIONS,WIFI-PROPERTIES,AP,WIRED-PROPERTIES,WIMAX-PROPERTIES,NSP,IP4,DHCP4,IP6,DHCP6"
-#define NMC_FIELDS_DEV_LIST_SECTIONS_COMMON  "GENERAL,CAPABILITIES,BOND,VLAN,CONNECTIONS,WIFI-PROPERTIES,AP,WIRED-PROPERTIES,WIMAX-PROPERTIES,NSP,IP4,DHCP4,IP6,DHCP6"
-#else
-#define NMC_FIELDS_DEV_LIST_SECTIONS_ALL     "GENERAL,CAPABILITIES,BOND,VLAN,CONNECTIONS,WIFI-PROPERTIES,AP,WIRED-PROPERTIES,IP4,DHCP4,IP6,DHCP6"
-#define NMC_FIELDS_DEV_LIST_SECTIONS_COMMON  "GENERAL,CAPABILITIES,BOND,VLAN,CONNECTIONS,WIFI-PROPERTIES,AP,WIRED-PROPERTIES,IP4,DHCP4,IP6,DHCP6"
-#endif
-
-/* Available fields for 'dev list' - GENERAL part */
-static NmcOutputField nmc_fields_dev_list_general[] = {
-	{"NAME",              N_("NAME"),              10, NULL, 0},  /* 0 */
-	{"DEVICE",            N_("DEVICE"),            10, NULL, 0},  /* 1 */
-	{"TYPE",              N_("TYPE"),              17, NULL, 0},  /* 2 */
-	{"VENDOR",            N_("VENDOR"),            20, NULL, 0},  /* 3 */
-	{"PRODUCT",           N_("PRODUCT"),           50, NULL, 0},  /* 4 */
-	{"DRIVER",            N_("DRIVER"),             9, NULL, 0},  /* 5 */
-	{"DRIVER-VERSION",    N_("DRIVER-VERSION"),    18, NULL, 0},  /* 6 */
-	{"FIRMWARE-VERSION",  N_("FIRMWARE-VERSION"),  18, NULL, 0},  /* 7 */
-	{"HWADDR",            N_("HWADDR"),            19, NULL, 0},  /* 8 */
-	{"STATE",             N_("STATE"),             14, NULL, 0},  /* 9 */
-	{"REASON",            N_("REASON"),            25, NULL, 0},  /* 10 */
-	{"UDI",               N_("UDI"),               64, NULL, 0},  /* 11 */
-	{"IP-IFACE",          N_("IP-IFACE"),          10, NULL, 0},  /* 12 */
-	{"NM-MANAGED",        N_("NM-MANAGED"),        15, NULL, 0},  /* 13 */
-	{"AUTOCONNECT",       N_("AUTOCONNECT"),       15, NULL, 0},  /* 14 */
-	{"FIRMWARE-MISSING",  N_("FIRMWARE-MISSING"),  18, NULL, 0},  /* 15 */
-	{"CONNECTION",        N_("CONNECTION"),        51, NULL, 0},  /* 16 */
-	{NULL, NULL, 0, NULL, 0}
+#define NMC_FIELDS_DEV_SHOW_GENERAL_ALL     "NAME,DEVICE,TYPE,VENDOR,PRODUCT,DRIVER,DRIVER-VERSION,FIRMWARE-VERSION,HWADDR,MTU,STATE,REASON,"\
+                                            "UDI,IP-IFACE,NM-MANAGED,AUTOCONNECT,FIRMWARE-MISSING,CONNECTION,CON-UUID,CON-PATH"
+#define NMC_FIELDS_DEV_SHOW_GENERAL_COMMON  "NAME,DEVICE,TYPE,VENDOR,PRODUCT,DRIVER,HWADDR,STATE"
+
+/* Available fields for 'device show' - CONNECTIONS part */
+static NmcOutputField nmc_fields_dev_show_connections[] = {
+	{"NAME",                       N_("NAME"),                       10},  /* 0 */
+	{"AVAILABLE-CONNECTION-PATHS", N_("AVAILABLE-CONNECTION-PATHS"), 80},  /* 1 */
+	{"AVAILABLE-CONNECTIONS",      N_("AVAILABLE-CONNECTIONS"),      80},  /* 2 */
+	{NULL, NULL, 0}
 };
-#define NMC_FIELDS_DEV_LIST_GENERAL_ALL     "NAME,DEVICE,TYPE,VENDOR,PRODUCT,DRIVER,DRIVER-VERSION,FIRMWARE-VERSION,HWADDR,STATE,REASON,UDI,IP-IFACE,"\
-                                            "NM-MANAGED,AUTOCONNECT,FIRMWARE-MISSING,CONNECTION"
-#define NMC_FIELDS_DEV_LIST_GENERAL_COMMON  "NAME,DEVICE,TYPE,VENDOR,PRODUCT,DRIVER,HWADDR,STATE"
-
-/* Available fields for 'dev list' - CONNECTIONS part */
-static NmcOutputField nmc_fields_dev_list_connections[] = {
-	{"NAME",                       N_("NAME"),                       10, NULL, 0},  /* 0 */
-	{"AVAILABLE-CONNECTION-PATHS", N_("AVAILABLE-CONNECTION-PATHS"), 80, NULL, 0},  /* 1 */
-	{"AVAILABLE-CONNECTIONS",      N_("AVAILABLE-CONNECTIONS"),      80, NULL, 0},  /* 2 */
-	{NULL, NULL, 0, NULL, 0}
+#define NMC_FIELDS_DEV_SHOW_CONNECTIONS_ALL     "AVAILABLE-CONNECTION-PATHS,AVAILABLE-CONNECTIONS"
+#define NMC_FIELDS_DEV_SHOW_CONNECTIONS_COMMON  "AVAILABLE-CONNECTION-PATHS,AVAILABLE-CONNECTIONS"
+
+/* Available fields for 'device show' - CAPABILITIES part */
+static NmcOutputField nmc_fields_dev_show_cap[] = {
+	{"NAME",            N_("NAME"),            13},  /* 0 */
+	{"CARRIER-DETECT",  N_("CARRIER-DETECT"),  16},  /* 1 */
+	{"SPEED",           N_("SPEED"),           10},  /* 2 */
+	{NULL,              NULL,                   0}
 };
-#define NMC_FIELDS_DEV_LIST_CONNECTIONS_ALL     "AVAILABLE-CONNECTION-PATHS,AVAILABLE-CONNECTIONS"
-#define NMC_FIELDS_DEV_LIST_CONNECTIONS_COMMON  "AVAILABLE-CONNECTION-PATHS,AVAILABLE-CONNECTIONS"
-
-/* Available fields for 'dev list' - CAPABILITIES part */
-static NmcOutputField nmc_fields_dev_list_cap[] = {
-	{"NAME",            N_("NAME"),            13, NULL, 0},  /* 0 */
-	{"CARRIER-DETECT",  N_("CARRIER-DETECT"),  16, NULL, 0},  /* 1 */
-	{"SPEED",           N_("SPEED"),           10, NULL, 0},  /* 2 */
-	{NULL,              NULL,                   0, NULL, 0}
+#define NMC_FIELDS_DEV_SHOW_CAP_ALL     "NAME,CARRIER-DETECT,SPEED"
+#define NMC_FIELDS_DEV_SHOW_CAP_COMMON  "NAME,CARRIER-DETECT,SPEED"
+
+/* Available fields for 'device show' - wired properties part */
+static NmcOutputField nmc_fields_dev_show_wired_prop[] = {
+	{"NAME",            N_("NAME"),     18},  /* 0 */
+	{"CARRIER",         N_("CARRIER"),  10},  /* 1 */
+	{NULL,              NULL,            0}
 };
-#define NMC_FIELDS_DEV_LIST_CAP_ALL     "NAME,CARRIER-DETECT,SPEED"
-#define NMC_FIELDS_DEV_LIST_CAP_COMMON  "NAME,CARRIER-DETECT,SPEED"
-
-/* Available fields for 'dev list' - wired properties part */
-static NmcOutputField nmc_fields_dev_list_wired_prop[] = {
-	{"NAME",            N_("NAME"),     18, NULL, 0},  /* 0 */
-	{"CARRIER",         N_("CARRIER"),  10, NULL, 0},  /* 1 */
-	{NULL,              NULL,            0, NULL, 0}
+#define NMC_FIELDS_DEV_SHOW_WIRED_PROP_ALL     "NAME,CARRIER"
+#define NMC_FIELDS_DEV_SHOW_WIRED_PROP_COMMON  "NAME,CARRIER"
+
+/* Available fields for 'device show' - wireless properties part */
+static NmcOutputField nmc_fields_dev_show_wifi_prop[] = {
+	{"NAME",       N_("NAME"),   18},  /* 0 */
+	{"WEP",        N_("WEP"),     5},  /* 1 */
+	{"WPA",        N_("WPA"),     5},  /* 2 */
+	{"WPA2",       N_("WPA2"),    6},  /* 3 */
+	{"TKIP",       N_("TKIP"),    6},  /* 4 */
+	{"CCMP",       N_("CCMP"),    6},  /* 5 */
+	{"AP",         N_("AP"),      6},  /* 6 */
+	{"ADHOC",      N_("ADHOC"),   6},  /* 7 */
+	{NULL,         NULL,          0}
 };
-#define NMC_FIELDS_DEV_LIST_WIRED_PROP_ALL     "NAME,CARRIER"
-#define NMC_FIELDS_DEV_LIST_WIRED_PROP_COMMON  "NAME,CARRIER"
-
-
-/* Available fields for 'dev list' - wireless properties part */
-static NmcOutputField nmc_fields_dev_list_wifi_prop[] = {
-	{"NAME",       N_("NAME"),        18, NULL, 0},  /* 0 */
-	{"WEP",        N_("WEP"),          5, NULL, 0},  /* 1 */
-	{"WPA",        N_("WPA"),          5, NULL, 0},  /* 2 */
-	{"WPA2",       N_("WPA2"),         6, NULL, 0},  /* 3 */
-	{"TKIP",       N_("TKIP"),         6, NULL, 0},  /* 4 */
-	{"CCMP",       N_("CCMP"),         6, NULL, 0},  /* 5 */
-	{"AP",         N_("AP"),           6, NULL, 0},  /* 6 */
-	{"ADHOC",      N_("ADHOC"),        6, NULL, 0},  /* 7 */
-	{NULL,         NULL,               0, NULL, 0}
-};
-#define NMC_FIELDS_DEV_LIST_WIFI_PROP_ALL     "NAME,WEP,WPA,WPA2,TKIP,CCMP,AP,ADHOC"
-#define NMC_FIELDS_DEV_LIST_WIFI_PROP_COMMON  "NAME,WEP,WPA,WPA2,TKIP,CCMP,AP,ADHOC"
-
-#if WITH_WIMAX
-/* Available fields for 'dev list' - wimax properties part */
-static NmcOutputField nmc_fields_dev_list_wimax_prop[] = {
-	{"NAME",       N_("NAME"),        18, NULL, 0},  /* 0 */
-	{"CTR-FREQ",   N_("CTR-FREQ"),     7, NULL, 0},  /* 1 */
-	{"RSSI",       N_("RSSI"),         5, NULL, 0},  /* 2 */
-	{"CINR",       N_("CINR"),         5, NULL, 0},  /* 3 */
-	{"TX-POW",     N_("TX-POW"),       5, NULL, 0},  /* 4 */
-	{"BSID",       N_("BSID"),        18, NULL, 0},  /* 5 */
-	{NULL,         NULL,               0, NULL, 0}
+#define NMC_FIELDS_DEV_SHOW_WIFI_PROP_ALL     "NAME,WEP,WPA,WPA2,TKIP,CCMP,AP,ADHOC"
+#define NMC_FIELDS_DEV_SHOW_WIFI_PROP_COMMON  "NAME,WEP,WPA,WPA2,TKIP,CCMP,AP,ADHOC"
+
+/* Available fields for 'device show' - wimax properties part */
+static NmcOutputField nmc_fields_dev_show_wimax_prop[] = {
+	{"NAME",       N_("NAME"),     18},  /* 0 */
+	{"CTR-FREQ",   N_("CTR-FREQ"),  7},  /* 1 */
+	{"RSSI",       N_("RSSI"),      5},  /* 2 */
+	{"CINR",       N_("CINR"),      5},  /* 3 */
+	{"TX-POW",     N_("TX-POW"),    5},  /* 4 */
+	{"BSID",       N_("BSID"),     18},  /* 5 */
+	{NULL,         NULL,            0}
 };
-#define NMC_FIELDS_DEV_LIST_WIMAX_PROP_ALL     "NAME,CTR-FREQ,RSSI,CINR,TX-POW,BSID"
-#define NMC_FIELDS_DEV_LIST_WIMAX_PROP_COMMON  "NAME,CTR-FREQ,RSSI,CINR,TX-POW,BSID"
-#endif
+#define NMC_FIELDS_DEV_SHOW_WIMAX_PROP_ALL     "NAME,CTR-FREQ,RSSI,CINR,TX-POW,BSID"
+#define NMC_FIELDS_DEV_SHOW_WIMAX_PROP_COMMON  "NAME,CTR-FREQ,RSSI,CINR,TX-POW,BSID"
 
-/* Available fields for 'dev wifi list' */
+/* Available fields for 'device wifi list' */
 static NmcOutputField nmc_fields_dev_wifi_list[] = {
-	{"NAME",       N_("NAME"),        15, NULL, 0},  /* 0 */
-	{"SSID",       N_("SSID"),        33, NULL, 0},  /* 1 */
-	{"BSSID",      N_("BSSID"),       19, NULL, 0},  /* 2 */
-	{"MODE",       N_("MODE"),        16, NULL, 0},  /* 3 */
-	{"FREQ",       N_("FREQ"),        10, NULL, 0},  /* 4 */
-	{"RATE",       N_("RATE"),        10, NULL, 0},  /* 5 */
-	{"SIGNAL",     N_("SIGNAL"),       8, NULL, 0},  /* 6 */
-	{"SECURITY",   N_("SECURITY"),    10, NULL, 0},  /* 7 */
-	{"WPA-FLAGS",  N_("WPA-FLAGS"),   25, NULL, 0},  /* 8 */
-	{"RSN-FLAGS",  N_("RSN-FLAGS"),   25, NULL, 0},  /* 9 */
-	{"DEVICE",     N_("DEVICE"),      10, NULL, 0},  /* 10 */
-	{"ACTIVE",     N_("ACTIVE"),       8, NULL, 0},  /* 11 */
-	{"DBUS-PATH",  N_("DBUS-PATH"),   46, NULL, 0},  /* 12 */
-	{NULL,         NULL,               0, NULL, 0}
+	{"NAME",       N_("NAME"),       15},  /* 0 */
+	{"SSID",       N_("SSID"),       33},  /* 1 */
+	{"SSID-HEX",   N_("SSID-HEX"),   66},  /* 2 */
+	{"BSSID",      N_("BSSID"),      19},  /* 3 */
+	{"MODE",       N_("MODE"),       16},  /* 4 */
+	{"CHAN",       N_("CHAN"),        6},  /* 5 */
+	{"FREQ",       N_("FREQ"),       10},  /* 6 */
+	{"RATE",       N_("RATE"),       10},  /* 7 */
+	{"SIGNAL",     N_("SIGNAL"),      8},  /* 8 */
+	{"BARS",       N_("BARS"),        6},  /* 9 */
+	{"SECURITY",   N_("SECURITY"),   10},  /* 10 */
+	{"WPA-FLAGS",  N_("WPA-FLAGS"),  25},  /* 11 */
+	{"RSN-FLAGS",  N_("RSN-FLAGS"),  25},  /* 12 */
+	{"DEVICE",     N_("DEVICE"),     10},  /* 13 */
+	{"ACTIVE",     N_("ACTIVE"),      8},  /* 14 */
+	{"IN-USE",     N_("*"),           1},  /* 15 */
+	{"DBUS-PATH",  N_("DBUS-PATH"),  46},  /* 16 */
+	{NULL,         NULL,              0}
 };
-#define NMC_FIELDS_DEV_WIFI_LIST_ALL           "SSID,BSSID,MODE,FREQ,RATE,SIGNAL,SECURITY,WPA-FLAGS,RSN-FLAGS,DEVICE,ACTIVE,DBUS-PATH"
-#define NMC_FIELDS_DEV_WIFI_LIST_COMMON        "SSID,BSSID,MODE,FREQ,RATE,SIGNAL,SECURITY,ACTIVE"
+#define NMC_FIELDS_DEV_WIFI_LIST_ALL           "SSID,SSID-HEX,BSSID,MODE,CHAN,FREQ,RATE,SIGNAL,BARS,SECURITY,"\
+                                               "WPA-FLAGS,RSN-FLAGS,DEVICE,ACTIVE,IN-USE,DBUS-PATH"
+#define NMC_FIELDS_DEV_WIFI_LIST_COMMON        "IN-USE,SSID,MODE,CHAN,RATE,SIGNAL,BARS,SECURITY"
 #define NMC_FIELDS_DEV_WIFI_LIST_FOR_DEV_LIST  "NAME,"NMC_FIELDS_DEV_WIFI_LIST_COMMON
 
-#if WITH_WIMAX
-/* Available fields for 'dev wimax list' */
+/* Available fields for 'device wimax list' */
 static NmcOutputField nmc_fields_dev_wimax_list[] = {
-	{"NAME",       N_("NAME"),        15, NULL, 0},  /* 0 */
-	{"NSP",        N_("NSP"),         33, NULL, 0},  /* 1 */
-	{"SIGNAL",     N_("SIGNAL"),       8, NULL, 0},  /* 2 */
-	{"TYPE",       N_("TYPE"),        16, NULL, 0},  /* 3 */
-	{"DEVICE",     N_("DEVICE"),      10, NULL, 0},  /* 4 */
-	{"ACTIVE",     N_("ACTIVE"),       8, NULL, 0},  /* 5 */
-	{"DBUS-PATH",  N_("DBUS-PATH"),   46, NULL, 0},  /* 6 */
-	{NULL,         NULL,               0, NULL, 0}
+	{"NAME",       N_("NAME"),        15},  /* 0 */
+	{"NSP",        N_("NSP"),         33},  /* 1 */
+	{"SIGNAL",     N_("SIGNAL"),       8},  /* 2 */
+	{"TYPE",       N_("TYPE"),        16},  /* 3 */
+	{"DEVICE",     N_("DEVICE"),      10},  /* 4 */
+	{"ACTIVE",     N_("ACTIVE"),       8},  /* 5 */
+	{"DBUS-PATH",  N_("DBUS-PATH"),   46},  /* 6 */
+	{NULL,         NULL,               0}
 };
 #define NMC_FIELDS_DEV_WIMAX_LIST_ALL           "NSP,SIGNAL,TYPE,DEVICE,ACTIVE,DBUS-PATH"
 #define NMC_FIELDS_DEV_WIMAX_LIST_COMMON        "NSP,SIGNAL,TYPE,DEVICE,ACTIVE"
 #define NMC_FIELDS_DEV_WIMAX_LIST_FOR_DEV_LIST  "NAME,"NMC_FIELDS_DEV_WIMAX_LIST_COMMON
-#endif
 
-/* Available fields for 'dev list' - BOND part */
-static NmcOutputField nmc_fields_dev_list_bond_prop[] = {
-	{"NAME",            N_("NAME"),     18, NULL, 0},  /* 0 */
-	{"SLAVES",          N_("SLAVES"),   20, NULL, 0},  /* 1 */
-	{NULL,              NULL,            0, NULL, 0}
+/* Available fields for 'device show' - BOND part */
+static NmcOutputField nmc_fields_dev_show_bond_prop[] = {
+	{"NAME",           N_("NAME"),     18},  /* 0 */
+	{"SLAVES",         N_("SLAVES"),   20},  /* 1 */
+	{NULL,             NULL,            0}
+};
+#define NMC_FIELDS_DEV_SHOW_BOND_PROP_ALL     "NAME,SLAVES"
+#define NMC_FIELDS_DEV_SHOW_BOND_PROP_COMMON  "NAME,SLAVES"
+
+/* Available fields for 'device show' - VLAN part */
+static NmcOutputField nmc_fields_dev_show_vlan_prop[] = {
+	{"NAME",           N_("NAME"),     18},  /* 0 */
+	{"ID",             N_("ID"),        5},  /* 1 */
+	{NULL,             NULL,            0}
 };
-#define NMC_FIELDS_DEV_LIST_BOND_PROP_ALL     "NAME,SLAVES"
-#define NMC_FIELDS_DEV_LIST_BOND_PROP_COMMON  "NAME,SLAVES"
-
-/* Available fields for 'dev list' - VLAN part */
-static NmcOutputField nmc_fields_dev_list_vlan_prop[] = {
-	{"NAME",            N_("NAME"),     18, NULL, 0},  /* 0 */
-	{"ID",              N_("ID"),        5, NULL, 0},  /* 1 */
-	{NULL,              NULL,            0, NULL, 0}
+#define NMC_FIELDS_DEV_SHOW_VLAN_PROP_ALL     "NAME,ID"
+#define NMC_FIELDS_DEV_SHOW_VLAN_PROP_COMMON  "NAME,ID"
+
+/* 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 sections for 'device show' */
+static NmcOutputField nmc_fields_dev_show_sections[] = {
+	{"GENERAL",           N_("GENERAL"),           0, nmc_fields_dev_show_general + 1     },  /* 0 */
+	{"CAPABILITIES",      N_("CAPABILITIES"),      0, nmc_fields_dev_show_cap + 1         },  /* 1 */
+	{"WIFI-PROPERTIES",   N_("WIFI-PROPERTIES"),   0, nmc_fields_dev_show_wifi_prop + 1   },  /* 2 */
+	{"AP",                N_("AP"),                0, nmc_fields_dev_wifi_list + 1        },  /* 3 */
+	{"WIRED-PROPERTIES",  N_("WIRED-PROPERTIES"),  0, nmc_fields_dev_show_wired_prop + 1  },  /* 4 */
+	{"WIMAX-PROPERTIES",  N_("WIMAX-PROPERTIES"),  0, nmc_fields_dev_show_wimax_prop + 1  },  /* 5 */
+	{"NSP",               N_("NSP"),               0, nmc_fields_dev_wimax_list + 1       },  /* 6 */
+	{"IP4",               N_("IP4"),               0, nmc_fields_ip4_config + 1           },  /* 7 */
+	{"DHCP4",             N_("DHCP4"),             0, nmc_fields_dhcp4_config + 1         },  /* 8 */
+	{"IP6",               N_("IP6"),               0, nmc_fields_ip6_config + 1           },  /* 9 */
+	{"DHCP6",             N_("DHCP6"),             0, nmc_fields_dhcp6_config + 1         },  /* 10 */
+	{"BOND",              N_("BOND"),              0, nmc_fields_dev_show_bond_prop + 1   },  /* 11 */
+	{"VLAN",              N_("VLAN"),              0, nmc_fields_dev_show_vlan_prop  + 1  },  /* 12 */
+	{"CONNECTIONS",       N_("CONNECTIONS"),       0, nmc_fields_dev_show_connections + 1 },  /* 13 */
+	{NULL,                NULL,                    0, NULL                                }
 };
-#define NMC_FIELDS_DEV_LIST_VLAN_PROP_ALL     "NAME,ID"
-#define NMC_FIELDS_DEV_LIST_VLAN_PROP_COMMON  "NAME,ID"
+#if WITH_WIMAX
+#define NMC_FIELDS_DEV_SHOW_SECTIONS_ALL     "GENERAL,CAPABILITIES,BOND,VLAN,CONNECTIONS,WIFI-PROPERTIES,AP,WIRED-PROPERTIES,"\
+                                             "WIMAX-PROPERTIES,NSP,IP4,DHCP4,IP6,DHCP6"
+#define NMC_FIELDS_DEV_SHOW_SECTIONS_COMMON  "GENERAL.DEVICE,GENERAL.TYPE,GENERAL.HWADDR,GENERAL.MTU,GENERAL.STATE,"\
+                                             "GENERAL.CONNECTION,GENERAL.CON-PATH,WIRED-PROPERTIES,IP4,IP6"
+#else
+#define NMC_FIELDS_DEV_SHOW_SECTIONS_ALL     "GENERAL,CAPABILITIES,BOND,VLAN,CONNECTIONS,WIFI-PROPERTIES,AP,WIRED-PROPERTIES,"\
+                                             "IP4,DHCP4,IP6,DHCP6"
+#define NMC_FIELDS_DEV_SHOW_SECTIONS_COMMON  "GENERAL.DEVICE,GENERAL.TYPE,GENERAL.HWADDR,GENERAL.MTU,GENERAL.STATE,"\
+                                             "GENERAL.CONNECTION,GENERAL.CON-PATH,WIRED-PROPERTIES,IP4,IP6"
+#endif
 
 
 /* glib main loop variable - defined in nmcli.c */
@@ -257,23 +276,127 @@ usage (void)
 	fprintf (stderr,
 	         _("Usage: nmcli device { COMMAND | help }\n\n"
 #if WITH_WIMAX
-	         "  COMMAND := { status | list | disconnect | wifi | wimax }\n\n"
+	           "COMMAND := { status | show | connect | disconnect | wifi | wimax }\n\n"
 #else
-	         "  COMMAND := { status | list | disconnect | wifi }\n\n"
+	           "COMMAND := { status | show | connect | disconnect | wifi }\n\n"
 #endif
-	         "  status\n"
-	         "  list [iface <iface>]\n"
-	         "  disconnect iface <iface> [--nowait] [--timeout <timeout>]\n"
-	         "  wifi [list [iface <iface>] [bssid <BSSID>]]\n"
-	         "  wifi connect <(B)SSID> [password <password>] [wep-key-type key|phrase] [iface <iface>] [bssid <BSSID>] [name <name>]\n"
-	         "               [--private] [--nowait] [--timeout <timeout>]\n"
+	           "  status\n\n"
+	           "  show [<ifname>]\n\n"
+	           "  connect <ifname>\n\n"
+	           "  disconnect <ifname>\n\n"
+	           "  wifi [list [ifname <ifname>] [bssid <BSSID>]]\n\n"
+	           "  wifi connect <(B)SSID> [password <password>] [wep-key-type key|phrase] [ifname <ifname>]\n"
+	           "                         [bssid <BSSID>] [name <name>] [private yes|no]\n\n"
+	           "  wifi rescan [[ifname] <ifname>]\n\n"
 #if WITH_WIMAX
-	         "  wimax [list [iface <iface>] [nsp <name>]]\n"
+	           "  wimax [list [ifname <ifname>] [nsp <name>]]\n\n"
 #endif
-	         "\n"
 	         ));
 }
 
+static void
+usage_device_status (void)
+{
+	fprintf (stderr,
+	         _("Usage: nmcli device status { help }\n"
+	           "\n"
+	           "Show status for all devices.\n"
+	           "By default, the following columns are shown:\n"
+	           " DEVICE     - interface name\n"
+	           " TYPE       - device type\n"
+	           " STATE      - device state\n"
+	           " CONNECTION - connection activated on device (if any)\n"
+	           "Displayed columns can be changed using '--fields' global option. 'status' is\n"
+	           "the default command, which means 'nmcli device' calls 'nmcli device status'.\n\n"));
+}
+
+static void
+usage_device_show (void)
+{
+	fprintf (stderr,
+	         _("Usage: nmcli device show { ARGUMENTS | help }\n"
+	           "\n"
+	           "ARGUMENTS := [<ifname>]\n"
+	           "\n"
+	           "Show details of device(s).\n"
+	           "The command lists details for all devices, or for a given device.\n\n"));
+}
+
+static void
+usage_device_connect (void)
+{
+	fprintf (stderr,
+	         _("Usage: nmcli device connect { ARGUMENTS | help }\n"
+	           "\n"
+	           "ARGUMENTS := <ifname>\n"
+	           "\n"
+	           "Connect the device.\n"
+	           "NetworkManager will try to find a suitable connection that will be activated.\n"
+	           "It will also consider connections that are not set to auto-connect.\n\n"));
+}
+
+static void
+usage_device_disconnect (void)
+{
+	fprintf (stderr,
+	         _("Usage: nmcli device disconnect { ARGUMENTS | help }\n"
+	           "\n"
+	           "ARGUMENTS := <ifname>\n"
+	           "\n"
+	           "Disconnect the device.\n"
+	           "The command disconnects the device and prevents it from auto-activating\n"
+	           "further connections without user/manual intervention.\n\n"));
+}
+
+static void
+usage_device_wifi (void)
+{
+	fprintf (stderr,
+	         _("Usage: nmcli device wifi { ARGUMENTS | help }\n"
+	           "\n"
+	           "Perform operation on Wi-Fi devices.\n"
+	           "\n"
+	           "ARGUMENTS := [list [ifname <ifname>] [bssid <BSSID>]]\n"
+	           "\n"
+	           "List available Wi-Fi access points. The 'ifname' and 'bssid' options can be\n"
+	           "used to list APs for a particular interface, or with a specific BSSID.\n"
+	           "\n"
+	           "ARGUMENTS := connect <(B)SSID> [password <password>] [wep-key-type key|phrase] [ifname <ifname>]\n"
+	           "                    [bssid <BSSID>] [name <name>] [private yes|no]\n"
+	           "\n"
+	           "Connect to a Wi-Fi network specified by SSID or BSSID. The command creates\n"
+	           "a new connection and then activates it on a device. This is a command-line\n"
+	           "counterpart of clicking an SSID in a GUI client. The command always creates\n"
+	           "a new connection and thus it is mainly useful for connecting to new Wi-Fi\n"
+	           "networks. If a connection for the network already exists, it is better to\n"
+	           "bring up the existing profile as follows: nmcli con up id <name>. Note that\n"
+	           "only open, WEP and WPA-PSK networks are supported at the moment. It is also\n"
+	           "assumed that IP configuration is obtained via DHCP.\n"
+	           "\n"
+	           "ARGUMENTS := rescan [[ifname] <ifname>]\n"
+	           "\n"
+	           "Request that NetworkManager immediately re-scan for available access points.\n"
+	           "NetworkManager scans Wi-Fi networks periodically, but in some cases it might\n"
+	           "be useful to start scanning manually. Note that this command does not show\n"
+	           "the APs, use 'nmcli device wifi list' for that.\n\n"));
+}
+
+#if WITH_WIMAX
+static void
+usage_device_wimax (void)
+{
+	fprintf (stderr,
+	         _("Usage: nmcli device wimax { ARGUMENTS | help }\n"
+	           "\n"
+	           "Perform operation on WiMAX devices.\n"
+	           "\n"
+	           "ARGUMENTS := [list [ifname <ifname>] [nsp <name>]]\n"
+	           "\n"
+	           "List available WiMAX NSPs. The 'ifname' and 'nsp' options can be used to\n"
+	           "list networks for a particular interface, or with a specific NSP.\n\n"));
+}
+#endif
+
 /* quit main loop */
 static void
 quit (void)
@@ -286,47 +409,46 @@ quit (void)
 	g_main_loop_quit (loop);  /* quit main loop */
 }
 
-/* Convert device type to string. Use setting names strings to match with
- * connection type names.
- */
-static const char *
-device_type_to_string (NMDevice *device)
+static int
+compare_devices (const void *a, const void *b)
 {
-	NMDeviceModemCapabilities caps = NM_DEVICE_MODEM_CAPABILITY_NONE;
-
-	switch (nm_device_get_device_type (device)) {
-	case NM_DEVICE_TYPE_ETHERNET:
-		return NM_SETTING_WIRED_SETTING_NAME;
-	case NM_DEVICE_TYPE_ADSL:
-		return NM_SETTING_ADSL_SETTING_NAME;
-	case NM_DEVICE_TYPE_WIFI:
-		return NM_SETTING_WIRELESS_SETTING_NAME;
-	case NM_DEVICE_TYPE_MODEM:
-		caps = nm_device_modem_get_current_capabilities (NM_DEVICE_MODEM (device));
-		if (caps & NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS)
-			return NM_SETTING_GSM_SETTING_NAME;
-		else if (caps & NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO)
-			return NM_SETTING_CDMA_SETTING_NAME;
-		return _("Unknown");
-	case NM_DEVICE_TYPE_BT:
-		return NM_SETTING_BLUETOOTH_SETTING_NAME;
-	case NM_DEVICE_TYPE_OLPC_MESH:
-		return NM_SETTING_OLPC_MESH_SETTING_NAME;
-#if WITH_WIMAX
-	case NM_DEVICE_TYPE_WIMAX:
-		return NM_SETTING_WIMAX_SETTING_NAME;
-#endif
-	case NM_DEVICE_TYPE_INFINIBAND:
-		return NM_SETTING_INFINIBAND_SETTING_NAME;
-	case NM_DEVICE_TYPE_BOND:
-		return NM_SETTING_BOND_SETTING_NAME;
-	case NM_DEVICE_TYPE_VLAN:
-		return NM_SETTING_VLAN_SETTING_NAME;
-	case NM_DEVICE_TYPE_BRIDGE:
-		return NM_SETTING_BRIDGE_SETTING_NAME;
-	default:
-		return _("Unknown");
+	NMDevice *da = *(NMDevice **)a;
+	NMDevice *db = *(NMDevice **)b;
+	int cmp;
+
+	/* Sort by later device states first */
+	cmp = nm_device_get_state (db) - nm_device_get_state (da);
+	if (cmp != 0)
+		return cmp;
+
+	cmp = g_strcmp0 (nm_device_get_type_description (da),
+	                 nm_device_get_type_description (db));
+	if (cmp != 0)
+		return cmp;
+
+	return g_strcmp0 (nm_device_get_iface (da),
+	                  nm_device_get_iface (db));
+}
+
+static NMDevice **
+get_devices_sorted (NMClient *client)
+{
+	const GPtrArray *devs;
+	NMDevice **sorted;
+
+	devs = nm_client_get_devices (client);
+	if (!devs) {
+		sorted = g_new (NMDevice *, 1);
+		sorted[0] = NULL;
+		return sorted;
 	}
+
+	sorted = g_new (NMDevice *, devs->len + 1);
+	memcpy (sorted, devs->pdata, devs->len * sizeof (NMDevice *));
+	sorted[devs->len] = NULL;
+
+	qsort (sorted, devs->len, sizeof (NMDevice *), compare_devices);
+	return sorted;
 }
 
 static char *
@@ -374,15 +496,17 @@ ap_wpa_rsn_flags_to_string (NM80211ApSecurityFlags flags)
 typedef struct {
 	NmCli *nmc;
 	int index;
+	guint32 output_flags;
 	const char* active_bssid;
 	const char* device;
 } APInfo;
 
 static void
-detail_access_point (gpointer data, gpointer user_data)
+fill_output_access_point (gpointer data, gpointer user_data)
 {
 	NMAccessPoint *ap = NM_ACCESS_POINT (data);
 	APInfo *info = (APInfo *) user_data;
+	NmcOutputField *arr;
 	gboolean active = FALSE;
 	NM80211ApFlags flags;
 	NM80211ApSecurityFlags wpa_flags, rsn_flags;
@@ -391,9 +515,16 @@ detail_access_point (gpointer data, gpointer user_data)
 	const GByteArray *ssid;
 	const char *bssid;
 	NM80211Mode mode;
-	char *freq_str, *ssid_str, *bitrate_str, *strength_str, *wpa_flags_str, *rsn_flags_str;
+	char *channel_str, *freq_str, *ssid_str = NULL, *ssid_hex_str = NULL,
+	     *bitrate_str, *strength_str, *wpa_flags_str, *rsn_flags_str;
 	GString *security_str;
 	char *ap_name;
+	const char *sig_level_0 = "____";
+	const char *sig_level_1 = "â–‚___";
+	const char *sig_level_2 = "â–‚â–„__";
+	const char *sig_level_3 = "â–‚â–„â–†_";
+	const char *sig_level_4 = "▂▄▆█";
+	const char *sig_bars;
 
 	if (info->active_bssid) {
 		const char *current_bssid = nm_access_point_get_bssid (ap);
@@ -410,75 +541,89 @@ detail_access_point (gpointer data, gpointer user_data)
 	freq = nm_access_point_get_frequency (ap);
 	mode = nm_access_point_get_mode (ap);
 	bitrate = nm_access_point_get_max_bitrate (ap);
-	strength = nm_access_point_get_strength (ap);
+	strength = MIN (nm_access_point_get_strength (ap), 100);
 
 	/* Convert to strings */
-	ssid_str = ssid_to_printable ((const char *) ssid->data, ssid->len);
+	if (ssid) {
+		ssid_str = nm_utils_ssid_to_utf8 (ssid);
+		ssid_hex_str = ssid_to_hex ((const char *) ssid->data, ssid->len);
+	}
+	channel_str = g_strdup_printf ("%u", nm_utils_wifi_freq_to_channel (freq));
 	freq_str = g_strdup_printf (_("%u MHz"), freq);
-	bitrate_str = g_strdup_printf (_("%u MB/s"), bitrate/1000);
+	bitrate_str = g_strdup_printf (_("%u Mbit/s"), bitrate/1000);
 	strength_str = g_strdup_printf ("%u", strength);
 	wpa_flags_str = ap_wpa_rsn_flags_to_string (wpa_flags);
 	rsn_flags_str = ap_wpa_rsn_flags_to_string (rsn_flags);
+	sig_bars = strength > 80 ? sig_level_4 :
+	           strength > 55 ? sig_level_3 :
+	           strength > 30 ? sig_level_2 :
+	           strength > 5  ? sig_level_1 :
+	                           sig_level_0;
 
 	security_str = g_string_new (NULL);
-	if (   !(flags & NM_802_11_AP_FLAGS_PRIVACY)
-	    &&  (wpa_flags != NM_802_11_AP_SEC_NONE)
-	    &&  (rsn_flags != NM_802_11_AP_SEC_NONE))
-		g_string_append (security_str, _("Encrypted: "));
 
 	if (   (flags & NM_802_11_AP_FLAGS_PRIVACY)
 	    && (wpa_flags == NM_802_11_AP_SEC_NONE)
-	    && (rsn_flags == NM_802_11_AP_SEC_NONE))
-		g_string_append (security_str, _("WEP "));
-	if (wpa_flags != NM_802_11_AP_SEC_NONE)
-		g_string_append (security_str, _("WPA "));
-	if (rsn_flags != NM_802_11_AP_SEC_NONE)
-		g_string_append (security_str, _("WPA2 "));
+	    && (rsn_flags == NM_802_11_AP_SEC_NONE)) {
+		g_string_append (security_str, _("WEP"));
+		g_string_append_c (security_str, ' ');
+	}
+	if (wpa_flags != NM_802_11_AP_SEC_NONE) {
+		g_string_append (security_str, _("WPA1"));
+		g_string_append_c (security_str, ' ');
+	}
+	if (rsn_flags != NM_802_11_AP_SEC_NONE) {
+		g_string_append (security_str, _("WPA2"));
+		g_string_append_c (security_str, ' ');
+	}
 	if (   (wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)
-	    || (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X))
-		g_string_append (security_str, _("Enterprise "));
+	    || (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) {
+		g_string_append   (security_str, _("802.1X"));
+		g_string_append_c (security_str, ' ');
+	}
 
 	if (security_str->len > 0)
 		g_string_truncate (security_str, security_str->len-1);  /* Chop off last space */
 
+	arr = nmc_dup_fields_array (nmc_fields_dev_wifi_list,
+	                            sizeof (nmc_fields_dev_wifi_list),
+	                            info->output_flags);
+
 	ap_name = g_strdup_printf ("AP[%d]", info->index++); /* AP */
-	info->nmc->allowed_fields[0].value = ap_name;
-	info->nmc->allowed_fields[1].value = ssid_str;
-	info->nmc->allowed_fields[2].value = bssid;
-	info->nmc->allowed_fields[3].value = mode == NM_802_11_MODE_ADHOC ? _("Ad-Hoc")
-	                                   : mode == NM_802_11_MODE_INFRA ? _("Infrastructure")
-	                                   : _("Unknown");
-	info->nmc->allowed_fields[4].value = freq_str;
-	info->nmc->allowed_fields[5].value = bitrate_str;
-	info->nmc->allowed_fields[6].value = strength_str;
-	info->nmc->allowed_fields[7].value = security_str->str;
-	info->nmc->allowed_fields[8].value = wpa_flags_str;
-	info->nmc->allowed_fields[9].value = rsn_flags_str;
-	info->nmc->allowed_fields[10].value = info->device;
-	info->nmc->allowed_fields[11].value = active ? _("yes") : _("no");
-	info->nmc->allowed_fields[12].value = nm_object_get_path (NM_OBJECT (ap));
-
-	info->nmc->print_fields.flags &= ~NMC_PF_FLAG_MAIN_HEADER_ADD & ~NMC_PF_FLAG_MAIN_HEADER_ONLY & ~NMC_PF_FLAG_FIELD_NAMES; /* Clear header flags */
-	print_fields (info->nmc->print_fields, info->nmc->allowed_fields);
-
-	g_free (ap_name);
-	g_free (ssid_str);
-	g_free (freq_str);
-	g_free (bitrate_str);
-	g_free (strength_str);
-	g_free (wpa_flags_str);
-	g_free (rsn_flags_str);
-	g_string_free (security_str, TRUE);
+	set_val_str  (arr, 0, ap_name);
+	set_val_str  (arr, 1, ssid_str);
+	set_val_str  (arr, 2, ssid_hex_str);
+	set_val_strc (arr, 3, bssid);
+	set_val_strc (arr, 4, mode == NM_802_11_MODE_ADHOC ? _("Ad-Hoc")
+	                    : mode == NM_802_11_MODE_INFRA ? _("Infra")
+	                    : _("N/A"));
+	set_val_str  (arr, 5, channel_str);
+	set_val_str  (arr, 6, freq_str);
+	set_val_str  (arr, 7, bitrate_str);
+	set_val_str  (arr, 8, strength_str);
+	set_val_strc (arr, 9, sig_bars);
+	set_val_str  (arr, 10, security_str->str);
+	set_val_str  (arr, 11, wpa_flags_str);
+	set_val_str  (arr, 12, rsn_flags_str);
+	set_val_strc (arr, 13, info->device);
+	set_val_strc (arr, 14, active ? _("yes") : _("no"));
+	set_val_strc (arr, 15, active ? "*" : " ");
+	set_val_strc (arr, 16, nm_object_get_path (NM_OBJECT (ap)));
+
+	g_ptr_array_add (info->nmc->output_data, arr);
+
+	g_string_free (security_str, FALSE);
 }
 
 #if WITH_WIMAX
 static void
-detail_wimax_nsp (NMWimaxNsp *nsp, NmCli *nmc, NMDevice *dev, int idx)
+fill_output_wimax_nsp (NMWimaxNsp *nsp, NmCli *nmc, NMDevice *dev, int idx, guint32 o_flags)
 {
 	NMDeviceWimax *wimax = NM_DEVICE_WIMAX (dev);
 	char *nsp_name, *quality_str;
 	const char *ntype;
 	gboolean active = FALSE;
+	NmcOutputField *arr;
 
 	switch (nm_wimax_nsp_get_network_type (nsp)) {
 	case NM_WIMAX_NSP_NETWORK_TYPE_HOME:
@@ -503,32 +648,64 @@ detail_wimax_nsp (NMWimaxNsp *nsp, NmCli *nmc, NMDevice *dev, int idx)
 	quality_str = g_strdup_printf ("%u", nm_wimax_nsp_get_signal_quality (nsp));
 	nsp_name = g_strdup_printf ("NSP[%d]", idx); /* NSP */
 
-	nmc->allowed_fields[0].value = nsp_name;
-	nmc->allowed_fields[1].value = nm_wimax_nsp_get_name (nsp);
-	nmc->allowed_fields[2].value = quality_str;
-	nmc->allowed_fields[3].value = ntype;
-	nmc->allowed_fields[4].value = nm_device_get_iface (dev);
-	nmc->allowed_fields[5].value = active ? _("yes") : _("no");
-	nmc->allowed_fields[6].value = nm_object_get_path (NM_OBJECT (nsp));
+	arr = nmc_dup_fields_array (nmc_fields_dev_wimax_list,
+	                            sizeof (nmc_fields_dev_wimax_list),
+	                            o_flags);
+	set_val_str  (arr, 0, nsp_name);
+	set_val_strc (arr, 1, nm_wimax_nsp_get_name (nsp));
+	set_val_str  (arr, 2, quality_str);
+	set_val_strc (arr, 3, ntype);
+	set_val_strc (arr, 4, nm_device_get_iface (dev));
+	set_val_strc (arr, 5, active ? _("yes") : _("no"));
+	set_val_strc (arr, 6, nm_object_get_path (NM_OBJECT (nsp)));
+
+	g_ptr_array_add (nmc->output_data, arr);
+}
+#endif
+
+static const char *
+construct_header_name (const char *base, const char *spec)
+{
+	static char header_name[128];
 
-	nmc->print_fields.flags &= ~NMC_PF_FLAG_MAIN_HEADER_ADD & ~NMC_PF_FLAG_MAIN_HEADER_ONLY & ~NMC_PF_FLAG_FIELD_NAMES; /* Clear header flags */
-	print_fields (nmc->print_fields, nmc->allowed_fields);
+	if (spec == NULL)
+		return base;
 
-	g_free (nsp_name);
-	g_free (quality_str);
+	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;
 }
-#endif
 
-struct cb_info {
-	NMClient *client;
-	const GPtrArray *active;
-};
+static const char *
+get_active_connection_id (NMDevice *device)
+{
+	const GPtrArray *avail_cons;
+	NMActiveConnection *ac;
+	const char *ac_uuid;
+	int i;
 
-static void
-show_device_info (gpointer data, gpointer user_data)
+	ac = nm_device_get_active_connection (device);
+	if (!ac)
+		return NULL;
+	ac_uuid = nm_active_connection_get_uuid (ac);
+
+	avail_cons = nm_device_get_available_connections (device);
+	for (i = 0; avail_cons && (i < avail_cons->len); i++) {
+		NMRemoteConnection *candidate = g_ptr_array_index (avail_cons, i);
+		const char *test_uuid = nm_connection_get_uuid (NM_CONNECTION (candidate));
+
+		if (g_strcmp0 (ac_uuid, test_uuid) == 0)
+			return nm_connection_get_id (NM_CONNECTION (candidate));
+	}
+	return NULL;
+}
+
+static gboolean
+show_device_info (NMDevice *device, NmCli *nmc)
 {
-	NMDevice *device = NM_DEVICE (data);
-	NmCli *nmc = (NmCli *) user_data;
 	GError *error = NULL;
 	APInfo *info;
 	const char *hwaddr = NULL;
@@ -537,18 +714,21 @@ show_device_info (gpointer data, gpointer user_data)
 	NMDeviceCapabilities caps;
 	NMActiveConnection *acon;
 	guint32 speed;
-	char *speed_str = NULL;
-	char *state_str = NULL;
-	char *reason_str = NULL;
+	char *speed_str, *state_str, *reason_str, *mtu_str;
 	GArray *sections_array;
 	int k;
 	char *fields_str;
-	char *fields_all =    NMC_FIELDS_DEV_LIST_SECTIONS_ALL;
-	char *fields_common = NMC_FIELDS_DEV_LIST_SECTIONS_COMMON;
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+	char *fields_all =    NMC_FIELDS_DEV_SHOW_SECTIONS_ALL;
+	char *fields_common = NMC_FIELDS_DEV_SHOW_SECTIONS_COMMON;
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
 	gboolean was_output = FALSE;
+	NMIP4Config *cfg4;
+	NMIP6Config *cfg6;
+	NMDHCP4Config *dhcp4;
+	NMDHCP6Config *dhcp6;
+	const char *base_hdr = _("Device details");
+	GPtrArray *fields_in_section = NULL;
 
 	if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0)
 		fields_str = fields_common;
@@ -557,94 +737,87 @@ show_device_info (gpointer data, gpointer user_data)
 	else
 		fields_str = nmc->required_fields;
 
-	sections_array = parse_output_fields (fields_str, nmc_fields_dev_list_sections, &error);
+	sections_array = parse_output_fields (fields_str, nmc_fields_dev_show_sections, TRUE, &fields_in_section, &error);
 	if (error) {
-		if (error->code == 0)
-			g_string_printf (nmc->return_text, _("Error: 'dev list': %s"), error->message);
-		else
-			g_string_printf (nmc->return_text, _("Error: 'dev list': %s; allowed fields: %s"), error->message, NMC_FIELDS_DEV_LIST_SECTIONS_ALL);
+		g_string_printf (nmc->return_text, _("Error: 'device show': %s"), error->message);
 		g_error_free (error);
 		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-		return;
+		return FALSE;
 	}
 
 	/* Main header */
-	nmc->allowed_fields = nmc_fields_dev_list_general;
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ONLY;
-	nmc->print_fields.header_name = _("Device details");
-	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_DEV_LIST_GENERAL_ALL, nmc->allowed_fields, NULL);
-	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
+	nmc->print_fields.header_name = (char *) construct_header_name (base_hdr, nm_device_get_iface (device));
+	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_DEV_SHOW_GENERAL_ALL,
+	                                                 nmc_fields_dev_show_general, FALSE, NULL, NULL);
+
+	nmc_fields_dev_show_general[0].flags = NMC_OF_FLAG_MAIN_HEADER_ONLY;
+	print_required_fields (nmc, nmc_fields_dev_show_general);
 
 	/* Loop through the required sections and print them. */
 	for (k = 0; k < sections_array->len; k++) {
 		int section_idx = g_array_index (sections_array, int, k);
+		char *section_fld = (char *) g_ptr_array_index (fields_in_section, k);
 
 		if (nmc->print_output != NMC_PRINT_TERSE && !nmc->multiline_output && was_output)
-			printf ("\n"); /* Empty line */
+			printf ("\n"); /* Print empty line between groups in tabular mode */
 
 		was_output = FALSE;
 
+		/* Remove any previous data */
+		nmc_empty_output_fields (nmc);
+
 		state = nm_device_get_state_reason (device, &reason);
 
 		/* section GENERAL */
-		if (!strcasecmp (nmc_fields_dev_list_sections[section_idx].name, nmc_fields_dev_list_sections[0].name)) {
-			nmc->allowed_fields = nmc_fields_dev_list_general;
-			nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-			nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_DEV_LIST_GENERAL_ALL, nmc->allowed_fields, NULL);
-			print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
-
-			if (NM_IS_DEVICE_ETHERNET (device))
-				hwaddr = nm_device_ethernet_get_hw_address (NM_DEVICE_ETHERNET (device));
-			else if (NM_IS_DEVICE_WIFI (device))
-				hwaddr = nm_device_wifi_get_hw_address (NM_DEVICE_WIFI (device));
-#if WITH_WIMAX
-			else if (NM_IS_DEVICE_WIMAX (device))
-				hwaddr = nm_device_wimax_get_hw_address (NM_DEVICE_WIMAX (device));
-#endif
-			else if (NM_IS_DEVICE_INFINIBAND (device))
-				hwaddr = nm_device_infiniband_get_hw_address (NM_DEVICE_INFINIBAND (device));
-			else if (NM_IS_DEVICE_BOND (device))
-				hwaddr = nm_device_bond_get_hw_address (NM_DEVICE_BOND (device));
-			else if (NM_IS_DEVICE_VLAN (device))
-				hwaddr = nm_device_vlan_get_hw_address (NM_DEVICE_VLAN (device));
-			else if (NM_IS_DEVICE_BRIDGE (device))
-				hwaddr = nm_device_bridge_get_hw_address (NM_DEVICE_BRIDGE (device));
+		if (!strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[0].name)) {
+			tmpl = nmc_fields_dev_show_general;
+			tmpl_len = sizeof (nmc_fields_dev_show_general);
+			nmc->print_fields.indices = parse_output_fields (section_fld ? section_fld : NMC_FIELDS_DEV_SHOW_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);
 
 			state_str = g_strdup_printf ("%d (%s)", state, nmc_device_state_to_string (state));
 			reason_str = g_strdup_printf ("%d (%s)", reason, nmc_device_reason_to_string (reason));
-
-			nmc->allowed_fields[0].value = nmc_fields_dev_list_sections[0].name;  /* "GENERAL"*/
-			nmc->allowed_fields[1].value = nm_device_get_iface (device);
-			nmc->allowed_fields[2].value = device_type_to_string (device);
-			nmc->allowed_fields[3].value = nm_device_get_vendor (device);
-			nmc->allowed_fields[4].value = nm_device_get_product (device);
-			nmc->allowed_fields[5].value = nm_device_get_driver (device) ? nm_device_get_driver (device) : _("(unknown)");
-			nmc->allowed_fields[6].value = nm_device_get_driver_version (device);
-			nmc->allowed_fields[7].value = nm_device_get_firmware_version (device);
-			nmc->allowed_fields[8].value = hwaddr ? hwaddr : _("(unknown)");
-			nmc->allowed_fields[9].value = state_str;
-			nmc->allowed_fields[10].value = reason_str;
-			nmc->allowed_fields[11].value = nm_device_get_udi (device);
-			nmc->allowed_fields[12].value = nm_device_get_ip_iface (device);
-			nmc->allowed_fields[13].value = nm_device_get_managed (device) ? _("yes") : _("no");
-			nmc->allowed_fields[14].value = nm_device_get_autoconnect (device) ? _("yes") : _("no");
-			nmc->allowed_fields[15].value = nm_device_get_firmware_missing (device) ? _("yes") : _("no");
-			nmc->allowed_fields[16].value = (acon = nm_device_get_active_connection (device)) ?
-			                                   nm_object_get_path (NM_OBJECT (acon)) : _("not connected");
-
-			nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-			print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
-			g_free (state_str);
-			g_free (reason_str);
+			hwaddr = nm_device_get_hw_address (device);
+			mtu_str = g_strdup_printf ("%u", nm_device_get_mtu (device));
+			acon = nm_device_get_active_connection (device);
+
+			arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+			set_val_strc (arr, 0, nmc_fields_dev_show_sections[0].name);  /* "GENERAL"*/
+			set_val_strc (arr, 1, nm_device_get_iface (device));
+			set_val_strc (arr, 2, nm_device_get_type_description (device));
+			set_val_strc (arr, 3, nm_device_get_vendor (device));
+			set_val_strc (arr, 4, nm_device_get_product (device));
+			set_val_strc (arr, 5, nm_device_get_driver (device) ? nm_device_get_driver (device) : _("(unknown)"));
+			set_val_strc (arr, 6, nm_device_get_driver_version (device));
+			set_val_strc (arr, 7, nm_device_get_firmware_version (device));
+			set_val_strc (arr, 8, hwaddr ? hwaddr : _("(unknown)"));
+			set_val_str  (arr, 9, mtu_str);
+			set_val_str  (arr, 10, state_str);
+			set_val_str  (arr, 11, reason_str);
+			set_val_strc (arr, 12, nm_device_get_udi (device));
+			set_val_strc (arr, 13, nm_device_get_ip_iface (device));
+			set_val_strc (arr, 14, nm_device_get_managed (device) ? _("yes") : _("no"));
+			set_val_strc (arr, 15, nm_device_get_autoconnect (device) ? _("yes") : _("no"));
+			set_val_strc (arr, 16, nm_device_get_firmware_missing (device) ? _("yes") : _("no"));
+			set_val_strc (arr, 17, get_active_connection_id (device));
+			set_val_strc (arr, 18, acon ? nm_active_connection_get_uuid (acon) : NULL);
+			set_val_strc (arr, 19, acon ? nm_object_get_path (NM_OBJECT (acon)) : NULL);
+			g_ptr_array_add (nmc->output_data, arr);
+
+			print_data (nmc);  /* Print all data */
 			was_output = TRUE;
 		}
 
 		/* section CAPABILITIES */
-		if (!strcasecmp (nmc_fields_dev_list_sections[section_idx].name, nmc_fields_dev_list_sections[1].name)) {
-			nmc->allowed_fields = nmc_fields_dev_list_cap;
-			nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-			nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_DEV_LIST_CAP_ALL, nmc->allowed_fields, NULL);
-			print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
+		if (!strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[1].name)) {
+			tmpl = nmc_fields_dev_show_cap;
+			tmpl_len = sizeof (nmc_fields_dev_show_cap);
+			nmc->print_fields.indices = parse_output_fields (section_fld ? section_fld : NMC_FIELDS_DEV_SHOW_CAP_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);
 
 			caps = nm_device_get_capabilities (device);
 			speed = 0;
@@ -656,20 +829,18 @@ show_device_info (gpointer data, gpointer user_data)
 				speed = nm_device_wifi_get_bitrate (NM_DEVICE_WIFI (device));
 				speed /= 1000;
 			}
-			if (speed)
-				speed_str = g_strdup_printf (_("%u Mb/s"), speed);
+			speed_str = speed ? g_strdup_printf (_("%u Mb/s"), speed) : g_strdup (_("unknown"));
 
-			nmc->allowed_fields[0].value = nmc_fields_dev_list_sections[1].name;  /* "CAPABILITIES" */
-			nmc->allowed_fields[1].value = (caps & NM_DEVICE_CAP_CARRIER_DETECT) ? _("yes") : _("no");
-			nmc->allowed_fields[2].value = speed_str ? speed_str : _("unknown");
+			arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+			set_val_strc (arr, 0, nmc_fields_dev_show_sections[1].name);  /* "CAPABILITIES" */
+			set_val_strc (arr, 1, (caps & NM_DEVICE_CAP_CARRIER_DETECT) ? _("yes") : _("no"));
+			set_val_str  (arr, 2, speed_str);
+			g_ptr_array_add (nmc->output_data, arr);
 
-			nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-			print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
-			g_free (speed_str);
+			print_data (nmc);  /* Print all data */
 			was_output = TRUE;
 		}
 
-
 		/* Wireless specific information */
 		if ((NM_IS_DEVICE_WIFI (device))) {
 			NMDeviceWifiCapabilities wcaps;
@@ -678,167 +849,177 @@ show_device_info (gpointer data, gpointer user_data)
 			const GPtrArray *aps;
 
 			/* section WIFI-PROPERTIES */
-			if (!strcasecmp (nmc_fields_dev_list_sections[section_idx].name, nmc_fields_dev_list_sections[2].name)) {
+			if (!strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[2].name)) {
 				wcaps = nm_device_wifi_get_capabilities (NM_DEVICE_WIFI (device));
 
-				nmc->allowed_fields = nmc_fields_dev_list_wifi_prop;
-				nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-				nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_DEV_LIST_WIFI_PROP_ALL, nmc->allowed_fields, NULL);
-				print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
-
-				nmc->allowed_fields[0].value = nmc_fields_dev_list_sections[2].name;  /* "WIFI-PROPERTIES" */
-				nmc->allowed_fields[1].value = (wcaps & (NM_WIFI_DEVICE_CAP_CIPHER_WEP40 | NM_WIFI_DEVICE_CAP_CIPHER_WEP104)) ? _("yes") : _("no");
-				nmc->allowed_fields[2].value = (wcaps & NM_WIFI_DEVICE_CAP_WPA) ? _("yes") : _("no");
-				nmc->allowed_fields[3].value = (wcaps & NM_WIFI_DEVICE_CAP_RSN) ? _("yes") : _("no");
-				nmc->allowed_fields[4].value = (wcaps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP) ? _("yes") : _("no");
-				nmc->allowed_fields[5].value = (wcaps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP) ? _("yes") : _("no");
-				nmc->allowed_fields[6].value = (wcaps & NM_WIFI_DEVICE_CAP_AP) ? _("yes") : _("no");
-				nmc->allowed_fields[7].value = (wcaps & NM_WIFI_DEVICE_CAP_ADHOC) ? _("yes") : _("no");
-
-				nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-				print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+				tmpl = nmc_fields_dev_show_wifi_prop;
+				tmpl_len = sizeof (nmc_fields_dev_show_wifi_prop);
+				nmc->print_fields.indices = parse_output_fields (section_fld ? section_fld : NMC_FIELDS_DEV_SHOW_WIFI_PROP_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);
+
+				arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+				set_val_strc (arr, 0, nmc_fields_dev_show_sections[2].name);  /* "WIFI-PROPERTIES" */
+				set_val_strc (arr, 1, (wcaps & (NM_WIFI_DEVICE_CAP_CIPHER_WEP40 | NM_WIFI_DEVICE_CAP_CIPHER_WEP104)) ?
+				                        _("yes") : _("no"));
+				set_val_strc (arr, 2, (wcaps & NM_WIFI_DEVICE_CAP_WPA) ? _("yes") : _("no"));
+				set_val_strc (arr, 3, (wcaps & NM_WIFI_DEVICE_CAP_RSN) ? _("yes") : _("no"));
+				set_val_strc (arr, 4, (wcaps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP) ? _("yes") : _("no"));
+				set_val_strc (arr, 5, (wcaps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP) ? _("yes") : _("no"));
+				set_val_strc (arr, 6, (wcaps & NM_WIFI_DEVICE_CAP_AP) ? _("yes") : _("no"));
+				set_val_strc (arr, 7, (wcaps & NM_WIFI_DEVICE_CAP_ADHOC) ? _("yes") : _("no"));
+				g_ptr_array_add (nmc->output_data, arr);
+
+				print_data (nmc);  /* Print all data */
 				was_output = TRUE;
 			}
 
 			/* section AP */
-			if (!strcasecmp (nmc_fields_dev_list_sections[section_idx].name, nmc_fields_dev_list_sections[3].name)) {
+			if (!strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[3].name)) {
 				if (state == NM_DEVICE_STATE_ACTIVATED) {
 					active_ap = nm_device_wifi_get_active_access_point (NM_DEVICE_WIFI (device));
 					active_bssid = active_ap ? nm_access_point_get_bssid (active_ap) : NULL;
 				}
 
-				nmc->allowed_fields = nmc_fields_dev_wifi_list;
-				nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-				nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_DEV_WIFI_LIST_FOR_DEV_LIST, nmc->allowed_fields, NULL);
-				print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
+				tmpl = nmc_fields_dev_wifi_list;
+				tmpl_len = sizeof (nmc_fields_dev_wifi_list);
+				nmc->print_fields.indices = parse_output_fields (section_fld ? section_fld : NMC_FIELDS_DEV_WIFI_LIST_FOR_DEV_LIST,
+				                                                 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);
 
-				nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
 				info = g_malloc0 (sizeof (APInfo));
 				info->nmc = nmc;
 				info->index = 1;
+				info->output_flags = NMC_OF_FLAG_SECTION_PREFIX;
 				info->active_bssid = active_bssid;
 				info->device = nm_device_get_iface (device);
 				aps = nm_device_wifi_get_access_points (NM_DEVICE_WIFI (device));
 				if (aps && aps->len)
-					g_ptr_array_foreach ((GPtrArray *) aps, detail_access_point, (gpointer) info);
+					g_ptr_array_foreach ((GPtrArray *) aps, fill_output_access_point, (gpointer) info);
 				g_free (info);
+				print_data (nmc);  /* Print all data */
 				was_output = TRUE;
 			}
 		} else if (NM_IS_DEVICE_ETHERNET (device)) {
 			/* WIRED-PROPERTIES */
-			if (!strcasecmp (nmc_fields_dev_list_sections[section_idx].name, nmc_fields_dev_list_sections[4].name)) {
-				nmc->allowed_fields = nmc_fields_dev_list_wired_prop;
-				nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-				nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_DEV_LIST_WIRED_PROP_ALL, nmc->allowed_fields, NULL);
-				print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
-
-				nmc->allowed_fields[0].value = nmc_fields_dev_list_sections[4].name;  /* "WIRED-PROPERTIES" */
-				nmc->allowed_fields[1].value = (nm_device_ethernet_get_carrier (NM_DEVICE_ETHERNET (device))) ? _("on") : _("off");
-
-				nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-				print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+			if (!strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[4].name)) {
+				tmpl = nmc_fields_dev_show_wired_prop;
+				tmpl_len = sizeof (nmc_fields_dev_show_wired_prop);
+				nmc->print_fields.indices = parse_output_fields (section_fld ? section_fld : NMC_FIELDS_DEV_SHOW_WIRED_PROP_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);
+
+				arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+				set_val_strc (arr, 0, nmc_fields_dev_show_sections[4].name);  /* "WIRED-PROPERTIES" */
+				set_val_strc (arr, 1, (nm_device_ethernet_get_carrier (NM_DEVICE_ETHERNET (device))) ?
+				                        _("on") : _("off"));
+				g_ptr_array_add (nmc->output_data, arr);
+
+				print_data (nmc);  /* Print all data */
 				was_output = TRUE;
 			}
 		}
 #if WITH_WIMAX
 		else if (NM_IS_DEVICE_WIMAX (device)) {
 			/* WIMAX-PROPERTIES */
-			if (!strcasecmp (nmc_fields_dev_list_sections[section_idx].name, nmc_fields_dev_list_sections[5].name)) {
+			if (!strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[5].name)) {
 				char *cfreq = NULL, *rssi = NULL, *cinr = NULL, *txpow = NULL;
 				guint tmp_uint;
 				gint tmp_int;
-				const char *bsid;
-
-				nmc->allowed_fields = nmc_fields_dev_list_wimax_prop;
-				nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-				nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_DEV_LIST_WIMAX_PROP_ALL, nmc->allowed_fields, NULL);
-				print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
 
-				nmc->allowed_fields[0].value = nmc_fields_dev_list_sections[5].name;  /* "WIMAX-PROPERTIES" */
+				/* Field names */
+				tmpl = nmc_fields_dev_show_wimax_prop;
+				tmpl_len = sizeof (nmc_fields_dev_show_wimax_prop);
+				nmc->print_fields.indices = parse_output_fields (section_fld ? section_fld : NMC_FIELDS_DEV_SHOW_WIMAX_PROP_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);
 
 				/* Center frequency */
 				tmp_uint = nm_device_wimax_get_center_frequency (NM_DEVICE_WIMAX (device));
 				if (tmp_uint)
 					cfreq = g_strdup_printf ("%'.1f MHz", (double) tmp_uint / 1000.0);
-				nmc->allowed_fields[1].value = cfreq ? cfreq : "";
 
 				/* RSSI */
 				tmp_int = nm_device_wimax_get_rssi (NM_DEVICE_WIMAX (device));
 				if (tmp_int)
 					rssi = g_strdup_printf ("%d dBm", tmp_int);
-				nmc->allowed_fields[2].value = rssi ? rssi : "";
 
 				/* CINR */
 				tmp_int = nm_device_wimax_get_cinr (NM_DEVICE_WIMAX (device));
 				if (tmp_int)
 					cinr = g_strdup_printf ("%d dB", tmp_int);
-				nmc->allowed_fields[3].value = cinr ? cinr : "";
 
 				/* TX Power */
 				tmp_int = nm_device_wimax_get_tx_power (NM_DEVICE_WIMAX (device));
 				if (tmp_int)
 					txpow = g_strdup_printf ("%'.2f dBm", (float) tmp_int / 2.0);
-				nmc->allowed_fields[4].value = txpow ? txpow : "";
 
-				/* BSID */
-				bsid = nm_device_wimax_get_bsid (NM_DEVICE_WIMAX (device));
-				nmc->allowed_fields[5].value = bsid ? bsid : "";
+				arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+				set_val_strc (arr, 0, nmc_fields_dev_show_sections[5].name);  /* "WIMAX-PROPERTIES" */
+				set_val_str  (arr, 1, cfreq);
+				set_val_str  (arr, 2, rssi);
+				set_val_str  (arr, 3, cinr);
+				set_val_str  (arr, 4, txpow);
+				set_val_strc (arr, 5, nm_device_wimax_get_bsid (NM_DEVICE_WIMAX (device)));
+				g_ptr_array_add (nmc->output_data, arr);
 
-				nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-				print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+				print_data (nmc);  /* Print all data */
 				was_output = TRUE;
 			}
 
 			/* section NSP */
-			if (!strcasecmp (nmc_fields_dev_list_sections[section_idx].name, nmc_fields_dev_list_sections[6].name)) {
+			if (!strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[6].name)) {
 				const GPtrArray *nsps;
 				int g, idx = 1;
 
-				nmc->allowed_fields = nmc_fields_dev_wimax_list;
-				nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-				nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_DEV_WIMAX_LIST_FOR_DEV_LIST, nmc->allowed_fields, NULL);
-				print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
-
-				nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
+				tmpl = nmc_fields_dev_wimax_list;
+				tmpl_len = sizeof (nmc_fields_dev_wimax_list);
+				nmc->print_fields.indices = parse_output_fields (section_fld ? section_fld : NMC_FIELDS_DEV_WIMAX_LIST_FOR_DEV_LIST,
+				                                                 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);
 
 				nsps = nm_device_wimax_get_nsps (NM_DEVICE_WIMAX (device));
 				for (g = 0; nsps && g < nsps->len; g++) {
 					NMWimaxNsp *nsp = g_ptr_array_index (nsps, g);
 
-					detail_wimax_nsp (nsp, nmc, device, idx++);
+					fill_output_wimax_nsp (nsp, nmc, device, idx++, NMC_OF_FLAG_SECTION_PREFIX);
 				}
+				print_data (nmc);  /* Print all data */
 				was_output = TRUE;
 			}
 		}
 #endif
 
 		/* IP configuration info */
-		if (state == NM_DEVICE_STATE_ACTIVATED) {
-			NMIP4Config *cfg4 = nm_device_get_ip4_config (device);
-			NMIP6Config *cfg6 = nm_device_get_ip6_config (device);
-			NMDHCP4Config *dhcp4 = nm_device_get_dhcp4_config (device);
-			NMDHCP6Config *dhcp6 = nm_device_get_dhcp6_config (device);
-
-			/* IP4 */
-			if (cfg4 && !strcasecmp (nmc_fields_dev_list_sections[section_idx].name, nmc_fields_dev_list_sections[7].name))
-				was_output = print_ip4_config (cfg4, nmc, nmc_fields_dev_list_sections[7].name);
-
-			/* DHCP4 */
-			if (dhcp4 && !strcasecmp (nmc_fields_dev_list_sections[section_idx].name, nmc_fields_dev_list_sections[8].name))
-				was_output = print_dhcp4_config (dhcp4, nmc, nmc_fields_dev_list_sections[8].name);
-
-			/* IP6 */
-			if (cfg6 && !strcasecmp (nmc_fields_dev_list_sections[section_idx].name, nmc_fields_dev_list_sections[9].name))
-				was_output = print_ip6_config (cfg6, nmc, nmc_fields_dev_list_sections[9].name);
-
-			/* DHCP6 */
-			if (dhcp6 && !strcasecmp (nmc_fields_dev_list_sections[section_idx].name, nmc_fields_dev_list_sections[10].name))
-				was_output = print_dhcp6_config (dhcp6, nmc, nmc_fields_dev_list_sections[10].name);
-		}
+		cfg4 = nm_device_get_ip4_config (device);
+		cfg6 = nm_device_get_ip6_config (device);
+		dhcp4 = nm_device_get_dhcp4_config (device);
+		dhcp6 = nm_device_get_dhcp6_config (device);
+
+		/* IP4 */
+		if (cfg4 && !strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[7].name))
+			was_output = print_ip4_config (cfg4, nmc, nmc_fields_dev_show_sections[7].name, section_fld);
+
+		/* DHCP4 */
+		if (dhcp4 && !strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[8].name))
+			was_output = print_dhcp4_config (dhcp4, nmc, nmc_fields_dev_show_sections[8].name, section_fld);
+
+		/* IP6 */
+		if (cfg6 && !strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[9].name))
+			was_output = print_ip6_config (cfg6, nmc, nmc_fields_dev_show_sections[9].name, section_fld);
+
+		/* DHCP6 */
+		if (dhcp6 && !strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[10].name))
+			was_output = print_dhcp6_config (dhcp6, nmc, nmc_fields_dev_show_sections[10].name, section_fld);
 
 		/* Bond-specific information */
 		if ((NM_IS_DEVICE_BOND (device))) {
-			if (!strcasecmp (nmc_fields_dev_list_sections[section_idx].name, nmc_fields_dev_list_sections[11].name)) {
+			if (!strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[11].name)) {
 				const GPtrArray *slaves;
 				GString *bond_slaves_str;
 				int idx;
@@ -857,54 +1038,61 @@ show_device_info (gpointer data, gpointer user_data)
 				if (bond_slaves_str->len > 0)
 					g_string_truncate (bond_slaves_str, bond_slaves_str->len-1);  /* Chop off last space */
 
-				nmc->allowed_fields = nmc_fields_dev_list_bond_prop;
-				nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-				nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_DEV_LIST_BOND_PROP_ALL, nmc->allowed_fields, NULL);
-				print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
+				tmpl = nmc_fields_dev_show_bond_prop;
+				tmpl_len = sizeof (nmc_fields_dev_show_bond_prop);
+				nmc->print_fields.indices = parse_output_fields (section_fld ? section_fld : NMC_FIELDS_DEV_SHOW_BOND_PROP_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);
 
-				nmc->allowed_fields[0].value = nmc_fields_dev_list_sections[11].name;  /* "BOND" */
-				nmc->allowed_fields[1].value = bond_slaves_str->str;
+				arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+				set_val_strc (arr, 0, nmc_fields_dev_show_sections[11].name);  /* "BOND" */
+				set_val_str  (arr, 1, bond_slaves_str->str);
+				g_ptr_array_add (nmc->output_data, arr);
 
-				nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-				print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+				print_data (nmc);  /* Print all data */
 
-				g_string_free (bond_slaves_str, TRUE);
+				g_string_free (bond_slaves_str, FALSE);
 				was_output = TRUE;
 			}
 		}
 
 		/* VLAN-specific information */
 		if ((NM_IS_DEVICE_VLAN (device))) {
-			if (!strcasecmp (nmc_fields_dev_list_sections[section_idx].name, nmc_fields_dev_list_sections[12].name)) {
+			if (!strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[12].name)) {
 				char * vlan_id_str = g_strdup_printf ("%u", nm_device_vlan_get_vlan_id (NM_DEVICE_VLAN (device)));
 
-				nmc->allowed_fields = nmc_fields_dev_list_vlan_prop;
-				nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-				nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_DEV_LIST_VLAN_PROP_ALL, nmc->allowed_fields, NULL);
-				print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
+				tmpl = nmc_fields_dev_show_vlan_prop;
+				tmpl_len = sizeof (nmc_fields_dev_show_vlan_prop);
+				nmc->print_fields.indices = parse_output_fields (section_fld ? section_fld : NMC_FIELDS_DEV_SHOW_VLAN_PROP_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);
 
-				nmc->allowed_fields[0].value = nmc_fields_dev_list_sections[12].name;  /* "VLAN" */
-				nmc->allowed_fields[1].value = vlan_id_str;
+				arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+				set_val_strc (arr, 0, nmc_fields_dev_show_sections[12].name);  /* "VLAN" */
+				set_val_str  (arr, 1, vlan_id_str);
+				g_ptr_array_add (nmc->output_data, arr);
 
-				nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-				print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+				print_data (nmc);  /* Print all data */
 
-				g_free (vlan_id_str);
 				was_output = TRUE;
 			}
 		}
 
 		/* section CONNECTIONS */
-		if (!strcasecmp (nmc_fields_dev_list_sections[section_idx].name, nmc_fields_dev_list_sections[13].name)) {
+		if (!strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[13].name)) {
 			const GPtrArray *avail_cons;
 			GString *ac_paths_str;
 			char **ac_arr = NULL;
 			int i;
 
-			nmc->allowed_fields = nmc_fields_dev_list_connections;
-			nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-			nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_DEV_LIST_CONNECTIONS_ALL, nmc->allowed_fields, NULL);
-			print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
+			tmpl = nmc_fields_dev_show_connections;
+			tmpl_len = sizeof (nmc_fields_dev_show_connections);
+			nmc->print_fields.indices = parse_output_fields (section_fld ? section_fld : NMC_FIELDS_DEV_SHOW_CONNECTIONS_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);
 
 			/* available-connections */
 			avail_cons = nm_device_get_available_connections (device);
@@ -930,47 +1118,59 @@ show_device_info (gpointer data, gpointer user_data)
 			if (ac_paths_str->len > 0)
 				g_string_append_c (ac_paths_str, '}');
 
-			set_val_str (nmc->allowed_fields, 0, nmc_fields_dev_list_sections[13].name);  /* "CONNECTIONS" */
-			set_val_str (nmc->allowed_fields, 1, ac_paths_str->str);
-			set_val_arr (nmc->allowed_fields, 2, (const char **) ac_arr);
+			arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+			set_val_strc (arr, 0, nmc_fields_dev_show_sections[13].name);  /* "CONNECTIONS" */
+			set_val_str  (arr, 1, ac_paths_str->str);
+			set_val_arr  (arr, 2, (ac_arr));
+			g_ptr_array_add (nmc->output_data, arr);
 
-			nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-			print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+			print_data (nmc);  /* Print all data */
 
-			g_string_free (ac_paths_str, TRUE);
-			g_strfreev (ac_arr);
+			g_string_free (ac_paths_str, FALSE);
 			was_output = TRUE;
 		}
 	}
 
 	if (sections_array)
 		g_array_free (sections_array, TRUE);
+	if (fields_in_section)
+		g_ptr_array_free (fields_in_section, TRUE);
+
+	return TRUE;
 }
 
 static void
-show_device_status (NMDevice *device, NmCli *nmc)
+fill_output_device_status (NMDevice *device, NmCli *nmc)
 {
-	nmc->allowed_fields[0].value = nm_device_get_iface (device);
-	nmc->allowed_fields[1].value = device_type_to_string (device);
-	nmc->allowed_fields[2].value = nmc_device_state_to_string (nm_device_get_state (device));
-	nmc->allowed_fields[3].value = nm_object_get_path (NM_OBJECT (device));
-
-	nmc->print_fields.flags &= ~NMC_PF_FLAG_MAIN_HEADER_ADD & ~NMC_PF_FLAG_MAIN_HEADER_ONLY & ~NMC_PF_FLAG_FIELD_NAMES; /* Clear header flags */
-	print_fields (nmc->print_fields, nmc->allowed_fields);
+	NMActiveConnection *ac;
+	NmcOutputField *arr = nmc_dup_fields_array (nmc_fields_dev_status,
+	                                            sizeof (nmc_fields_dev_status),
+	                                            0);
+
+	ac = nm_device_get_active_connection (device);
+
+	set_val_strc (arr, 0, nm_device_get_iface (device));
+	set_val_strc (arr, 1, nm_device_get_type_description (device));
+	set_val_strc (arr, 2, nmc_device_state_to_string (nm_device_get_state (device)));
+	set_val_strc (arr, 3, nm_object_get_path (NM_OBJECT (device)));
+	set_val_strc (arr, 4, get_active_connection_id (device));
+	set_val_strc (arr, 5, ac ? nm_active_connection_get_uuid (ac) : NULL);
+	set_val_strc (arr, 6, ac ? nm_object_get_path (NM_OBJECT (ac)) : NULL);
+
+	g_ptr_array_add (nmc->output_data, arr);
 }
 
 static NMCResultCode
 do_devices_status (NmCli *nmc, int argc, char **argv)
 {
 	GError *error = NULL;
-	const GPtrArray *devices;
+	NMDevice **devices;
 	int i;
 	char *fields_str;
 	char *fields_all =    NMC_FIELDS_DEV_STATUS_ALL;
 	char *fields_common = NMC_FIELDS_DEV_STATUS_COMMON;
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
 
 	while (argc > 0) {
 		fprintf (stderr, _("Unknown parameter: %s\n"), *argv);
@@ -985,45 +1185,41 @@ do_devices_status (NmCli *nmc, int argc, char **argv)
 	else
 		fields_str = nmc->required_fields;
 
-	nmc->allowed_fields = nmc_fields_dev_status;
-	nmc->print_fields.indices = parse_output_fields (fields_str, nmc->allowed_fields, &error);
+	tmpl = nmc_fields_dev_status;
+	tmpl_len = sizeof (nmc_fields_dev_status);
+	nmc->print_fields.indices = parse_output_fields (fields_str, tmpl, FALSE, NULL, &error);
 
 	if (error) {
-		if (error->code == 0)
-			g_string_printf (nmc->return_text, _("Error: 'dev status': %s"), error->message);
-		else
-			g_string_printf (nmc->return_text, _("Error: 'dev status': %s; allowed fields: %s"), error->message, NMC_FIELDS_DEV_STATUS_ALL);
+		g_string_printf (nmc->return_text, _("Error: 'device status': %s"), error->message);
 		g_error_free (error);
 		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
 		goto error;
 	}
 
-	if (!nmc_is_nm_running (nmc, &error)) {
-		if (error) {
-			g_string_printf (nmc->return_text, _("Error: Can't find out if NetworkManager is running: %s."), error->message);
-			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
-			g_error_free (error);
-		} else {
-			g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
-			nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
-		}
+	nmc->get_client (nmc);
+
+	if (!nm_client_get_manager_running (nmc->client)) {
+		g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
+		nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
 		goto error;
 	}
 
 	if (!nmc_versions_match (nmc))
 		goto error;
 
-	/* Print headers */
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ADD | NMC_PF_FLAG_FIELD_NAMES;
+	/* Add headers */
 	nmc->print_fields.header_name = _("Status of devices");
-	print_fields (nmc->print_fields, nmc->allowed_fields);
+	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);
 
-	nmc->get_client (nmc);
-	devices = nm_client_get_devices (nmc->client);
-	for (i = 0; devices && (i < devices->len); i++) {
-		NMDevice *device = g_ptr_array_index (devices, i);
-		show_device_status (device, nmc);
-	}
+	devices = get_devices_sorted (nmc->client);
+	for (i = 0; devices[i]; i++)
+		fill_output_device_status (devices[i], nmc);
+
+	/* Now print all data */
+	print_data (nmc);
+
+	g_free (devices);
 
 	return NMC_RESULT_SUCCESS;
 
@@ -1032,89 +1228,67 @@ error:
 }
 
 static NMCResultCode
-do_devices_list (NmCli *nmc, int argc, char **argv)
+do_devices_show (NmCli *nmc, int argc, char **argv)
 {
-	const GPtrArray *devices;
-	GError *error = NULL;
+	NMDevice **devices = NULL;
 	NMDevice *device = NULL;
-	const char *iface = NULL;
-	gboolean iface_specified = FALSE;
+	const char *ifname = NULL;
 	int i;
+	gboolean ret;
 
-	while (argc > 0) {
-		if (strcmp (*argv, "iface") == 0) {
-			iface_specified = TRUE;
-
-			if (next_arg (&argc, &argv) != 0) {
-				g_string_printf (nmc->return_text, _("Error: '%s' argument is missing."), *(argv-1));
-				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-				goto error;
-			}
-
-			iface = *argv;
-		} else {
-			fprintf (stderr, _("Unknown parameter: %s\n"), *argv);
-		}
-
-		argc--;
-		argv++;
+	if (argc == 1)
+		ifname = *argv;
+	else if (argc > 1) {
+		g_string_printf (nmc->return_text, _("Error: invalid extra argument '%s'."), *(argv+1));
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		goto error;
 	}
 
-	if (!nmc_is_nm_running (nmc, &error)) {
-		if (error) {
-			g_string_printf (nmc->return_text, _("Error: Can't find out if NetworkManager is running: %s."), error->message);
-			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
-			g_error_free (error);
-		} else {
-			g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
-			nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
-		}
+	nmc->get_client (nmc);
+
+	if (!nm_client_get_manager_running (nmc->client)) {
+		g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
+		nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
 		goto error;
 	}
 
 	if (!nmc_versions_match (nmc))
 		goto error;
 
-	nmc->get_client (nmc);
-	devices = nm_client_get_devices (nmc->client);
+	devices = get_devices_sorted (nmc->client);
 
-	if (iface_specified) {
-		for (i = 0; devices && (i < devices->len); i++) {
-			NMDevice *candidate = g_ptr_array_index (devices, i);
+	if (ifname) {
+		/* Interface specified; show details only for the device */
+		for (i = 0; devices[i]; i++) {
+			NMDevice *candidate = devices[i];
 			const char *dev_iface = nm_device_get_iface (candidate);
 
-			if (!g_strcmp0 (dev_iface, iface))
+			if (!g_strcmp0 (dev_iface, ifname))
 				device = candidate;
 		}
 		if (!device) {
-			g_string_printf (nmc->return_text, _("Error: Device '%s' not found."), iface);
-			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+			g_string_printf (nmc->return_text, _("Error: Device '%s' not found."), ifname);
+			nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
 			goto error;
 		}
 		show_device_info (device, nmc);
 	} else {
-		if (devices)
-			g_ptr_array_foreach ((GPtrArray *) devices, show_device_info, nmc);
+		/* Show details for all devices */
+		for (i = 0; devices[i]; i++) {
+			nmc_empty_output_fields (nmc);
+			ret = show_device_info (devices[i], nmc);
+			if (!ret)
+				break;
+			if (devices[i + 1])
+				printf ("\n"); /* Empty line */
+		}
 	}
 
 error:
+	g_free (devices);
 	return nmc->return_value;
 }
 
-static void
-device_state_cb (NMDevice *device, GParamSpec *pspec, gpointer user_data)
-{
-	NmCli *nmc = (NmCli *) user_data;
-	NMDeviceState state;
-
-	state = nm_device_get_state (device);
-
-	if (state == NM_DEVICE_STATE_DISCONNECTED) {
-		g_string_printf (nmc->return_text, _("Success: Device '%s' successfully disconnected."), nm_device_get_iface (device));
-		quit ();
-	}
-}
-
 static gboolean
 timeout_cb (gpointer user_data)
 {
@@ -1139,6 +1313,165 @@ progress_cb (gpointer user_data)
 }
 
 static void
+connected_state_cb (NMDevice *device, GParamSpec *pspec, gpointer user_data)
+{
+	NMActiveConnection *active = (NMActiveConnection *) user_data;
+	NMDeviceState state;
+
+	state = nm_device_get_state (device);
+
+	if (state == NM_DEVICE_STATE_ACTIVATED) {
+		nmc_terminal_erase_line ();
+		printf (_("Device '%s' successfully activated with '%s'.\n"),
+		        nm_device_get_iface (device),
+		        nm_active_connection_get_uuid (active));
+		quit ();
+	}
+}
+
+static void
+connect_device_cb (NMClient *client, NMActiveConnection *active, GError *error, gpointer user_data)
+{
+	NmCli *nmc = (NmCli *) user_data;
+	const GPtrArray *devices;
+	NMDevice *device;
+	NMDeviceState state;
+
+	if (error) {
+		g_string_printf (nmc->return_text, _("Error: Device activation failed: %s"),
+		                 error->message ? error->message : _("(unknown)"));
+		nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
+		quit ();
+	} else {
+		g_assert (active);
+		devices = nm_active_connection_get_devices (active);
+		if (!devices || devices->len == 0) {
+			g_string_printf (nmc->return_text, _("Error: Device activation failed: device was disconnected"));
+			nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
+			quit ();
+			return;
+		}
+
+		device = g_ptr_array_index (devices, 0);
+		state = nm_device_get_state (device);
+
+		if (nmc->nowait_flag || state == NM_DEVICE_STATE_ACTIVATED) {
+			/* Don't want to wait or device already activated */
+			if (state == NM_DEVICE_STATE_ACTIVATED && nmc->print_output == NMC_PRINT_PRETTY) {
+				nmc_terminal_erase_line ();
+				printf (_("Device '%s' has been connected.\n"), nm_device_get_iface (device));
+			}
+			quit ();
+		} else {
+			g_signal_connect (device, "notify::state", G_CALLBACK (connected_state_cb), active);
+			/* Start timer not to loop forever if "notify::state" signal is not issued */
+			g_timeout_add_seconds (nmc->timeout, timeout_cb, nmc);
+		}
+	}
+}
+
+static NMCResultCode
+do_device_connect (NmCli *nmc, int argc, char **argv)
+{
+	NMDevice **devices;
+	NMDevice *device = NULL;
+	const char *ifname = NULL;
+	char *ifname_ask = NULL;
+	int i;
+
+	/* Set default timeout for connect operation. */
+	if (nmc->timeout == -1)
+		nmc->timeout = 90;
+
+	if (argc == 0) {
+		if (nmc->ask)
+			ifname = ifname_ask = nmc_readline (PROMPT_INTERFACE);
+
+		if (!ifname_ask) {
+			g_string_printf (nmc->return_text, _("Error: No interface specified."));
+			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+			goto error;
+		}
+	} else {
+		ifname = *argv;
+	}
+
+	if (!ifname) {
+		g_string_printf (nmc->return_text, _("Error: No interface specified."));
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		goto error;
+	}
+
+	if (next_arg (&argc, &argv) == 0) {
+		g_string_printf (nmc->return_text, _("Error: extra argument not allowed: '%s'."), *argv);
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		goto error;
+	}
+
+	nmc->get_client (nmc);
+	if (!nm_client_get_manager_running (nmc->client)) {
+		g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
+		nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
+		goto error;
+	}
+
+	if (!nmc_versions_match (nmc))
+		goto error;
+
+	devices = get_devices_sorted (nmc->client);
+	for (i = 0; devices[i]; i++) {
+		NMDevice *candidate = devices[i];
+		const char *dev_iface = nm_device_get_iface (candidate);
+
+		if (!g_strcmp0 (dev_iface, ifname))
+			device = candidate;
+	}
+	g_free (devices);
+
+	if (!device) {
+		g_string_printf (nmc->return_text, _("Error: Device '%s' not found."), ifname);
+		nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
+		goto error;
+	}
+
+	/*
+	 * Use nowait_flag instead of should_wait, because exiting has to be postponed
+	 * till connect_device_cb() is called, giving NM time to check our permissions.
+	 */
+	nmc->nowait_flag = (nmc->timeout == 0);
+	nmc->should_wait = TRUE;
+	nm_client_activate_connection (nmc->client,
+	                               NULL,  /* let NM find a connection automatically */
+	                               device,
+	                               NULL,
+	                               connect_device_cb,
+	                               nmc);
+
+	/* Start progress indication */
+	if (nmc->print_output == NMC_PRINT_PRETTY)
+		progress_id = g_timeout_add (120, progress_cb, device);
+
+error:
+	g_free (ifname_ask);
+
+	return nmc->return_value;
+}
+
+static void
+disconnect_state_cb (NMDevice *device, GParamSpec *pspec, gpointer user_data)
+{
+	NmCli *nmc = (NmCli *) user_data;
+	NMDeviceState state;
+
+	state = nm_device_get_state (device);
+
+	if (state == NM_DEVICE_STATE_DISCONNECTED) {
+		g_string_printf (nmc->return_text, _("Success: Device '%s' successfully disconnected."), nm_device_get_iface (device));
+		quit ();
+	}
+}
+
+static void
 disconnect_device_cb (NMDevice *device, GError *error, gpointer user_data)
 {
 	NmCli *nmc = (NmCli *) user_data;
@@ -1156,13 +1489,14 @@ disconnect_device_cb (NMDevice *device, GError *error, gpointer user_data)
 
 		if (nmc->nowait_flag || state == NM_DEVICE_STATE_DISCONNECTED) {
 			/* Don't want to wait or device already disconnected */
-			if (state == NM_DEVICE_STATE_DISCONNECTED && nmc->print_output == NMC_PRINT_PRETTY) {
-				nmc_terminal_erase_line ();
+			if (state == NM_DEVICE_STATE_DISCONNECTED) {
+				if (nmc->print_output == NMC_PRINT_PRETTY)
+					nmc_terminal_erase_line ();
 				printf (_("Device '%s' has been disconnected.\n"), nm_device_get_iface (device));
 			}
 			quit ();
 		} else {
-			g_signal_connect (device, "notify::state", G_CALLBACK (device_state_cb), nmc);
+			g_signal_connect (device, "notify::state", G_CALLBACK (disconnect_state_cb), nmc);
 			/* Start timer not to loop forever if "notify::state" signal is not issued */
 			g_timeout_add_seconds (nmc->timeout, timeout_cb, nmc);
 		}
@@ -1173,93 +1507,72 @@ disconnect_device_cb (NMDevice *device, GError *error, gpointer user_data)
 static NMCResultCode
 do_device_disconnect (NmCli *nmc, int argc, char **argv)
 {
-	const GPtrArray *devices;
-	GError *error = NULL;
+	NMDevice **devices;
 	NMDevice *device = NULL;
-	const char *iface = NULL;
-	gboolean iface_specified = FALSE;
-	gboolean wait = TRUE;
+	const char *ifname = NULL;
+	char *ifname_ask = NULL;
 	int i;
 
-	/* Set default timeout for disconnect operation */
-	nmc->timeout = 10;
+	/* Set default timeout for disconnect operation. */
+	if (nmc->timeout == -1)
+		nmc->timeout = 10;
 
-	while (argc > 0) {
-		if (strcmp (*argv, "iface") == 0) {
-			iface_specified = TRUE;
-
-			if (next_arg (&argc, &argv) != 0) {
-				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
-				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-				goto error;
-			}
-
-			iface = *argv;
-		} else if (strcmp (*argv, "--nowait") == 0) {
-			wait = FALSE;
-		} else if (strcmp (*argv, "--timeout") == 0) {
-			if (next_arg (&argc, &argv) != 0) {
-				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
-				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-				goto error;
-			}
-
-			errno = 0;
-			nmc->timeout = strtol (*argv, NULL, 10);
-			if (errno || nmc->timeout < 0) {
-				g_string_printf (nmc->return_text, _("Error: timeout value '%s' is not valid."), *argv);
-				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-				goto error;
-			}
+	if (argc == 0) {
+		if (nmc->ask)
+			ifname = ifname_ask = nmc_readline (PROMPT_INTERFACE);
 
-		} else {
-			fprintf (stderr, _("Unknown parameter: %s\n"), *argv);
+		if (!ifname_ask) {
+			g_string_printf (nmc->return_text, _("Error: No interface specified."));
+			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+			goto error;
 		}
+	} else {
+		ifname = *argv;
+	}
 
-		argc--;
-		argv++;
+	if (!ifname) {
+		g_string_printf (nmc->return_text, _("Error: No interface specified."));
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		goto error;
 	}
 
-	if (!iface_specified) {
-		g_string_printf (nmc->return_text, _("Error: iface has to be specified."));
+	if (next_arg (&argc, &argv) == 0) {
+		g_string_printf (nmc->return_text, _("Error: extra argument not allowed: '%s'."), *argv);
 		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
 		goto error;
 	}
 
-	if (!nmc_is_nm_running (nmc, &error)) {
-		if (error) {
-			g_string_printf (nmc->return_text, _("Error: Can't find out if NetworkManager is running: %s."), error->message);
-			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
-			g_error_free (error);
-		} else {
-			g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
-			nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
-		}
+	nmc->get_client (nmc);
+	if (!nm_client_get_manager_running (nmc->client)) {
+		g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
+		nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
 		goto error;
 	}
 
 	if (!nmc_versions_match (nmc))
 		goto error;
 
-	nmc->get_client (nmc);
-	devices = nm_client_get_devices (nmc->client);
-	for (i = 0; devices && (i < devices->len); i++) {
-		NMDevice *candidate = g_ptr_array_index (devices, i);
+	devices = get_devices_sorted (nmc->client);
+	for (i = 0; devices[i]; i++) {
+		NMDevice *candidate = devices[i];
 		const char *dev_iface = nm_device_get_iface (candidate);
 
-		if (!g_strcmp0 (dev_iface, iface))
+		if (!g_strcmp0 (dev_iface, ifname))
 			device = candidate;
 	}
+	g_free (devices);
 
 	if (!device) {
-		g_string_printf (nmc->return_text, _("Error: Device '%s' not found."), iface);
-		nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+		g_string_printf (nmc->return_text, _("Error: Device '%s' not found."), ifname);
+		nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
 		goto error;
 	}
 
-	/* Use nowait_flag instead of should_wait because exitting has to be postponed till disconnect_device_cb()
-	 * is called, giving NM time to check our permissions */
-	nmc->nowait_flag = !wait;
+	/*
+	 * Use nowait_flag instead of should_wait, because exiting has to be postponed
+	 * till disconnect_device_cb() is called, giving NM time to check our permissions.
+	 */
+	nmc->nowait_flag = (nmc->timeout == 0);
 	nmc->should_wait = TRUE;
 	nm_device_disconnect (device, disconnect_device_cb, nmc);
 
@@ -1278,20 +1591,29 @@ show_acces_point_info (NMDevice *device, NmCli *nmc)
 	const char *active_bssid = NULL;
 	const GPtrArray *aps;
 	APInfo *info;
+	NmcOutputField *arr;
 
 	if (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED) {
 		active_ap = nm_device_wifi_get_active_access_point (NM_DEVICE_WIFI (device));
 		active_bssid = active_ap ? nm_access_point_get_bssid (active_ap) : NULL;
 	}
 
+	arr = nmc_dup_fields_array (nmc_fields_dev_wifi_list, sizeof (nmc_fields_dev_wifi_list),
+	                            NMC_OF_FLAG_MAIN_HEADER_ADD | NMC_OF_FLAG_FIELD_NAMES);
+	g_ptr_array_add (nmc->output_data, arr);
+
 	info = g_malloc0 (sizeof (APInfo));
 	info->nmc = nmc;
 	info->index = 1;
+	info->output_flags = 0;
 	info->active_bssid = active_bssid;
 	info->device = nm_device_get_iface (device);
 	aps = nm_device_wifi_get_access_points (NM_DEVICE_WIFI (device));
 	if (aps && aps->len)
-		g_ptr_array_foreach ((GPtrArray *) aps, detail_access_point, (gpointer) info);
+		g_ptr_array_foreach ((GPtrArray *) aps, fill_output_access_point, (gpointer) info);
+
+	print_data (nmc);  /* Print all data */
+	nmc_empty_output_fields (nmc);
 	g_free (info);
 }
 
@@ -1301,27 +1623,27 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv)
 	GError *error = NULL;
 	NMDevice *device = NULL;
 	NMAccessPoint *ap = NULL;
-	const char *iface = NULL;
+	const char *ifname = NULL;
 	const char *bssid_user = NULL;
-	const GPtrArray *devices;
+	NMDevice **devices = NULL;
 	const GPtrArray *aps;
 	APInfo *info;
 	int i, j;
 	char *fields_str;
 	char *fields_all =    NMC_FIELDS_DEV_WIFI_LIST_ALL;
 	char *fields_common = NMC_FIELDS_DEV_WIFI_LIST_COMMON;
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
+	const char *base_hdr = _("Wi-Fi scan list");
 
 	while (argc > 0) {
-		if (strcmp (*argv, "iface") == 0) {
+		if (strcmp (*argv, "ifname") == 0) {
 			if (next_arg (&argc, &argv) != 0) {
 				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
 				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
 				goto error;
 			}
-			iface = *argv;
+			ifname = *argv;
 		} else if (strcmp (*argv, "bssid") == 0 || strcmp (*argv, "hwaddr") == 0) {
 			/* hwaddr is deprecated and will be removed later */
 			if (next_arg (&argc, &argv) != 0) {
@@ -1338,7 +1660,6 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv)
 		argv++;
 	}
 
-
 	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)
@@ -1346,58 +1667,49 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv)
 	else
 		fields_str = nmc->required_fields;
 
-	nmc->allowed_fields = nmc_fields_dev_wifi_list;
-	nmc->print_fields.indices = parse_output_fields (fields_str, nmc->allowed_fields, &error);
+	tmpl = nmc_fields_dev_wifi_list;
+	tmpl_len = sizeof (nmc_fields_dev_wifi_list);
+	nmc->print_fields.indices = parse_output_fields (fields_str, tmpl, FALSE, NULL, &error);
 
 	if (error) {
-		if (error->code == 0)
-			g_string_printf (nmc->return_text, _("Error: 'dev wifi': %s"), error->message);
-		else
-			g_string_printf (nmc->return_text, _("Error: 'dev wifi': %s; allowed fields: %s"), error->message, NMC_FIELDS_DEV_WIFI_LIST_ALL);
+		g_string_printf (nmc->return_text, _("Error: 'device wifi': %s"), error->message);
 		g_error_free (error);
 		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
 		goto error;
 	}
 
-	if (!nmc_is_nm_running (nmc, &error)) {
-		if (error) {
-			g_string_printf (nmc->return_text, _("Error: Can't find out if NetworkManager is running: %s."), error->message);
-			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
-			g_error_free (error);
-		} else {
-			g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
-			nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
-		}
+	nmc->get_client (nmc);
+
+	if (!nm_client_get_manager_running (nmc->client)) {
+		g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
+		nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
 		goto error;
 	}
 
 	if (!nmc_versions_match (nmc))
 		goto error;
 
-	/* Print headers */
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ADD | NMC_PF_FLAG_FIELD_NAMES;
-	nmc->print_fields.header_name = _("WiFi scan list");
-
-	nmc->get_client (nmc);
-	devices = nm_client_get_devices (nmc->client);
-	if (iface) {
+	devices = get_devices_sorted (nmc->client);
+	if (ifname) {
 		/* Device specified - list only APs of this interface */
-		for (i = 0; devices && (i < devices->len); i++) {
-			NMDevice *candidate = g_ptr_array_index (devices, i);
+		for (i = 0; devices[i]; i++) {
+			NMDevice *candidate = devices[i];
 			const char *dev_iface = nm_device_get_iface (candidate);
 
-			if (!g_strcmp0 (dev_iface, iface)) {
+			if (!g_strcmp0 (dev_iface, ifname)) {
 				device = candidate;
 				break;
 			}
 		}
-
 		if (!device) {
-			g_string_printf (nmc->return_text, _("Error: Device '%s' not found."), iface);
-			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+			g_string_printf (nmc->return_text, _("Error: Device '%s' not found."), ifname);
+			nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
 			goto error;
 		}
 
+		/* Main header name */
+		nmc->print_fields.header_name = (char *) construct_header_name (base_hdr, ifname);
+
 		if (NM_IS_DEVICE_WIFI (device)) {
 			if (bssid_user) {
 				/* Specific AP requested - list only that */
@@ -1413,38 +1725,50 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv)
 					g_free (bssid_up);
 				}
 				if (!ap) {
-					g_string_printf (nmc->return_text, _("Error: Access point with bssid '%s' not found."), bssid_user);
-					nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+					g_string_printf (nmc->return_text, _("Error: Access point with bssid '%s' not found."),
+					                 bssid_user);
+					nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
 					goto error;
 				}
+				/* Add headers (field names) */
+				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);
+
 				info = g_malloc0 (sizeof (APInfo));
 				info->nmc = nmc;
 				info->index = 1;
+				info->output_flags = 0;
 				info->active_bssid = NULL;
 				info->device = nm_device_get_iface (device);
-				print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
-				detail_access_point (ap, info);
+
+				fill_output_access_point (ap, info);
+
+				print_data (nmc);  /* Print all data */
 				g_free (info);
 			} else {
-				print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
 				show_acces_point_info (device, nmc);
 			}
 		} else {
-			g_string_printf (nmc->return_text, _("Error: Device '%s' is not a WiFi device."), iface);
+			g_string_printf (nmc->return_text, _("Error: Device '%s' is not a Wi-Fi device."), ifname);
 			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
 			goto error;
 		}
 	} else {
 		/* List APs for all devices */
-		print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
 		if (bssid_user) {
 			/* Specific AP requested - list only that */
-			for (i = 0; devices && (i < devices->len); i++) {
-				NMDevice *dev = g_ptr_array_index (devices, i);
+			for (i = 0; devices[i]; i++) {
+				NMDevice *dev = devices[i];
 
 				if (!NM_IS_DEVICE_WIFI (dev))
 					continue;
 
+				/* Main header name */
+				nmc->print_fields.header_name = (char *) construct_header_name (base_hdr, nm_device_get_iface (dev));
+
+				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);
+
 				aps = nm_device_wifi_get_access_points (NM_DEVICE_WIFI (dev));
 				for (j = 0; aps && (j < aps->len); j++) {
 					char *bssid_up;
@@ -1458,22 +1782,30 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv)
 						info = g_malloc0 (sizeof (APInfo));
 						info->nmc = nmc;
 						info->index = 1;
+						info->output_flags = 0;
 						info->active_bssid = NULL;
 						info->device = nm_device_get_iface (dev);
-						detail_access_point (ap, info);
+						fill_output_access_point (ap, info);
 						g_free (info);
 					}
 					g_free (bssid_up);
 				}
+				print_data (nmc);  /* Print all data */
+				nmc_empty_output_fields (nmc);
 			}
 			if (!ap) {
-				g_string_printf (nmc->return_text, _("Error: Access point with bssid '%s' not found."), bssid_user);
-				nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+				g_string_printf (nmc->return_text, _("Error: Access point with bssid '%s' not found."),
+				                 bssid_user);
+				nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
 				goto error;
 			}
 		} else {
-			for (i = 0; devices && (i < devices->len); i++) {
-				NMDevice *dev = g_ptr_array_index (devices, i);
+			for (i = 0; devices[i]; i++) {
+				NMDevice *dev = devices[i];
+
+				/* Main header name */
+				nmc->print_fields.header_name = (char *) construct_header_name (base_hdr,
+				                                                                nm_device_get_iface (dev));
 				if (NM_IS_DEVICE_WIFI (dev))
 					show_acces_point_info (dev, nmc);
 			}
@@ -1481,6 +1813,7 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv)
 	}
 
 error:
+	g_free (devices);
 	return nmc->return_value;
 }
 
@@ -1494,13 +1827,12 @@ monitor_device_state_cb (NMDevice *device, GParamSpec *pspec, gpointer user_data
 	state = nm_device_get_state_reason (device, &reason);
 
 	if (state == NM_DEVICE_STATE_ACTIVATED) {
-		if (nmc->print_output == NMC_PRINT_PRETTY) {
-			NMActiveConnection *active = nm_device_get_active_connection (device);
+		NMActiveConnection *active = nm_device_get_active_connection (device);
 
+		if (nmc->print_output == NMC_PRINT_PRETTY)
 			nmc_terminal_erase_line ();
-			printf (_("Connection with UUID '%s' created and activated on device '%s'\n"),
-			        nm_active_connection_get_uuid (active), nm_device_get_iface (device));
-		}
+		printf (_("Connection with UUID '%s' created and activated on device '%s'\n"),
+		        nm_active_connection_get_uuid (active), nm_device_get_iface (device));
 		quit ();
 	} else if (state == NM_DEVICE_STATE_FAILED) {
 		g_string_printf (nmc->return_text, _("Error: Connection activation failed: (%d) %s."),
@@ -1543,7 +1875,9 @@ add_and_activate_cb (NMClient *client,
 
 		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 && nmc->print_output == NMC_PRINT_PRETTY) {
+			if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
+				if (nmc->print_output == NMC_PRINT_PRETTY)
+					nmc_terminal_erase_line ();
 				printf (_("Connection with UUID '%s' created and activated on device '%s'\n"),
 				        nm_active_connection_get_uuid (active), nm_device_get_iface (device));
 			}
@@ -1617,16 +1951,20 @@ find_ap_on_device (NMDevice *device, GByteArray *bssid, const char *ssid)
 
 		if (ssid) {
 			/* Parameter is SSID */
-			const GByteArray *candidate_ssid = nm_access_point_get_ssid (candidate_ap);
-			char *ssid_tmp = nm_utils_ssid_to_utf8 (candidate_ssid);
+			const GByteArray *candidate_ssid;
 
-			/* Compare SSIDs */
-			if (strcmp (ssid, ssid_tmp) == 0) {
-				ap = candidate_ap;
+			candidate_ssid = nm_access_point_get_ssid (candidate_ap);
+			if (candidate_ssid) {
+				char *ssid_tmp = nm_utils_ssid_to_utf8 (candidate_ssid);
+
+				/* Compare SSIDs */
+				if (strcmp (ssid, ssid_tmp) == 0) {
+					ap = candidate_ap;
+					g_free (ssid_tmp);
+					break;
+				}
 				g_free (ssid_tmp);
-				break;
 			}
-			g_free (ssid_tmp);
 		} else if (bssid) {
 			/* Parameter is BSSID */
 			const char *candidate_bssid = nm_access_point_get_bssid (candidate_ap);
@@ -1650,27 +1988,31 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
 {
 	NMDevice *device = NULL;
 	NMAccessPoint *ap = NULL;
+	NM80211ApFlags ap_flags;
+	NM80211ApSecurityFlags ap_wpa_flags;
+	NM80211ApSecurityFlags ap_rsn_flags;
 	NMConnection *connection = NULL;
 	NMSettingConnection *s_con;
 	NMSettingWireless *s_wifi;
 	NMSettingWirelessSecurity *s_wsec;
 	AddAndActivateInfo *info;
 	const char *param_user = NULL;
-	const char *iface = NULL;
+	const char *ifname = NULL;
 	const char *bssid = NULL;
 	const char *password = NULL;
 	const char *con_name = NULL;
 	gboolean private = FALSE;
-	gboolean wait = TRUE;
 	gboolean wep_passphrase = FALSE;
 	GByteArray *bssid1_arr = NULL;
 	GByteArray *bssid2_arr = NULL;
 	const GPtrArray *devices;
 	int devices_idx;
-	GError *error = NULL;
+	char *ssid_ask = NULL;
+	char *passwd_ask = NULL;
 
-	/* Default timeout for waiting for operation completion */
-	nmc->timeout = 90;
+	/* Set default timeout waiting for operation completion. */
+	if (nmc->timeout == -1)
+		nmc->timeout = 90;
 
 	/* Get the first compulsory argument (SSID or BSSID) */
 	if (argc > 0) {
@@ -1680,20 +2022,27 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
 		argc--;
 		argv++;
 	} else {
-		g_string_printf (nmc->return_text, _("Error: SSID or BSSID are missing."));
-		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-		goto error;
+		if (nmc->ask) {
+			ssid_ask = nmc_readline (_("SSID or BSSID: "));
+			param_user = ssid_ask ? ssid_ask : "";
+			bssid1_arr = nm_utils_hwaddr_atoba (param_user, ARPHRD_ETHER);
+		}
+		if (!ssid_ask) {
+			g_string_printf (nmc->return_text, _("Error: SSID or BSSID are missing."));
+			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+			goto error;
+		}
 	}
 
 	/* Get the rest of the parameters */
 	while (argc > 0) {
-		if (strcmp (*argv, "iface") == 0) {
+		if (strcmp (*argv, "ifname") == 0) {
 			if (next_arg (&argc, &argv) != 0) {
 				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
 				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
 				goto error;
 			}
-			iface = *argv;
+			ifname = *argv;
 		} else if (strcmp (*argv, "bssid") == 0) {
 			if (next_arg (&argc, &argv) != 0) {
 				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
@@ -1739,22 +2088,17 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
 				goto error;
 			}
 			con_name = *argv;
-		} else if (strcmp (*argv, "--private") == 0) {
-			private = TRUE;
-		} else if (strcmp (*argv, "--nowait") == 0) {
-			wait = FALSE;
-		} else if (strcmp (*argv, "--timeout") == 0) {
+		} else if (strcmp (*argv, "private") == 0) {
+			GError *err_tmp = NULL;
 			if (next_arg (&argc, &argv) != 0) {
 				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
 				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
 				goto error;
 			}
-
-			errno = 0;
-			nmc->timeout = strtol (*argv, NULL, 10);
-			if (errno || nmc->timeout < 0) {
-				g_string_printf (nmc->return_text, _("Error: timeout value '%s' is not valid."), *argv);
+			if (!nmc_string_to_bool (*argv, &private, &err_tmp)) {
+				g_string_printf (nmc->return_text, _("Error: %s: %s."), *(argv-1), err_tmp->message);
 				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				g_clear_error (&err_tmp);
 				goto error;
 			}
 		} else {
@@ -1778,31 +2122,26 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
 		goto error;
 	}
 
-	if (!nmc_is_nm_running (nmc, &error)) {
-		if (error) {
-			g_string_printf (nmc->return_text, _("Error: Can't find out if NetworkManager is running: %s."), error->message);
-			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
-			g_error_free (error);
-		} else {
-			g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
-			nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
-		}
+	nmc->get_client (nmc);
+
+	if (!nm_client_get_manager_running (nmc->client)) {
+		g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
+		nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
 		goto error;
 	}
 
 	if (!nmc_versions_match (nmc))
 		goto error;
 
-	nmc->get_client (nmc);
 	devices = nm_client_get_devices (nmc->client);
 
 	/* Find a device to activate the connection on */
 	devices_idx = 0;
-	device = find_wifi_device_by_iface (devices, iface, &devices_idx);
+	device = find_wifi_device_by_iface (devices, ifname, &devices_idx);
 
 	if (!device) {
-		if (iface)
-			g_string_printf (nmc->return_text, _("Error: Device '%s' is not a Wi-Fi device."), iface);
+		if (ifname)
+			g_string_printf (nmc->return_text, _("Error: Device '%s' is not a Wi-Fi device."), ifname);
 		else
 			g_string_printf (nmc->return_text, _("Error: No Wi-Fi device found."));
 		nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
@@ -1811,8 +2150,8 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
 
 	/* Find an AP to connect to */
 	ap = find_ap_on_device (device, bssid1_arr, bssid1_arr ? NULL : param_user);
-	if (!ap && !iface) {
-		/* AP not found. iface was not specified, so try finding the AP on another device. */
+	if (!ap && !ifname) {
+		/* AP not found. ifname was not specified, so try finding the AP on another device. */
 		while ((device = find_wifi_device_by_iface (devices, NULL, &devices_idx)) != NULL) {
 			ap = find_ap_on_device (device, bssid1_arr, bssid1_arr ? NULL : param_user);
 			if (ap)
@@ -1825,7 +2164,7 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
 			g_string_printf (nmc->return_text, _("Error: No network with SSID '%s' found."), param_user);
 		else
 			g_string_printf (nmc->return_text, _("Error: No access point with BSSID '%s' found."), param_user);
-		nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+		nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
 		goto error;
 	}
 
@@ -1853,42 +2192,50 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
 		/* 'bssid' parameter is used to restrict the conenction only to the BSSID */
 		g_object_set (s_wifi, NM_SETTING_WIRELESS_BSSID, bssid2_arr, NULL);
 	}
-	if (password) {
-		NM80211ApFlags flags = nm_access_point_get_flags (ap);
-		NM80211ApSecurityFlags wpa_flags = nm_access_point_get_wpa_flags (ap);
-		NM80211ApSecurityFlags rsn_flags = nm_access_point_get_rsn_flags (ap);
 
-		s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
-		nm_connection_add_setting (connection, NM_SETTING (s_wsec));
+	/* handle password */
+	ap_flags = nm_access_point_get_flags (ap);
+	ap_wpa_flags = nm_access_point_get_wpa_flags (ap);
+	ap_rsn_flags = nm_access_point_get_rsn_flags (ap);
+
+	/* Set password for WEP or WPA-PSK. */
+	if (ap_flags & NM_802_11_AP_FLAGS_PRIVACY) {
+		/* Ask for missing password when one is expected and '--ask' is used */
+		if (!password && nmc->ask)
+			password = passwd_ask = nmc_readline (_("Password: "));
+
+		if (password) {
+			if (!connection)
+				connection = nm_connection_new ();
+			s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
+			nm_connection_add_setting (connection, NM_SETTING (s_wsec));
 
-		/* Set password for WEP or WPA-PSK. */
-		if (flags & NM_802_11_AP_FLAGS_PRIVACY) {
-			if (wpa_flags == NM_802_11_AP_SEC_NONE && rsn_flags == NM_802_11_AP_SEC_NONE) {
+			if (ap_wpa_flags == NM_802_11_AP_SEC_NONE && ap_rsn_flags == NM_802_11_AP_SEC_NONE) {
 				/* WEP */
 				nm_setting_wireless_security_set_wep_key (s_wsec, 0, password);
 				g_object_set (G_OBJECT (s_wsec),
 				              NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE,
 				              wep_passphrase ? NM_WEP_KEY_TYPE_PASSPHRASE: NM_WEP_KEY_TYPE_KEY,
 				              NULL);
-			} else if (   !(wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)
-				   && !(rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) {
+			} else if (   !(ap_wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)
+				   && !(ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) {
 				/* WPA PSK */
 				g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_PSK, password, NULL);
 			}
 		}
-		// FIXME: WPA-Enterprise is not supported yet.
-		// We are not able to determine and fill all the parameters for
-		// 802.1X authentication automatically without user providing
-		// the data. Adding nmcli options for the 8021x setting would
-		// clutter the command. However, that could be solved later by
-		// implementing add/edit connections support for nmcli.
 	}
+	// FIXME: WPA-Enterprise is not supported yet.
+	// We are not able to determine and fill all the parameters for
+	// 802.1X authentication automatically without user providing
+	// the data. Adding nmcli options for the 8021x setting would
+	// clutter the command. However, that could be solved later by
+	// implementing add/edit connections support for nmcli.
 
 	/* nowait_flag indicates user input. should_wait says whether quit in start().
 	 * We have to delay exit after add_and_activate_cb() is called, even if
 	 * the user doesn't want to wait, in order to give NM time to check our
 	 * permissions. */
-	nmc->nowait_flag = !wait;
+	nmc->nowait_flag = (nmc->timeout == 0);
 	nmc->should_wait = TRUE;
 
 	info = g_malloc0 (sizeof (AddAndActivateInfo));
@@ -1907,7 +2254,67 @@ error:
 		g_byte_array_free (bssid1_arr, TRUE);
 	if (bssid2_arr)
 		g_byte_array_free (bssid2_arr, TRUE);
+	g_free (ssid_ask);
+	g_free (passwd_ask);
+
+	return nmc->return_value;
+}
+
+static void
+request_rescan_cb (NMDeviceWifi *device, GError *error, gpointer user_data)
+{
+	NmCli *nmc = (NmCli *) user_data;
+
+	if (error) {
+		g_string_printf (nmc->return_text, _("Error: %s."),
+		                 error->message ? error->message : _("unknown"));
+		nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+	}
+	quit ();
+}
+
+static NMCResultCode
+do_device_wifi_rescan (NmCli *nmc, int argc, char **argv)
+{
+	NMDevice *device;
+	const char *ifname = NULL;
+	const GPtrArray *devices;
+	int devices_idx;
+
+	nmc->should_wait = TRUE;
+
+	/* Get the parameters */
+	if (argc > 0) {
+		if (strcmp (*argv, "ifname") == 0) {
+			if (next_arg (&argc, &argv) != 0) {
+				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				goto error;
+			}
+		}
+		ifname = *argv;
+	}
+
+	/* Find Wi-Fi device to scan on. When no ifname is provided, the first Wi-Fi is used. */
+	nmc->get_client (nmc);
+	devices = nm_client_get_devices (nmc->client);
+	devices_idx = 0;
+	device = find_wifi_device_by_iface (devices, ifname, &devices_idx);
+
+	if (!device) {
+		if (ifname)
+			g_string_printf (nmc->return_text, _("Error: Device '%s' is not a Wi-Fi device."), ifname);
+		else
+			g_string_printf (nmc->return_text, _("Error: No Wi-Fi device found."));
+		nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+		goto error;
+	}
 
+	nm_device_wifi_request_scan_simple (NM_DEVICE_WIFI (device), request_rescan_cb, nmc);
+
+	return nmc->return_value;
+error:
+	nmc->should_wait = FALSE;
 	return nmc->return_value;
 }
 
@@ -1921,8 +2328,10 @@ do_device_wifi (NmCli *nmc, int argc, char **argv)
 			nmc->return_value = do_device_wifi_list (nmc, argc-1, argv+1);
 		} else if (matches (*argv, "connect") == 0) {
 			nmc->return_value = do_device_wifi_connect_network (nmc, argc-1, argv+1);
+		} else if (matches (*argv, "rescan") == 0) {
+			nmc->return_value = do_device_wifi_rescan (nmc, argc-1, argv+1);
 		} else {
-			g_string_printf (nmc->return_text, _("Error: 'dev wifi' command '%s' is not valid."), *argv);
+			g_string_printf (nmc->return_text, _("Error: 'device wifi' command '%s' is not valid."), *argv);
 			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
 		}
 	}
@@ -1936,13 +2345,21 @@ show_nsp_info (NMDevice *device, NmCli *nmc)
 {
 	const GPtrArray *nsps;
 	int i, idx = 1;
+	NmcOutputField *arr;
+
+	/* Add headers (field names) */
+	arr = nmc_dup_fields_array (nmc_fields_dev_wimax_list, sizeof (nmc_fields_dev_wimax_list),
+	                            NMC_OF_FLAG_MAIN_HEADER_ADD | NMC_OF_FLAG_FIELD_NAMES);
+	g_ptr_array_add (nmc->output_data, arr);
 
 	nsps = nm_device_wimax_get_nsps (NM_DEVICE_WIMAX (device));
 	for (i = 0; nsps && i < nsps->len; i++) {
 		NMWimaxNsp *nsp = g_ptr_array_index (nsps, i);
 
-		detail_wimax_nsp (nsp, nmc, device, idx++);
+		fill_output_wimax_nsp (nsp, nmc, device, idx++, 0);
 	}
+	print_data (nmc);  /* Print all data */
+	nmc_empty_output_fields (nmc);
 }
 
 static NMCResultCode
@@ -1951,7 +2368,7 @@ do_device_wimax_list (NmCli *nmc, int argc, char **argv)
 	GError *error = NULL;
 	NMDevice *device = NULL;
 	NMWimaxNsp *nsp = NULL;
-	const char *iface = NULL;
+	const char *ifname = NULL;
 	const char *nsp_user = NULL;
 	const GPtrArray *devices;
 	const GPtrArray *nsps;
@@ -1959,18 +2376,18 @@ do_device_wimax_list (NmCli *nmc, int argc, char **argv)
 	char *fields_str;
 	char *fields_all =    NMC_FIELDS_DEV_WIMAX_LIST_ALL;
 	char *fields_common = NMC_FIELDS_DEV_WIMAX_LIST_COMMON;
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
+	const char *base_hdr = _("WiMAX NSP list");
 
 	while (argc > 0) {
-		if (strcmp (*argv, "iface") == 0) {
+		if (strcmp (*argv, "ifname") == 0) {
 			if (next_arg (&argc, &argv) != 0) {
 				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
 				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
 				goto error;
 			}
-			iface = *argv;
+			ifname = *argv;
 		} else if (strcmp (*argv, "nsp") == 0) {
 			if (next_arg (&argc, &argv) != 0) {
 				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
@@ -1993,58 +2410,50 @@ do_device_wimax_list (NmCli *nmc, int argc, char **argv)
 	else
 		fields_str = nmc->required_fields;
 
-	nmc->allowed_fields = nmc_fields_dev_wimax_list;
-	nmc->print_fields.indices = parse_output_fields (fields_str, nmc->allowed_fields, &error);
+	tmpl = nmc_fields_dev_wimax_list;
+	tmpl_len = sizeof (nmc_fields_dev_wimax_list);
+	nmc->print_fields.indices = parse_output_fields (fields_str, tmpl, FALSE, NULL, &error);
 
 	if (error) {
-		if (error->code == 0)
-			g_string_printf (nmc->return_text, _("Error: 'dev wimax': %s"), error->message);
-		else
-			g_string_printf (nmc->return_text, _("Error: 'dev wimax': %s; allowed fields: %s"), error->message, NMC_FIELDS_DEV_WIMAX_LIST_ALL);
+		g_string_printf (nmc->return_text, _("Error: 'device wimax': %s"), error->message);
 		g_error_free (error);
 		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
 		goto error;
 	}
 
-	if (!nmc_is_nm_running (nmc, &error)) {
-		if (error) {
-			g_string_printf (nmc->return_text, _("Error: Can't find out if NetworkManager is running: %s."), error->message);
-			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
-			g_error_free (error);
-		} else {
-			g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
-			nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
-		}
+	nmc->get_client (nmc);
+
+	if (!nm_client_get_manager_running (nmc->client)) {
+		g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
+		nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
 		goto error;
 	}
 
 	if (!nmc_versions_match (nmc))
 		goto error;
 
-	/* Print headers */
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ADD | NMC_PF_FLAG_FIELD_NAMES;
-	nmc->print_fields.header_name = _("WiMAX NSP list");
-
-	nmc->get_client (nmc);
 	devices = nm_client_get_devices (nmc->client);
-	if (iface) {
+	if (ifname) {
 		/* Device specified - list only NSPs of this interface */
 		for (i = 0; devices && (i < devices->len); i++) {
 			NMDevice *candidate = g_ptr_array_index (devices, i);
 			const char *dev_iface = nm_device_get_iface (candidate);
 
-			if (!g_strcmp0 (dev_iface, iface)) {
+			if (!g_strcmp0 (dev_iface, ifname)) {
 				device = candidate;
 				break;
 			}
 		}
 
 		if (!device) {
-			g_string_printf (nmc->return_text, _("Error: Device '%s' not found."), iface);
-			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+			g_string_printf (nmc->return_text, _("Error: Device '%s' not found."), ifname);
+			nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
 			goto error;
 		}
 
+		/* Main header name */
+		nmc->print_fields.header_name = (char *) construct_header_name (base_hdr, ifname);
+
 		if (NM_IS_DEVICE_WIMAX (device)) {
 			if (nsp_user) {
 				/* Specific NSP requested - list only that */
@@ -2061,23 +2470,24 @@ do_device_wimax_list (NmCli *nmc, int argc, char **argv)
 				}
 				if (!nsp) {
 					g_string_printf (nmc->return_text, _("Error: NSP with name '%s' not found."), nsp_user);
-					nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+					nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
 					goto error;
 				}
-				print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
-				detail_wimax_nsp (nsp, nmc, device, 1);
+				/* Add headers (field names) */
+				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);
+				fill_output_wimax_nsp (nsp, nmc, device, 1, 0);
+				print_data (nmc);  /* Print all data */
 			} else {
-				print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
 				show_nsp_info (device, nmc);
 			}
 		} else {
-			g_string_printf (nmc->return_text, _("Error: Device '%s' is not a WiMAX device."), iface);
+			g_string_printf (nmc->return_text, _("Error: Device '%s' is not a WiMAX device."), ifname);
 			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
 			goto error;
 		}
 	} else {
 		/* List NSPs for all devices */
-		print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
 		if (nsp_user) {
 			/* Specific NSP requested - list only that */
 			for (i = 0; devices && (i < devices->len); i++) {
@@ -2087,6 +2497,12 @@ do_device_wimax_list (NmCli *nmc, int argc, char **argv)
 				if (!NM_IS_DEVICE_WIMAX (dev))
 					continue;
 
+				/* Main header name */
+				nmc->print_fields.header_name = (char *) construct_header_name (base_hdr, nm_device_get_iface (dev));
+
+				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);
+
 				nsps = nm_device_wimax_get_nsps (NM_DEVICE_WIMAX (dev));
 				for (j = 0, nsp = NULL; nsps && (j < nsps->len); j++) {
 					NMWimaxNsp *candidate_nsp = g_ptr_array_index (nsps, j);
@@ -2096,19 +2512,26 @@ do_device_wimax_list (NmCli *nmc, int argc, char **argv)
 					nsp_up = g_ascii_strup (nsp_user, -1);
 					if (!strcmp (nsp_up, candidate_name)) {
 						nsp = candidate_nsp;
-						detail_wimax_nsp (nsp, nmc, dev, idx);
+						fill_output_wimax_nsp (nsp, nmc, dev, idx, 0);
 					}
 					g_free (nsp_up);
 				}
+				print_data (nmc);  /* Print all data */
+				nmc_empty_output_fields (nmc);
 			}
 			if (!nsp) {
 				g_string_printf (nmc->return_text, _("Error: Access point with nsp '%s' not found."), nsp_user);
-				nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+				nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
 				goto error;
 			}
 		} else {
 			for (i = 0; devices && (i < devices->len); i++) {
 				NMDevice *dev = g_ptr_array_index (devices, i);
+
+				/* Main header name */
+				nmc->print_fields.header_name = (char *) construct_header_name (base_hdr,
+				                                                                nm_device_get_iface (dev));
+
 				if (NM_IS_DEVICE_WIMAX (dev))
 					show_nsp_info (dev, nmc);
 			}
@@ -2129,7 +2552,7 @@ do_device_wimax (NmCli *nmc, int argc, char **argv)
 			nmc->return_value = do_device_wimax_list (nmc, argc-1, argv+1);
 		}
 		else {
-			g_string_printf (nmc->return_text, _("Error: 'dev wimax' command '%s' is not valid."), *argv);
+			g_string_printf (nmc->return_text, _("Error: 'device wimax' command '%s' is not valid."), *argv);
 			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
 		}
 	}
@@ -2138,11 +2561,82 @@ do_device_wimax (NmCli *nmc, int argc, char **argv)
 }
 #endif
 
+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;
+}
+
+/* Global variable defined in nmcli.c */
+extern NmCli nm_cli;
+
+static char *
+gen_func_ifnames (const char *text, int state)
+{
+	int i, j = 0;
+	const GPtrArray *devices;
+	const char **ifnames;
+	char *ret;
+
+	nm_cli.get_client (&nm_cli);
+	devices = nm_client_get_devices (nm_cli.client);
+	if (!devices || devices->len < 1)
+		return NULL;
+
+	ifnames = g_new (const char *, devices->len + 1);
+	for (i = 0; i < devices->len; i++) {
+		NMDevice *dev = g_ptr_array_index (devices, i);
+		const char *ifname = nm_device_get_iface (dev);
+		ifnames[j++] = ifname;
+	}
+	ifnames[j] = NULL;
+
+	ret = nmc_rl_gen_func_basic (text, state, ifnames);
+
+	g_free (ifnames);
+	return ret;
+}
+
+static char **
+nmcli_device_tab_completion (const char *text, int start, int end)
+{
+	char **match_array = NULL;
+	rl_compentry_func_t *generator_func = NULL;
+
+	/* Disable readline's default filename completion */
+	rl_attempted_completion_over = 1;
+
+	/* Disable appending space after completion */
+	rl_completion_append_character = '\0';
+
+	if (!is_single_word (rl_line_buffer))
+		return NULL;
+
+	if (g_strcmp0 (rl_prompt, PROMPT_INTERFACE) == 0)
+		generator_func = gen_func_ifnames;
+
+	if (generator_func)
+		match_array = rl_completion_matches (text, generator_func);
+
+	return match_array;
+}
+
 NMCResultCode
 do_devices (NmCli *nmc, int argc, char **argv)
 {
 	GError *error = NULL;
 
+	rl_attempted_completion_function = (rl_completion_func_t *) nmcli_device_tab_completion;
+
 	if (argc == 0) {
 		if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error))
 			goto opt_error;
@@ -2150,36 +2644,62 @@ do_devices (NmCli *nmc, int argc, char **argv)
 	}
 
 	if (argc > 0) {
-		if (matches (*argv, "status") == 0) {
+		if (nmc_arg_is_help (*argv)) {
+			usage ();
+			goto usage_exit;
+		}
+		else if (matches (*argv, "status") == 0) {
+			if (nmc_arg_is_help (*(argv+1))) {
+				usage_device_status ();
+				goto usage_exit;
+			}
 			if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error))
 				goto opt_error;
 			nmc->return_value = do_devices_status (nmc, argc-1, argv+1);
 		}
-		else if (matches (*argv, "list") == 0) {
+		else if (matches (*argv, "show") == 0) {
+			if (nmc_arg_is_help (*(argv+1))) {
+				usage_device_show ();
+				goto usage_exit;
+			}
 			if (!nmc->mode_specified)
-				nmc->multiline_output = TRUE;  /* multiline mode is default for 'dev list' */
-			nmc->return_value = do_devices_list (nmc, argc-1, argv+1);
+				nmc->multiline_output = TRUE;  /* multiline mode is default for 'device show' */
+			nmc->return_value = do_devices_show (nmc, argc-1, argv+1);
+		}
+		else if (matches (*argv, "connect") == 0) {
+			if (nmc_arg_is_help (*(argv+1))) {
+				usage_device_connect ();
+				goto usage_exit;
+			}
+			nmc->return_value = do_device_connect (nmc, argc-1, argv+1);
 		}
 		else if (matches (*argv, "disconnect") == 0) {
+			if (nmc_arg_is_help (*(argv+1))) {
+				usage_device_disconnect ();
+				goto usage_exit;
+			}
 			nmc->return_value = do_device_disconnect (nmc, argc-1, argv+1);
 		}
 		else if (matches (*argv, "wifi") == 0) {
+			if (nmc_arg_is_help (*(argv+1))) {
+				usage_device_wifi ();
+				goto usage_exit;
+			}
 			if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error))
 				goto opt_error;
 			nmc->return_value = do_device_wifi (nmc, argc-1, argv+1);
 		}
 #if WITH_WIMAX
 		else if (matches (*argv, "wimax") == 0) {
+			if (nmc_arg_is_help (*(argv+1))) {
+				usage_device_wimax ();
+				goto usage_exit;
+			}
 			if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error))
 				goto opt_error;
 			nmc->return_value = do_device_wimax (nmc, argc-1, argv+1);
 		}
 #endif
-		else if (   matches (*argv, "help") == 0
-		         || (g_str_has_prefix (*argv, "-") &&  matches ((*argv)+1, "help") == 0)
-		         || (g_str_has_prefix (*argv, "--") && matches ((*argv)+2, "help") == 0)) {
-			usage ();
-		}
 		else {
 			usage ();
 			g_string_printf (nmc->return_text, _("Error: 'dev' command '%s' is not valid."), *argv);
@@ -2187,6 +2707,7 @@ do_devices (NmCli *nmc, int argc, char **argv)
 		}
 	}
 
+usage_exit:
 	return nmc->return_value;
 
 opt_error:
diff --git a/cli/src/network-manager.c b/cli/src/network-manager.c
index 8fb5f6cf..ed074c6d 100644
--- a/cli/src/network-manager.c
+++ b/cli/src/network-manager.c
@@ -14,7 +14,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * (C) Copyright 2010 - 2012 Red Hat, Inc.
+ * (C) Copyright 2010 - 2014 Red Hat, Inc.
  */
 
 #include "config.h"
@@ -32,67 +32,223 @@
 #include "network-manager.h"
 
 
-/* Available fields for 'nm status' */
+/* Available fields for 'general status' */
 static NmcOutputField nmc_fields_nm_status[] = {
-	{"RUNNING",        N_("RUNNING"),         15, NULL, 0},  /* 0 */
-	{"VERSION",        N_("VERSION"),         10, NULL, 0},  /* 1 */
-	{"STATE",          N_("STATE"),           15, NULL, 0},  /* 2 */
-	{"NET-ENABLED",    N_("NET-ENABLED"),     13, NULL, 0},  /* 3 */
-	{"WIFI-HARDWARE",  N_("WIFI-HARDWARE"),   15, NULL, 0},  /* 4 */
-	{"WIFI",           N_("WIFI"),            10, NULL, 0},  /* 5 */
-	{"WWAN-HARDWARE",  N_("WWAN-HARDWARE"),   15, NULL, 0},  /* 6 */
-	{"WWAN",           N_("WWAN"),            10, NULL, 0},  /* 7 */
-	{"WIMAX-HARDWARE", N_("WIMAX-HARDWARE"),  15, NULL, 0},  /* 8 */
-	{"WIMAX",          N_("WIMAX"),           10, NULL, 0},  /* 9 */
-	{NULL,             NULL,                  0, NULL, 0}
+	{"RUNNING",      N_("RUNNING"),      15},  /* 0 */
+	{"VERSION",      N_("VERSION"),      10},  /* 1 */
+	{"STATE",        N_("STATE"),        15},  /* 2 */
+	{"STARTUP",      N_("STARTUP"),      10},  /* 3 */
+	{"CONNECTIVITY", N_("CONNECTIVITY"), 15},  /* 4 */
+	{"NETWORKING",   N_("NETWORKING"),   13},  /* 5 */
+	{"WIFI-HW",      N_("WIFI-HW"),      15},  /* 6 */
+	{"WIFI",         N_("WIFI"),         10},  /* 7 */
+	{"WWAN-HW",      N_("WWAN-HW"),      15},  /* 8 */
+	{"WWAN",         N_("WWAN"),         10},  /* 9 */
+	{"WIMAX-HW",     N_("WIMAX-HW"),     15},  /* 10 */
+	{"WIMAX",        N_("WIMAX"),        10},  /* 11 */
+	{NULL,           NULL,                0}
 };
 #if WITH_WIMAX
-#define NMC_FIELDS_NM_STATUS_ALL     "RUNNING,VERSION,STATE,NET-ENABLED,WIFI-HARDWARE,WIFI,WWAN-HARDWARE,WWAN,WIMAX-HARDWARE,WIMAX"
+#define NMC_FIELDS_NM_STATUS_ALL     "RUNNING,VERSION,STATE,STARTUP,CONNECTIVITY,NETWORKING,WIFI-HW,WIFI,WWAN-HW,WWAN,WIMAX-HW,WIMAX"
+#define NMC_FIELDS_NM_STATUS_SWITCH  "NETWORKING,WIFI-HW,WIFI,WWAN-HW,WWAN,WIMAX-HW,WIMAX"
+#define NMC_FIELDS_NM_STATUS_RADIO   "WIFI-HW,WIFI,WWAN-HW,WWAN,WIMAX-HW,WIMAX"
 #else
-#define NMC_FIELDS_NM_STATUS_ALL     "RUNNING,VERSION,STATE,NET-ENABLED,WIFI-HARDWARE,WIFI,WWAN-HARDWARE,WWAN"
+#define NMC_FIELDS_NM_STATUS_ALL     "RUNNING,VERSION,STATE,STARTUP,CONNECTIVITY,NETWORKING,WIFI-HW,WIFI,WWAN-HW,WWAN"
+#define NMC_FIELDS_NM_STATUS_SWITCH  "NETWORKING,WIFI-HW,WIFI,WWAN-HW,WWAN"
+#define NMC_FIELDS_NM_STATUS_RADIO   "WIFI-HW,WIFI,WWAN-HW,WWAN"
 #endif
-#define NMC_FIELDS_NM_STATUS_COMMON  "RUNNING,STATE,WIFI-HARDWARE,WIFI,WWAN-HARDWARE,WWAN"
-#define NMC_FIELDS_NM_NET_ENABLED    "NET-ENABLED"
+#define NMC_FIELDS_NM_STATUS_COMMON  "STATE,CONNECTIVITY,WIFI-HW,WIFI,WWAN-HW,WWAN"
+#define NMC_FIELDS_NM_NETWORKING     "NETWORKING"
 #define NMC_FIELDS_NM_WIFI           "WIFI"
 #define NMC_FIELDS_NM_WWAN           "WWAN"
 #define NMC_FIELDS_NM_WIMAX          "WIMAX"
+#define NMC_FIELDS_NM_CONNECTIVITY   "CONNECTIVITY"
 
-/* Available fields for 'nm permissions' */
+
+/* Available fields for 'general permissions' */
 static NmcOutputField nmc_fields_nm_permissions[] = {
-	{"PERMISSION",     N_("PERMISSION"),      57, NULL, 0},  /* 0 */
-	{"VALUE",          N_("VALUE"),           10, NULL, 0},  /* 1 */
-	{NULL,             NULL,                  0, NULL, 0}
+	{"PERMISSION", N_("PERMISSION"), 57},  /* 0 */
+	{"VALUE",      N_("VALUE"),      10},  /* 1 */
+	{NULL,         NULL,              0}
 };
 #define NMC_FIELDS_NM_PERMISSIONS_ALL     "PERMISSION,VALUE"
 #define NMC_FIELDS_NM_PERMISSIONS_COMMON  "PERMISSION,VALUE"
 
+/* Available fields for 'general logging' */
+static NmcOutputField nmc_fields_nm_logging[] = {
+	{"LEVEL",   N_("LEVEL"),   10},  /* 0 */
+	{"DOMAINS", N_("DOMAINS"), 70},  /* 1 */
+	{NULL,      NULL,           0}
+};
+#define NMC_FIELDS_NM_LOGGING_ALL     "LEVEL,DOMAINS"
+#define NMC_FIELDS_NM_LOGGING_COMMON  "LEVEL,DOMAINS"
+
 
 /* glib main loop variable - defined in nmcli.c */
 extern GMainLoop *loop;
 
+
+static void
+usage_general (void)
+{
+	fprintf (stderr,
+	         _("Usage: nmcli general { COMMAND | help }\n\n"
+	           "COMMAND := { status | hostname | permissions | logging }\n\n"
+	           "  status\n\n"
+	           "  hostname [<hostname>]\n\n"
+	           "  permissions\n\n"
+	           "  logging [level <log level>] [domains <log domains>]\n\n"));
+}
+
+static void
+usage_general_status (void)
+{
+	fprintf (stderr,
+	         _("Usage: nmcli general status { help }\n"
+	           "\n"
+	           "Show overall status of NetworkManager.\n"
+	           "'status' is the default action, which means 'nmcli gen' calls 'nmcli gen status'\n\n"));
+}
+
+static void
+usage_general_hostname (void)
+{
+	fprintf (stderr,
+	         _("Usage: nmcli general hostname { ARGUMENTS | help }\n"
+	           "\n"
+	           "ARGUMENTS := [<hostname>]\n"
+	           "\n"
+	           "Get or change persistent system hostname.\n"
+	           "With no arguments, this prints currently configured hostname. When you pass\n"
+	           "a hostname, NetworkManager will set it as the new persistent system hostname.\n\n"));
+}
+
+static void
+usage_general_permissions (void)
+{
+	fprintf (stderr,
+	         _("Usage: nmcli general permissions { help }\n"
+	           "\n"
+	           "Show caller permissions for authenticated operations.\n\n"));
+}
+
+static void
+usage_general_logging (void)
+{
+	fprintf (stderr,
+	         _("Usage: nmcli general logging { ARGUMENTS | help }\n"
+	           "\n"
+	           "ARGUMENTS := [level <log level>] [domains <log domains>]\n"
+	           "\n"
+	           "Get or change NetworkManager logging level and domains.\n"
+	           "Without any argument current logging level and domains are shown. In order to\n"
+	           "change logging state, provide level and/or domain. Please refer to the man page\n"
+	           "for the list of possible logging domains.\n\n"));
+}
+
+static void
+usage_networking (void)
+{
+	fprintf (stderr,
+	         _("Usage: nmcli networking { COMMAND | help }\n\n"
+	           "COMMAND := { [ on | off | connectivity ] }\n\n"
+	           "  on\n\n"
+	           "  off\n\n"
+	           "  connectivity [check]\n\n"));
+}
+
+static void
+usage_networking_on (void)
+{
+	fprintf (stderr,
+	         _("Usage: nmcli networking on { help }\n"
+	           "\n"
+	           "Switch networking on.\n\n"));
+}
+
+static void
+usage_networking_off (void)
+{
+	fprintf (stderr,
+	         _("Usage: nmcli networking off { help }\n"
+	           "\n"
+	           "Switch networking off.\n\n"));
+}
+
+static void
+usage_networking_connectivity (void)
+{
+	fprintf (stderr,
+	         _("Usage: nmcli networking connectivity { ARGUMENTS | help }\n"
+	           "\n"
+	           "ARGUMENTS := [check]\n"
+	           "\n"
+	           "Get network connectivity state.\n"
+	           "The optional 'check' argument makes NetworkManager re-check the connectivity.\n\n"));
+
+}
+
 static void
-usage (void)
+usage_radio (void)
 {
 	fprintf (stderr,
-	         _("Usage: nmcli nm { COMMAND | help }\n\n"
+	         _("Usage: nmcli radio { COMMAND | help }\n\n"
 #if WITH_WIMAX
-	         "  COMMAND := { status | permissions | enable | sleep | wifi | wwan | wimax }\n\n"
+	           "COMMAND := { all | wifi | wwan | wimax }\n\n"
+	           "  all | wifi | wwan | wimax [ on | off ]\n\n"
 #else
-	         "  COMMAND := { status | permissions | enable | sleep | wifi | wwan }\n\n"
-#endif
-	         "  status\n"
-	         "  permissions\n"
-	         "  enable [true|false]\n"
-	         "  sleep [true|false]\n"
-	         "  wifi [on|off]\n"
-	         "  wwan [on|off]\n"
-#if WITH_WIMAX
-	         "  wimax [on|off]\n"
+	           "COMMAND := { all | wifi | wwan }\n\n"
+	           "  all | wifi | wwan [ on | off ]\n\n"
 #endif
-	         "\n"
 	         ));
 }
 
+static void
+usage_radio_all (void)
+{
+	fprintf (stderr,
+	         _("Usage: nmcli radio all { ARGUMENTS | help }\n"
+	           "\n"
+	           "ARGUMENTS := [on | off]\n"
+	           "\n"
+	           "Get status of all radio switches, or turn them on/off.\n\n"));
+}
+
+static void
+usage_radio_wifi (void)
+{
+	fprintf (stderr,
+	         _("Usage: nmcli radio wifi { ARGUMENTS | help }\n"
+	           "\n"
+	           "ARGUMENTS := [on | off]\n"
+	           "\n"
+	           "Get status of Wi-Fi radio switch, or turn it on/off.\n\n"));
+}
+
+static void
+usage_radio_wwan (void)
+{
+	fprintf (stderr,
+	         _("Usage: nmcli radio wwan { ARGUMENTS | help }\n"
+	           "\n"
+	           "ARGUMENTS := [on | off]\n"
+	           "\n"
+	           "Get status of mobile broadband radio switch, or turn it on/off.\n\n"));
+}
+
+#if WITH_WIMAX
+static void
+usage_radio_wimax (void)
+{
+	fprintf (stderr,
+	         _("Usage: nmcli radio wimax { ARGUMENTS | help }\n"
+	           "\n"
+	           "ARGUMENTS := [on | off]\n"
+	           "\n"
+	           "Get status of WiMAX radio switch, or turn it on/off.\n\n"));
+}
+#endif
+
 /* quit main loop */
 static void
 quit (void)
@@ -124,11 +280,30 @@ nm_state_to_string (NMState state)
 	}
 }
 
-static NMCResultCode
-show_nm_status (NmCli *nmc)
+static const char *
+nm_connectivity_to_string (NMConnectivityState connectivity)
+{
+	switch (connectivity) {
+	case NM_CONNECTIVITY_NONE:
+		return _("none");
+	case NM_CONNECTIVITY_PORTAL:
+		return _("portal");
+	case NM_CONNECTIVITY_LIMITED:
+		return _("limited");
+	case NM_CONNECTIVITY_FULL:
+		return _("full");
+	case NM_CONNECTIVITY_UNKNOWN:
+	default:
+		return _("unknown");
+	}
+}
+
+static gboolean
+show_nm_status (NmCli *nmc, const char *pretty_header_name, const char *print_flds)
 {
-	gboolean nm_running;
+	gboolean nm_running, startup = FALSE;
 	NMState state = NM_STATE_UNKNOWN;
+	NMConnectivityState connectivity = NM_CONNECTIVITY_UNKNOWN;
 	const char *net_enabled_str;
 	const char *wireless_hw_enabled_str, *wireless_enabled_str;
 	const char *wwan_hw_enabled_str, *wwan_enabled_str;
@@ -137,11 +312,10 @@ show_nm_status (NmCli *nmc)
 #endif
 	GError *error = NULL;
 	const char *fields_str;
-	const char *fields_all =    NMC_FIELDS_NM_STATUS_ALL;
-	const char *fields_common = NMC_FIELDS_NM_STATUS_COMMON;
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+	const char *fields_all =    print_flds ? print_flds : NMC_FIELDS_NM_STATUS_ALL;
+	const char *fields_common = print_flds ? print_flds : NMC_FIELDS_NM_STATUS_COMMON;
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
 
 	if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0)
 		fields_str = fields_common;
@@ -150,26 +324,27 @@ show_nm_status (NmCli *nmc)
 	else
 		fields_str = nmc->required_fields;
 
-	nmc->allowed_fields = nmc_fields_nm_status;
-	nmc->print_fields.indices = parse_output_fields (fields_str, nmc->allowed_fields, &error);
+	tmpl = nmc_fields_nm_status;
+	tmpl_len = sizeof (nmc_fields_nm_status);
+	nmc->print_fields.indices = parse_output_fields (fields_str, tmpl, FALSE, NULL, &error);
 
 	if (error) {
-		if (error->code == 0)
-			g_string_printf (nmc->return_text, _("Error: 'nm status': %s"), error->message);
-		else
-			g_string_printf (nmc->return_text, _("Error: 'nm status': %s; allowed fields: %s"), error->message, NMC_FIELDS_NM_STATUS_ALL);
+		g_string_printf (nmc->return_text, _("Error: only these fields are allowed: %s"), fields_all);
 		g_error_free (error);
 		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-		return nmc->return_value;
+		return FALSE;
 	}
 
-	nm_running = nmc_is_nm_running (nmc, NULL);
+	nmc->get_client (nmc); /* create NMClient */
+
+	nm_running = nm_client_get_manager_running (nmc->client);
 	if (nm_running) {
 		if (!nmc_versions_match (nmc))
-			goto error;
+			return FALSE;
 
-		nmc->get_client (nmc); /* create NMClient */
 		state = nm_client_get_state (nmc->client);
+		startup = nm_client_get_startup (nmc->client);
+		connectivity = nm_client_get_connectivity (nmc->client);
 		net_enabled_str = nm_client_networking_get_enabled (nmc->client) ? _("enabled") : _("disabled");
 		wireless_hw_enabled_str = nm_client_wireless_hardware_get_enabled (nmc->client) ? _("enabled") : _("disabled");
 		wireless_enabled_str = nm_client_wireless_get_enabled (nmc->client) ? _("enabled") : _("disabled");
@@ -189,30 +364,30 @@ show_nm_status (NmCli *nmc)
 #endif
 	}
 
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ADD | NMC_PF_FLAG_FIELD_NAMES;
-	nmc->print_fields.header_name = _("NetworkManager status");
-	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
-
-	nmc->allowed_fields[0].value = nm_running ? _("running") : _("not running");
-	nmc->allowed_fields[1].value = nm_running ? nm_client_get_version (nmc->client) : _("unknown");
-	nmc->allowed_fields[2].value = nm_state_to_string (state);
-	nmc->allowed_fields[3].value = net_enabled_str;
-	nmc->allowed_fields[4].value = wireless_hw_enabled_str;
-	nmc->allowed_fields[5].value = wireless_enabled_str;
-	nmc->allowed_fields[6].value = wwan_hw_enabled_str;
-	nmc->allowed_fields[7].value = wwan_enabled_str;
+	nmc->print_fields.header_name = pretty_header_name ? (char *) pretty_header_name : _("NetworkManager status");
+	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, tmpl_len, 0);
+	set_val_strc (arr, 0, nm_running ? _("running") : _("not running"));
+	set_val_strc (arr, 1, nm_running ? nm_client_get_version (nmc->client) : _("unknown"));
+	set_val_strc (arr, 2, nm_state_to_string (state));
+	set_val_strc (arr, 3, nm_running ? (startup ? _("starting") : _("started")) : _("unknown"));
+	set_val_strc (arr, 4, nm_connectivity_to_string (connectivity));
+	set_val_strc (arr, 5, net_enabled_str);
+	set_val_strc (arr, 6, wireless_hw_enabled_str);
+	set_val_strc (arr, 7, wireless_enabled_str);
+	set_val_strc (arr, 8, wwan_hw_enabled_str);
+	set_val_strc (arr, 9, wwan_enabled_str);
 #if WITH_WIMAX
-	nmc->allowed_fields[8].value = wimax_hw_enabled_str;
-	nmc->allowed_fields[9].value = wimax_enabled_str;
+	set_val_strc (arr, 10, wimax_hw_enabled_str);
+	set_val_strc (arr, 11, wimax_enabled_str);
 #endif
+	g_ptr_array_add (nmc->output_data, arr);
 
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag;
-	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+	print_data (nmc);  /* Print all data */
 
-	return NMC_RESULT_SUCCESS;
-
-error:
-	return nmc->return_value;
+	return TRUE;
 }
 
 #define NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK     "org.freedesktop.NetworkManager.enable-disable-network"
@@ -274,7 +449,7 @@ permission_result_to_string (NMClientPermissionResult perm_result)
 	}
 }
 
-static NMCResultCode
+static gboolean
 show_nm_permissions (NmCli *nmc)
 {
 	NMClientPermission perm;
@@ -282,9 +457,8 @@ show_nm_permissions (NmCli *nmc)
 	const char *fields_str;
 	const char *fields_all =    NMC_FIELDS_NM_PERMISSIONS_ALL;
 	const char *fields_common = NMC_FIELDS_NM_PERMISSIONS_COMMON;
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
 
 	if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0)
 		fields_str = fields_common;
@@ -293,311 +467,451 @@ show_nm_permissions (NmCli *nmc)
 	else
 		fields_str = nmc->required_fields;
 
-	nmc->allowed_fields = nmc_fields_nm_permissions;
-	nmc->print_fields.indices = parse_output_fields (fields_str, nmc->allowed_fields, &error);
+	tmpl = nmc_fields_nm_permissions;
+	tmpl_len = sizeof (nmc_fields_nm_permissions);
+	nmc->print_fields.indices = parse_output_fields (fields_str, tmpl, FALSE, NULL, &error);
 
 	if (error) {
-		if (error->code == 0)
-			g_string_printf (nmc->return_text, _("Error: 'nm permissions': %s"), error->message);
-		else
-			g_string_printf (nmc->return_text, _("Error: 'nm permissions': %s; allowed fields: %s"), error->message, NMC_FIELDS_NM_PERMISSIONS_ALL);
+		g_string_printf (nmc->return_text, _("Error: 'general permissions': %s"), error->message);
 		g_error_free (error);
 		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-		return nmc->return_value;
-	}
-
-	if (!nmc_is_nm_running (nmc, &error)) {
-		if (error) {
-			g_string_printf (nmc->return_text, _("Error: Can't find out if NetworkManager is running: %s."), error->message);
-			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
-			g_error_free (error);
-		} else {
-			g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
-			nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
-		}
-		goto error;
+		return FALSE;
 	}
 
 	nmc->get_client (nmc); /* create NMClient */
 
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ADD | NMC_PF_FLAG_FIELD_NAMES;
+	if (!nm_client_get_manager_running (nmc->client)) {
+		g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
+		nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
+		return FALSE;
+	}
+
 	nmc->print_fields.header_name = _("NetworkManager permissions");
-	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
+	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);
 
 	for (perm = NM_CLIENT_PERMISSION_NONE + 1; perm <= NM_CLIENT_PERMISSION_LAST; perm++) {
 		NMClientPermissionResult perm_result = nm_client_get_permission_result (nmc->client, perm);
 
-		set_val_str (nmc->allowed_fields, 0, permission_to_string (perm));
-		set_val_str (nmc->allowed_fields, 1, permission_result_to_string (perm_result));
-		nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag;
-		print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+		arr = nmc_dup_fields_array (tmpl, tmpl_len, 0);
+		set_val_strc (arr, 0, permission_to_string (perm));
+		set_val_strc (arr, 1, permission_result_to_string (perm_result));
+		g_ptr_array_add (nmc->output_data, arr);
 	}
-	return NMC_RESULT_SUCCESS;
+	print_data (nmc);  /* Print all data */
 
-error:
-	return nmc->return_value;
+	return TRUE;
 }
 
-/* libnm-glib doesn't provide API fro Sleep method - implement D-Bus call ourselves */
-static void networking_set_sleep (NmCli *nmc, gboolean in_sleep)
+static gboolean
+show_general_logging (NmCli *nmc)
 {
-	DBusGConnection *connection = NULL;
-	DBusGProxy *proxy = NULL;
-	GError *err = NULL;
+	char *level = NULL;
+	char *domains = NULL;
+	GError *error = NULL;
+	const char *fields_str;
+	const char *fields_all =    NMC_FIELDS_NM_LOGGING_ALL;
+	const char *fields_common = NMC_FIELDS_NM_LOGGING_COMMON;
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
 
-	connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &err);
-	if (!connection) {
-		g_string_printf (nmc->return_text, _("Error: Couldn't connect to system bus: %s"), err->message);
-		nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
-		g_error_free (err);
-		goto gone;
+	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
+		fields_str = nmc->required_fields;
+
+	tmpl = nmc_fields_nm_logging;
+	tmpl_len = sizeof (nmc_fields_nm_logging);
+	nmc->print_fields.indices = parse_output_fields (fields_str, tmpl, FALSE, NULL, &error);
+
+	if (error) {
+		g_string_printf (nmc->return_text, _("Error: 'general logging': %s"), error->message);
+		g_error_free (error);
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		return FALSE;
 	}
 
-	proxy = dbus_g_proxy_new_for_name (connection,
-	                                   "org.freedesktop.NetworkManager",
-	                                   "/org/freedesktop/NetworkManager",
-	                                   "org.freedesktop.NetworkManager");
-	if (!proxy) {
-		g_string_printf (nmc->return_text, _("Error: Couldn't create D-Bus object proxy."));
-		nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
-		goto gone;
+	nmc->get_client (nmc); /* create NMClient */
+	nm_client_get_logging (nmc->client, &level, &domains, &error);
+	if (error) {
+		g_string_printf (nmc->return_text, _("Error: %s."), error->message);
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		g_error_free (error);
+		return FALSE;
 	}
 
-	if (!dbus_g_proxy_call (proxy, "Sleep", &err, G_TYPE_BOOLEAN, in_sleep, G_TYPE_INVALID, G_TYPE_INVALID)) {
-		g_string_printf (nmc->return_text, _("Error in sleep: %s"), err->message);
+	nmc->print_fields.header_name = _("NetworkManager logging");
+	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, tmpl_len, 0);
+	set_val_str (arr, 0, level);
+	set_val_str (arr, 1, domains);
+	g_ptr_array_add (nmc->output_data, arr);
+
+	print_data (nmc);  /* Print all data */
+
+	return TRUE;
+}
+
+static void
+save_hostname_cb (NMRemoteSettings *settings, GError *error, gpointer user_data)
+{
+	NmCli *nmc = (NmCli *) user_data;
+
+	if (error) {
+		g_string_printf (nmc->return_text, _("Error: failed to set hostname: (%d) %s"),
+		                 error->code, error->message);
 		nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
-		g_error_free (err);
 	}
-
-gone:
-	if (connection) dbus_g_connection_unref (connection);
-	if (proxy) g_object_unref (proxy);
+	quit ();
 }
 
-/* entry point function for global network manager related commands 'nmcli nm' */
+/*
+ * Entry point function for general operations 'nmcli general'
+ */
 NMCResultCode
-do_network_manager (NmCli *nmc, int argc, char **argv)
+do_general (NmCli *nmc, int argc, char **argv)
 {
 	GError *error = NULL;
-	gboolean sleep_flag;
-	gboolean enable_net;
-	gboolean enable_wifi;
-	gboolean enable_wwan;
-#if WITH_WIMAX
-	gboolean enable_wimax;
-#endif
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
 
 	if (argc == 0) {
-		if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error))
-			goto opt_error;
-		nmc->return_value = show_nm_status (nmc);
+		if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error)) {
+			g_string_printf (nmc->return_text, _("Error: %s."), error->message);
+			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+			goto finish;
+		}
+		show_nm_status (nmc, NULL, NULL);
 	}
 
 	if (argc > 0) {
-		if (matches (*argv, "status") == 0) {
-			if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error))
-				goto opt_error;
-			nmc->return_value = show_nm_status (nmc);
+		if (nmc_arg_is_help (*argv)) {
+			usage_general ();
+		}
+		else if (matches (*argv, "status") == 0) {
+			if (nmc_arg_is_help (*(argv+1))) {
+				usage_general_status ();
+				goto finish;
+			}
+			if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error)) {
+				g_string_printf (nmc->return_text, _("Error: %s."), error->message);
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				goto finish;
+			}
+			show_nm_status (nmc, NULL, NULL);
+		}
+		else if (matches (*argv, "hostname") == 0) {
+			NMRemoteSettings *rem_settings;
+
+			if (nmc_arg_is_help (*(argv+1))) {
+				usage_general_hostname ();
+				goto finish;
+			}
+
+			/* get system settings */
+			if (!(rem_settings = nm_remote_settings_new (NULL))) {
+				g_string_printf (nmc->return_text, _("Error: Could not get system settings."));
+				nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+				goto finish;
+			}
+
+			if (next_arg (&argc, &argv) != 0) {
+				/* no arguments -> get hostname */
+				char *hostname = NULL;
+
+				g_object_get (rem_settings, NM_REMOTE_SETTINGS_HOSTNAME, &hostname, NULL);
+				if (hostname)
+					printf ("%s\n", hostname);
+				g_free (hostname);
+			} else {
+				/* hostname provided -> set it */
+				const char *hostname = *argv;
+
+				if (next_arg (&argc, &argv) == 0)
+					printf ("Warning: ignoring extra garbage after '%s' hostname\n", hostname);
+
+				nmc->should_wait = TRUE;
+				nm_remote_settings_save_hostname (rem_settings, hostname, save_hostname_cb, nmc);
+			}
 		}
 		else if (matches (*argv, "permissions") == 0) {
-			if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error))
-				goto opt_error;
-			nmc->return_value = show_nm_permissions (nmc);
+			if (nmc_arg_is_help (*(argv+1))) {
+				usage_general_permissions ();
+				goto finish;
+			}
+			if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error)) {
+				g_string_printf (nmc->return_text, _("Error: %s."), error->message);
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				goto finish;
+			}
+			show_nm_permissions (nmc);
 		}
-		else if (matches (*argv, "enable") == 0) {
+		else if (matches (*argv, "logging") == 0) {
+			if (nmc_arg_is_help (*(argv+1))) {
+				usage_general_logging ();
+				goto finish;
+			}
 			if (next_arg (&argc, &argv) != 0) {
-				/* no argument, show current state of networking */
-				if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error))
-					goto opt_error;
-				if (nmc->required_fields && strcasecmp (nmc->required_fields, "NET-ENABLED")) {
-					g_string_printf (nmc->return_text, _("Error: '--fields' value '%s' is not valid here; allowed fields: %s"),
-					                 nmc->required_fields, NMC_FIELDS_NM_NET_ENABLED);
+				/* no arguments -> get logging level and domains */
+				if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error)) {
+					g_string_printf (nmc->return_text, _("Error: %s."), error->message);
 					nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-					goto end;
+					goto finish;
 				}
-				nmc->allowed_fields = nmc_fields_nm_status;
-				nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_NM_NET_ENABLED, nmc->allowed_fields, NULL);
-				nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ADD | NMC_PF_FLAG_FIELD_NAMES;
-				nmc->print_fields.header_name = _("Networking enabled");
-				print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
-
-				if (nmc_is_nm_running (nmc, NULL)) {
-					nmc->get_client (nmc); /* create NMClient */
-					nmc->allowed_fields[3].value = nm_client_networking_get_enabled (nmc->client) ? _("enabled") : _("disabled");
-				} else
-					nmc->allowed_fields[3].value = _("unknown");
-				nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag;
-				print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+				show_general_logging (nmc);
 			} else {
-				if (!strcmp (*argv, "true"))
-					enable_net = TRUE;
-				else if (!strcmp (*argv, "false"))
-					enable_net = FALSE;
-				else {
-					g_string_printf (nmc->return_text, _("Error: invalid 'enable' parameter: '%s'; use 'true' or 'false'."), *argv);
-					nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-					goto end;
+				/* arguments provided -> set logging level and domains */
+				const char *level = NULL;
+				const char *domains = NULL;
+				nmc_arg_t exp_args[] = { {"level",   TRUE, &level,   TRUE},
+				                         {"domains", TRUE, &domains, TRUE},
+				                         {NULL} };
+
+				if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, &error)) {
+					g_string_assign (nmc->return_text, error->message);
+					nmc->return_value = error->code;
+					goto finish;
 				}
+
 				nmc->get_client (nmc); /* create NMClient */
-				nm_client_networking_set_enabled (nmc->client, enable_net);
+				nm_client_set_logging (nmc->client, level, domains, &error);
+				if (error) {
+					if (g_error_matches (error, DBUS_GERROR, DBUS_GERROR_ACCESS_DENIED))
+						g_string_printf (nmc->return_text, _("Error: access denied to set logging; %s"), error->message);
+					else
+						g_string_printf (nmc->return_text, _("Error: %s"), error->message);
+					nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+					goto finish;
+				}
 			}
 		}
-		else if (matches (*argv, "sleep") == 0) {
+		else {
+			usage_general ();
+			g_string_printf (nmc->return_text, _("Error: 'general' command '%s' is not valid."), *argv);
+			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		}
+	}
+
+finish:
+	if (error)
+		g_error_free (error);
+	return nmc->return_value;
+}
+
+static gboolean
+nmc_switch_show (NmCli *nmc, const char *switch_name, const char *header)
+{
+	g_return_val_if_fail (nmc != NULL, FALSE);
+	g_return_val_if_fail (switch_name != NULL, FALSE);
+
+	if (nmc->required_fields && strcasecmp (nmc->required_fields, switch_name) != 0) {
+		g_string_printf (nmc->return_text, _("Error: '--fields' value '%s' is not valid here (allowed field: %s)"),
+		                 nmc->required_fields, switch_name);
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		return FALSE;
+	}
+	if (nmc->print_output == NMC_PRINT_NORMAL)
+		nmc->print_output = NMC_PRINT_TERSE;
+
+	if (!nmc->required_fields)
+		nmc->required_fields = g_strdup (switch_name);
+	return show_nm_status (nmc, header, NULL);
+}
+
+static gboolean
+nmc_switch_parse_on_off (NmCli *nmc, const char *arg1, const char *arg2, gboolean *res)
+{
+	g_return_val_if_fail (nmc != NULL, FALSE);
+	g_return_val_if_fail (arg1 && arg2, FALSE);
+	g_return_val_if_fail (res != NULL, FALSE);
+
+	if (!strcmp (arg2, "on"))
+		*res = TRUE;
+	else if (!strcmp (arg2, "off"))
+		*res = FALSE;
+	else {
+		g_string_printf (nmc->return_text, _("Error: invalid '%s' argument: '%s' (use on/off)."), arg1, arg2);
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static gboolean
+show_networking_connectivity (NmCli *nmc)
+{
+	return nmc_switch_show (nmc, NMC_FIELDS_NM_CONNECTIVITY, _("Connectivity"));
+}
+
+/*
+ * Entry point function for 'nmcli networking'
+ */
+NMCResultCode
+do_networking (NmCli *nmc, int argc, char **argv)
+{
+	gboolean enable_flag;
+
+	if (argc == 0)
+		nmc_switch_show (nmc, NMC_FIELDS_NM_NETWORKING, _("Networking"));
+	else if (argc > 0) {
+		if (nmc_arg_is_help (*argv)) {
+			usage_networking ();
+		} else if (matches (*argv, "connectivity") == 0) {
+			if (nmc_arg_is_help (*(argv+1))) {
+				usage_networking_connectivity ();
+				goto finish;
+			}
 			if (next_arg (&argc, &argv) != 0) {
-				g_string_printf (nmc->return_text, _("Error: Sleeping status is not exported by NetworkManager."));
-				nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+				/* no arguments -> get current state */
+				show_networking_connectivity (nmc);
+			} else if (matches (*argv, "check") == 0) {
+				GError *error = NULL;
+
+				nmc->get_client (nmc); /* create NMClient */
+				nm_client_check_connectivity (nmc->client, NULL, &error);
+				if (error) {
+					g_string_printf (nmc->return_text, _("Error: %s."), error->message);
+					nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+					g_clear_error (&error);
+				} else
+					show_networking_connectivity (nmc);
 			} else {
-				if (!strcmp (*argv, "true"))
-					sleep_flag = TRUE;
-				else if (!strcmp (*argv, "false"))
-					sleep_flag = FALSE;
-				else {
-					g_string_printf (nmc->return_text, _("Error: invalid 'sleep' parameter: '%s'; use 'true' or 'false'."), *argv);
+				usage_networking ();
+				g_string_printf (nmc->return_text, _("Error: 'networking connectivity' command '%s' is not valid."), *argv);
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+			}
+		} else if (nmc_switch_parse_on_off (nmc, *(argv-1), *argv, &enable_flag)) {
+			if (nmc_arg_is_help (*(argv+1))) {
+				if (enable_flag)
+					usage_networking_on ();
+				else
+					usage_networking_off ();
+				goto finish;
+			}
+
+			nmc->get_client (nmc); /* create NMClient */
+			nm_client_networking_set_enabled (nmc->client, enable_flag);
+		} else {
+			usage_networking ();
+			g_string_printf (nmc->return_text, _("Error: 'networking' command '%s' is not valid."), *argv);
+			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		}
+	}
+
+finish:
+	quit ();
+	return nmc->return_value;
+}
+
+/*
+ * Entry point function for radio switch commands 'nmcli radio'
+ */
+NMCResultCode
+do_radio (NmCli *nmc, int argc, char **argv)
+{
+	GError *error = NULL;
+	gboolean enable_flag;
+
+	if (argc == 0) {
+		if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error)) {
+			g_string_printf (nmc->return_text, _("Error: %s."), error->message);
+			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+			g_error_free (error);
+			goto finish;
+		}
+		show_nm_status (nmc, _("Radio switches"), NMC_FIELDS_NM_STATUS_RADIO);
+	}
+
+	if (argc > 0) {
+		if (nmc_arg_is_help (*argv)) {
+			usage_radio ();
+		}
+		else if (matches (*argv, "all") == 0) {
+			if (nmc_arg_is_help (*(argv+1))) {
+				usage_radio_all ();
+				goto finish;
+			}
+			if (next_arg (&argc, &argv) != 0) {
+				/* no argument, show all radio switches */
+				if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error)) {
+					g_string_printf (nmc->return_text, _("Error: %s."), error->message);
 					nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-					goto end;
+					g_error_free (error);
+					goto finish;
 				}
-				networking_set_sleep (nmc, sleep_flag);
+				show_nm_status (nmc, _("Radio switches"), NMC_FIELDS_NM_STATUS_RADIO);
+			} else {
+				if (!nmc_switch_parse_on_off (nmc, *(argv-1), *argv, &enable_flag))
+					goto finish;
+
+				nmc->get_client (nmc); /* create NMClient */
+				nm_client_wireless_set_enabled (nmc->client, enable_flag);
+				nm_client_wimax_set_enabled (nmc->client, enable_flag);
+				nm_client_wwan_set_enabled (nmc->client, enable_flag);
 			}
 		}
 		else if (matches (*argv, "wifi") == 0) {
+			if (nmc_arg_is_help (*(argv+1))) {
+				usage_radio_wifi ();
+				goto finish;
+			}
 			if (next_arg (&argc, &argv) != 0) {
 				/* no argument, show current WiFi state */
-				if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error))
-					goto opt_error;
-				if (nmc->required_fields && strcasecmp (nmc->required_fields, "WIFI")) {
-					g_string_printf (nmc->return_text, _("Error: '--fields' value '%s' is not valid here; allowed fields: %s"),
-					                 nmc->required_fields, NMC_FIELDS_NM_WIFI);
-					nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-					goto end;
-				}
-				nmc->allowed_fields = nmc_fields_nm_status;
-				nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_NM_WIFI, nmc->allowed_fields, NULL);
-				nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ADD | NMC_PF_FLAG_FIELD_NAMES;
-				nmc->print_fields.header_name = _("WiFi enabled");
-				print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
-
-				if (nmc_is_nm_running (nmc, NULL)) {
-					nmc->get_client (nmc); /* create NMClient */
-					nmc->allowed_fields[5].value = nm_client_wireless_get_enabled (nmc->client) ? _("enabled") : _("disabled");
-				} else
-					nmc->allowed_fields[5].value = _("unknown");
-				nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag;
-				print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+				nmc_switch_show (nmc, NMC_FIELDS_NM_WIFI, _("Wi-Fi radio switch"));
 			} else {
-				if (!strcmp (*argv, "on"))
-					enable_wifi = TRUE;
-				else if (!strcmp (*argv, "off"))
-					enable_wifi = FALSE;
-				else {
-					g_string_printf (nmc->return_text, _("Error: invalid 'wifi' parameter: '%s'."), *argv);
-					nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-					goto end;
-				}
+				if (!nmc_switch_parse_on_off (nmc, *(argv-1), *argv, &enable_flag))
+					goto finish;
+				
 				nmc->get_client (nmc); /* create NMClient */
-				nm_client_wireless_set_enabled (nmc->client, enable_wifi);
+				nm_client_wireless_set_enabled (nmc->client, enable_flag);
 			}
 		}
 		else if (matches (*argv, "wwan") == 0) {
+			if (nmc_arg_is_help (*(argv+1))) {
+				usage_radio_wwan ();
+				goto finish;
+			}
 			if (next_arg (&argc, &argv) != 0) {
-				if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error))
-					goto opt_error;
-				/* no argument, show current WWAN state */
-				if (nmc->required_fields && strcasecmp (nmc->required_fields, "WWAN")) {
-					g_string_printf (nmc->return_text, _("Error: '--fields' value '%s' is not valid here; allowed fields: %s"),
-					                 nmc->required_fields, NMC_FIELDS_NM_WWAN);
-					nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-					goto end;
-				}
-				nmc->allowed_fields = nmc_fields_nm_status;
-				nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_NM_WWAN, nmc->allowed_fields, NULL);
-				nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ADD | NMC_PF_FLAG_FIELD_NAMES;
-				nmc->print_fields.header_name = _("WWAN enabled");
-				print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
-
-				if (nmc_is_nm_running (nmc, NULL)) {
-					nmc->get_client (nmc); /* create NMClient */
-					nmc->allowed_fields[7].value = nm_client_wwan_get_enabled (nmc->client) ? _("enabled") : _("disabled");
-				} else
-					nmc->allowed_fields[7].value = _("unknown");
-				nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag;
-				print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+				/* no argument, show current WWAN (mobile broadband) state */
+				nmc_switch_show (nmc, NMC_FIELDS_NM_WWAN, _("WWAN radio switch"));
 			} else {
-				if (!strcmp (*argv, "on"))
-					enable_wwan = TRUE;
-				else if (!strcmp (*argv, "off"))
-					enable_wwan = FALSE;
-				else {
-					g_string_printf (nmc->return_text, _("Error: invalid 'wwan' parameter: '%s'."), *argv);
-					nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-					goto end;
-				}
+				if (!nmc_switch_parse_on_off (nmc, *(argv-1), *argv, &enable_flag))
+					goto finish;
+
 				nmc->get_client (nmc); /* create NMClient */
-				nm_client_wwan_set_enabled (nmc->client, enable_wwan);
+				nm_client_wwan_set_enabled (nmc->client, enable_flag);
 			}
 		}
 #if WITH_WIMAX
 		else if (matches (*argv, "wimax") == 0) {
+			if (nmc_arg_is_help (*(argv+1))) {
+				usage_radio_wimax ();
+				goto finish;
+			}
 			if (next_arg (&argc, &argv) != 0) {
-				if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error))
-					goto opt_error;
 				/* no argument, show current WiMAX state */
-				if (nmc->required_fields && strcasecmp (nmc->required_fields, "WIMAX")) {
-					g_string_printf (nmc->return_text, _("Error: '--fields' value '%s' is not valid here; allowed fields: %s"),
-					                 nmc->required_fields, NMC_FIELDS_NM_WIMAX);
-					nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-					goto end;
-				}
-				nmc->allowed_fields = nmc_fields_nm_status;
-				nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_NM_WIMAX, nmc->allowed_fields, NULL);
-				nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ADD | NMC_PF_FLAG_FIELD_NAMES;
-				nmc->print_fields.header_name = _("WiMAX enabled");
-				print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
-
-				if (nmc_is_nm_running (nmc, NULL)) {
-					nmc->get_client (nmc); /* create NMClient */
-					nmc->allowed_fields[9].value = nm_client_wimax_get_enabled (nmc->client) ? _("enabled") : _("disabled");
-				} else
-					nmc->allowed_fields[9].value = _("unknown");
-				nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag;
-				print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+				nmc_switch_show (nmc, NMC_FIELDS_NM_WIMAX, _("WiMAX radio switch"));
 			} else {
-				if (!strcmp (*argv, "on"))
-					enable_wimax = TRUE;
-				else if (!strcmp (*argv, "off"))
-					enable_wimax = FALSE;
-				else {
-					g_string_printf (nmc->return_text, _("Error: invalid 'wimax' parameter: '%s'."), *argv);
-					nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-					goto end;
-				}
+				if (!nmc_switch_parse_on_off (nmc, *(argv-1), *argv, &enable_flag))
+					goto finish;
+
 				nmc->get_client (nmc); /* create NMClient */
-				nm_client_wimax_set_enabled (nmc->client, enable_wimax);
+				nm_client_wimax_set_enabled (nmc->client, enable_flag);
 			}
 		}
 #endif
-		else if (   matches (*argv, "help") == 0
-		         || (g_str_has_prefix (*argv, "-")  && matches ((*argv)+1, "help") == 0)
-		         || (g_str_has_prefix (*argv, "--") && matches ((*argv)+2, "help") == 0)) {
-			usage ();
-		}
 		else {
-			usage ();
-			g_string_printf (nmc->return_text, _("Error: 'nm' command '%s' is not valid."), *argv);
+			usage_radio ();
+			g_string_printf (nmc->return_text, _("Error: 'radio' command '%s' is not valid."), *argv);
 			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
 		}
 	}
 
-end:
+finish:
 	quit ();
 	return nmc->return_value;
-
-opt_error:
-	quit ();
-	g_string_printf (nmc->return_text, _("Error: %s."), error->message);
-	nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-	g_error_free (error);
-	return nmc->return_value;
 }
+
diff --git a/cli/src/network-manager.h b/cli/src/network-manager.h
index 93cc1b07..bccba7ce 100644
--- a/cli/src/network-manager.h
+++ b/cli/src/network-manager.h
@@ -14,7 +14,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * (C) Copyright 2010 Red Hat, Inc.
+ * (C) Copyright 2010 - 2012 Red Hat, Inc.
  */
 
 #ifndef NMC_NETWORK_MANAGER_H
@@ -22,6 +22,8 @@
 
 #include "nmcli.h"
 
-NMCResultCode do_network_manager (NmCli *nmc, int argc, char **argv);
+NMCResultCode do_general    (NmCli *nmc, int argc, char **argv);
+NMCResultCode do_networking (NmCli *nmc, int argc, char **argv);
+NMCResultCode do_radio      (NmCli *nmc, int argc, char **argv);
 
 #endif /* NMC_NETWORK_MANAGER_H */
diff --git a/cli/src/nmcli.c b/cli/src/nmcli.c
index 757ff92b..66288c20 100644
--- a/cli/src/nmcli.c
+++ b/cli/src/nmcli.c
@@ -16,7 +16,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * (C) Copyright 2010 - 2012 Red Hat, Inc.
+ * (C) Copyright 2010 - 2014 Red Hat, Inc.
  */
 
 /* Generated configuration file */
@@ -26,6 +26,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include <signal.h>
+#include <pthread.h>
 #include <locale.h>
 
 #include <glib.h>
@@ -36,6 +37,7 @@
 
 #include "nmcli.h"
 #include "utils.h"
+#include "common.h"
 #include "connections.h"
 #include "devices.h"
 #include "network-manager.h"
@@ -46,6 +48,10 @@
 # define NMCLI_VERSION VERSION
 #endif
 
+/* Global NmCli object */
+// FIXME: Currently, we pass NmCli over in most APIs, but we might refactor
+// that and use the global variable directly instead.
+NmCli nm_cli;
 
 typedef struct {
 	NmCli *nmc;
@@ -55,6 +61,7 @@ typedef struct {
 
 /* --- Global variables --- */
 GMainLoop *loop = NULL;
+static sigset_t signal_set;
 
 
 /* Get an error quark for use with GError */
@@ -82,11 +89,15 @@ usage (const char *prog_name)
 	         "  -f[ields] <field1,field2,...>|all|common   specify fields to output\n"
 	         "  -e[scape] yes|no                           escape columns separators in values\n"
 	         "  -n[ocheck]                                 don't check nmcli and NetworkManager versions\n"
+	         "  -a[sk]                                     ask for missing parameters\n"
+	         "  -w[ait] <seconds>                          set timeout waiting for finishing operations\n"
 	         "  -v[ersion]                                 show program version\n"
 	         "  -h[elp]                                    print this help\n"
 	         "\n"
 	         "OBJECT\n"
-	         "  nm              NetworkManager's status\n"
+	         "  g[eneral]       NetworkManager's general status and operations\n"
+	         "  n[etworking]    overall networking control\n"
+	         "  r[adio]         NetworkManager radio switches\n"
 	         "  c[onnection]    NetworkManager's connections\n"
 	         "  d[evice]        devices managed by NetworkManager\n"
 	         "\n"),
@@ -104,7 +115,9 @@ static const struct cmd {
 	const char *cmd;
 	NMCResultCode (*func) (NmCli *nmc, int argc, char **argv);
 } nmcli_cmds[] = {
-	{ "nm",         do_network_manager },
+	{ "general",    do_general },
+	{ "networking", do_networking },
+	{ "radio",      do_radio },
 	{ "connection", do_connections },
 	{ "device",     do_devices },
 	{ "help",       do_help },
@@ -183,9 +196,9 @@ parse_command_line (NmCli *nmc, int argc, char **argv)
 				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
 				return nmc->return_value;
 			}
-			if (!strcmp (argv[1], "tabular"))
+			if (matches (argv[1], "tabular") == 0)
 				nmc->multiline_output = FALSE;
-			else if (!strcmp (argv[1], "multiline"))
+			else if (matches (argv[1], "multiline") == 0)
 				nmc->multiline_output = TRUE;
 			else {
 		 		g_string_printf (nmc->return_text, _("Error: '%s' is not valid argument for '%s' option."), argv[1], opt);
@@ -199,9 +212,9 @@ parse_command_line (NmCli *nmc, int argc, char **argv)
 				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
 				return nmc->return_value;
 			}
-			if (!strcmp (argv[1], "yes"))
+			if (matches (argv[1], "yes") == 0)
 				nmc->escape_values = TRUE;
-			else if (!strcmp (argv[1], "no"))
+			else if (matches (argv[1], "no") == 0)
 				nmc->escape_values = FALSE;
 			else {
 		 		g_string_printf (nmc->return_text, _("Error: '%s' is not valid argument for '%s' option."), argv[1], opt);
@@ -218,6 +231,23 @@ parse_command_line (NmCli *nmc, int argc, char **argv)
 			nmc->required_fields = g_strdup (argv[1]);
 		} else if (matches (opt, "-nocheck") == 0) {
 			nmc->nocheck_ver = TRUE;
+		} else if (matches (opt, "-ask") == 0) {
+			nmc->ask = TRUE;
+		} else if (matches (opt, "-wait") == 0) {
+			unsigned long timeout;
+			next_arg (&argc, &argv);
+			if (argc <= 1) {
+		 		g_string_printf (nmc->return_text, _("Error: missing argument for '%s' option."), opt);
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				return nmc->return_value;
+			}
+			if (!nmc_string_to_uint (argv[1], TRUE, 0, G_MAXINT, &timeout)) {
+		 		g_string_printf (nmc->return_text, _("Error: '%s' is not a valid timeout for '%s' option."),
+				                 argv[1], opt);
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				return nmc->return_value;
+			}
+			nmc->timeout = (int) timeout;
 		} else if (matches (opt, "-version") == 0) {
 			printf (_("nmcli tool, version %s\n"), NMCLI_VERSION);
 			return NMC_RESULT_SUCCESS;
@@ -240,27 +270,68 @@ parse_command_line (NmCli *nmc, int argc, char **argv)
 	return nmc->return_value;
 }
 
-static void
-signal_handler (int signo)
-{
-	if (signo == SIGINT || signo == SIGTERM) {
-		g_message (_("Caught signal %d, shutting down..."), signo);
-		g_main_loop_quit (loop);
+void *signal_handling_thread (void *arg);
+/*
+ * Thread function waiting for signals and processing them.
+ * Wait for signals in signal set. The semantics of sigwait() require that all
+ * threads (including the thread calling sigwait()) have the signal masked, for
+ * reliable operation. Otherwise, a signal that arrives while this thread is
+ * not blocked in sigwait() might be delivered to another thread.
+ */
+void *
+signal_handling_thread (void *arg) {
+	int signo;
+
+	while (1) {
+		sigwait (&signal_set, &signo);
+
+		switch (signo) {
+		case SIGINT:
+		case SIGQUIT:
+		case SIGTERM:
+			nmc_cleanup_readline ();
+			printf (_("\nError: nmcli terminated by signal %d."), signo);
+			exit (1);
+			break;
+		default:
+			break;
+		}
 	}
+	return NULL;
 }
 
-static void
+/*
+ * Mask the signals we are interested in and create a signal handling thread.
+ * Because all threads inherit the signal mask from their creator, all threads
+ * in the process will have the signals masked. That's why setup_signals() has
+ * to be called before creating other threads.
+ */
+static gboolean
 setup_signals (void)
 {
-	struct sigaction action;
-	sigset_t mask;
-
-	sigemptyset (&mask);
-	action.sa_handler = signal_handler;
-	action.sa_mask = mask;
-	action.sa_flags = 0;
-	sigaction (SIGTERM,  &action, NULL);
-	sigaction (SIGINT,  &action, NULL);
+	pthread_t signal_thread_id;
+	int status;
+
+	sigemptyset (&signal_set);
+	sigaddset (&signal_set, SIGINT);
+	sigaddset (&signal_set, SIGQUIT);
+	sigaddset (&signal_set, SIGTERM);
+
+	/* Block all signals of interest. */
+	status = pthread_sigmask (SIG_BLOCK, &signal_set, NULL);
+	if (status != 0) {
+		fprintf (stderr, _("Failed to set signal mask: %d"), status);
+		return FALSE;
+	}
+
+       /* Create the signal handling thread. */
+	status = pthread_create (&signal_thread_id, NULL, signal_handling_thread, NULL);
+	if (status != 0) {
+		fprintf (stderr, _("Failed to create signal handling thread: %d"), status);
+		return FALSE;
+	}
+
+	return TRUE;
 }
 
 static NMClient *
@@ -287,7 +358,7 @@ nmc_init (NmCli *nmc)
 	nmc->return_value = NMC_RESULT_SUCCESS;
 	nmc->return_text = g_string_new (_("Success"));
 
-	nmc->timeout = 10;
+	nmc->timeout = -1;
 
 	nmc->system_settings = NULL;
 	nmc->system_settings_running = FALSE;
@@ -300,9 +371,13 @@ nmc_init (NmCli *nmc)
 	nmc->mode_specified = FALSE;
 	nmc->escape_values = TRUE;
 	nmc->required_fields = NULL;
-	nmc->allowed_fields = NULL;
+	nmc->output_data = g_ptr_array_new_full (20, g_free);
 	memset (&nmc->print_fields, '\0', sizeof (NmcPrintFields));
 	nmc->nocheck_ver = FALSE;
+	nmc->ask = FALSE;
+	nmc->editor_status_line = FALSE;
+	nmc->editor_save_confirmation = TRUE;
+	nmc->editor_prompt_color = NMC_TERM_COLOR_NORMAL;
 }
 
 static void
@@ -316,8 +391,8 @@ nmc_cleanup (NmCli *nmc)
 	g_slist_free (nmc->system_connections);
 
 	g_free (nmc->required_fields);
-	if (nmc->print_fields.indices)
-		g_array_free (nmc->print_fields.indices, TRUE);
+	nmc_empty_output_fields (nmc);
+	g_ptr_array_unref (nmc->output_data);
 }
 
 static gboolean
@@ -336,8 +411,11 @@ start (gpointer data)
 int
 main (int argc, char *argv[])
 {
-	NmCli nmc;
-	ArgsInfo args_info = { &nmc, argc, argv };
+	ArgsInfo args_info = { &nm_cli, argc, argv };
+
+	/* Set up unix signal handling */
+	if (!setup_signals ())
+		exit (NMC_RESULT_ERROR_UNKNOWN);
 
 	/* Set locale to use environment variables */
 	setlocale (LC_ALL, "");
@@ -349,22 +427,23 @@ main (int argc, char *argv[])
 	textdomain (GETTEXT_PACKAGE);
 #endif
 
+#if !GLIB_CHECK_VERSION (2, 35, 0)
 	g_type_init ();
+#endif
 
-	nmc_init (&nmc);
+	nmc_init (&nm_cli);
 	g_idle_add (start, &args_info);
 
 	loop = g_main_loop_new (NULL, FALSE);  /* create main loop */
-	setup_signals ();                      /* setup UNIX signals */
 	g_main_loop_run (loop);                /* run main loop */
 
 	/* Print result descripting text */
-	if (nmc.return_value != NMC_RESULT_SUCCESS) {
-		fprintf (stderr, "%s\n", nmc.return_text->str);
+	if (nm_cli.return_value != NMC_RESULT_SUCCESS) {
+		fprintf (stderr, "%s\n", nm_cli.return_text->str);
 	}
 
 	g_main_loop_unref (loop);
-	nmc_cleanup (&nmc);
+	nmc_cleanup (&nm_cli);
 
-	return nmc.return_value;
+	return nm_cli.return_value;
 }
diff --git a/cli/src/nmcli.h b/cli/src/nmcli.h
index 8928126b..b300c6d3 100644
--- a/cli/src/nmcli.h
+++ b/cli/src/nmcli.h
@@ -55,7 +55,10 @@ typedef enum {
 	NMC_RESULT_ERROR_NM_NOT_RUNNING = 8,
 
 	/* nmcli and NetworkManager versions mismatch */
-	NMC_RESULT_ERROR_VERSIONS_MISMATCH = 9
+	NMC_RESULT_ERROR_VERSIONS_MISMATCH = 9,
+
+	/* Connection/Device/AP not found */
+	NMC_RESULT_ERROR_NOT_FOUND = 10
 } NMCResultCode;
 
 typedef enum {
@@ -66,33 +69,40 @@ typedef enum {
 
 /* === Output fields === */
 /* Flags for NmcOutputField */
-#define NMC_OF_FLAG_ARRAY              0x00000001   /* 'value' is an NULL-terminated array rather then a single string */
-
-typedef struct {
-	const char *name;       /* Field's name */
-	const char *name_l10n;  /* Field's name for translation */
-	int width;              /* Width in screen columns */
-	const void *value;      /* Value of current field - char* or char** */
-	guint32 flags;          /* Flags */
+#define NMC_OF_FLAG_FIELD_NAMES        0x00000001   /* Print field names instead of values */
+#define NMC_OF_FLAG_SECTION_PREFIX     0x00000002   /* Use the first value as section prefix for the other field names - just in multiline */
+#define NMC_OF_FLAG_MAIN_HEADER_ADD    0x00000004   /* Print main header in addition to values/field names */
+#define NMC_OF_FLAG_MAIN_HEADER_ONLY   0x00000008   /* Print main header only */
+
+typedef struct _NmcOutputField {
+	const char *name;               /* Field's name */
+	const char *name_l10n;          /* Field's name for translation */
+	int width;                      /* Width in screen columns */
+	struct _NmcOutputField *group;  /* Points to an array with available section field names if this is a section (group) field */
+	void *value;                    /* Value of current field - char* or char** (NULL-terminated array) */
+	gboolean value_is_array;        /* Whether value is char** instead of char* */
+	gboolean free_value;            /* Whether to free the value */
+	guint32 flags;                  /* Flags - whether and how to print values/field names/headers */
 } NmcOutputField;
 
-/* Flags for NmcPrintFields */
-#define NMC_PF_FLAG_MULTILINE          0x00000001   /* Multiline output instead of tabular */
-#define NMC_PF_FLAG_TERSE              0x00000002   /* Terse output mode */
-#define NMC_PF_FLAG_PRETTY             0x00000004   /* Pretty output mode */
-#define NMC_PF_FLAG_MAIN_HEADER_ADD    0x00000008   /* Print main header in addition to values/field names */
-#define NMC_PF_FLAG_MAIN_HEADER_ONLY   0x00000010   /* Print main header only */
-#define NMC_PF_FLAG_FIELD_NAMES        0x00000020   /* Print field names instead of values */
-#define NMC_PF_FLAG_ESCAPE             0x00000040   /* Escape column separator and '\' */
-#define NMC_PF_FLAG_SECTION_PREFIX     0x00000080   /* Use the first value as section prefix for the other field names - just in multiline */
-
 typedef struct {
 	GArray *indices;      /* Array of field indices to the array of allowed fields */
 	char *header_name;    /* Name of the output */
 	int indent;           /* Indent by this number of spaces */
-	guint32 flags;        /* Various flags for controlling output: see NMC_PF_FLAG_* values */
 } NmcPrintFields;
 
+typedef enum {
+	NMC_TERM_COLOR_NORMAL  = 0,
+	NMC_TERM_COLOR_BLACK   = 1,
+	NMC_TERM_COLOR_RED     = 2,
+	NMC_TERM_COLOR_GREEN   = 3,
+	NMC_TERM_COLOR_YELLOW  = 4,
+	NMC_TERM_COLOR_BLUE    = 5,
+	NMC_TERM_COLOR_MAGENTA = 6,
+	NMC_TERM_COLOR_CYAN    = 7,
+	NMC_TERM_COLOR_WHITE   = 8
+} NmcTermColor;
+
 /* NmCli - main structure */
 typedef struct _NmCli {
 	NMClient *client;                                 /* Pointer to NMClient of libnm-glib */
@@ -114,9 +124,13 @@ typedef struct _NmCli {
 	gboolean mode_specified;                          /* Whether tabular/multiline mode was specified via '--mode' option */
 	gboolean escape_values;                           /* Whether to escape ':' and '\' in terse tabular mode */
 	char *required_fields;                            /* Required fields in output: '--fields' option */
-	NmcOutputField *allowed_fields;                   /* Array of allowed fields for particular commands */
+	GPtrArray *output_data;                           /* GPtrArray of arrays of NmcOutputField structs - accumulates data for output */
 	NmcPrintFields print_fields;                      /* Structure with field indices to print */
 	gboolean nocheck_ver;                             /* Don't check nmcli and NM versions: option '--nocheck' */
+	gboolean ask;                                     /* Ask for missing parameters: option '--ask' */
+	gboolean editor_status_line;                      /* Whether to display status line in connection editor */
+	gboolean editor_save_confirmation;                /* Whether to ask for confirmation on saving connections with 'autoconnect=yes' */
+	NmcTermColor editor_prompt_color;                 /* Color of prompt in connection editor */
 } NmCli;
 
 /* Error quark for GError domain */
diff --git a/cli/src/settings.c b/cli/src/settings.c
index 1b3d0fd0..0fc708b3 100644
--- a/cli/src/settings.c
+++ b/cli/src/settings.c
@@ -14,43 +14,50 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * (C) Copyright 2010 - 2012 Red Hat, Inc.
+ * (C) Copyright 2010 - 2014 Red Hat, Inc.
  */
 
 #include "config.h"
 
-#include "net/if_arp.h"
+#include <net/if_arp.h>
+#include <stdio.h>
 
 #include <glib.h>
 #include <glib/gi18n.h>
 #include <libnm-util/nm-utils.h>
 
 #include "utils.h"
+#include "common.h"
 #include "settings.h"
 
+/* Forward declarations */
+static char *wep_key_type_to_string (NMWepKeyType type);
 
 /* Helper macro to define fields */
-#define SETTING_FIELD(setting, width) { setting, N_(setting), width, NULL, 0 }
+#define SETTING_FIELD(setting, width) { setting, N_(setting), width, NULL, FALSE, FALSE, 0 }
 
 /* Available fields for NM_SETTING_CONNECTION_SETTING_NAME */
-static NmcOutputField nmc_fields_setting_connection[] = {
-	SETTING_FIELD ("name",  15),                            /* 0 */
-	SETTING_FIELD (NM_SETTING_CONNECTION_ID, 25),           /* 1 */
-	SETTING_FIELD (NM_SETTING_CONNECTION_UUID, 38),         /* 2 */
-	SETTING_FIELD (NM_SETTING_CONNECTION_TYPE, 17),         /* 3 */
-	SETTING_FIELD (NM_SETTING_CONNECTION_AUTOCONNECT, 13),  /* 4 */
-	SETTING_FIELD (NM_SETTING_CONNECTION_TIMESTAMP, 10),    /* 5 */
-	SETTING_FIELD (NM_SETTING_CONNECTION_READ_ONLY, 10),    /* 6 */
-	SETTING_FIELD (NM_SETTING_CONNECTION_PERMISSIONS, 30),  /* 7 */
-	SETTING_FIELD (NM_SETTING_CONNECTION_ZONE, 10),         /* 8 */
-	SETTING_FIELD (NM_SETTING_CONNECTION_MASTER, 20),       /* 9 */
-	SETTING_FIELD (NM_SETTING_CONNECTION_SLAVE_TYPE, 20),   /* 10 */
-	SETTING_FIELD (NM_SETTING_CONNECTION_SECONDARIES, 40),  /* 11 */
-	{NULL, NULL, 0, NULL, 0}
+NmcOutputField nmc_fields_setting_connection[] = {
+	SETTING_FIELD ("name",  15),                                     /* 0 */
+	SETTING_FIELD (NM_SETTING_CONNECTION_ID, 25),                    /* 1 */
+	SETTING_FIELD (NM_SETTING_CONNECTION_UUID, 38),                  /* 2 */
+	SETTING_FIELD (NM_SETTING_CONNECTION_INTERFACE_NAME, 20),        /* 3 */
+	SETTING_FIELD (NM_SETTING_CONNECTION_TYPE, 17),                  /* 4 */
+	SETTING_FIELD (NM_SETTING_CONNECTION_AUTOCONNECT, 13),           /* 5 */
+	SETTING_FIELD (NM_SETTING_CONNECTION_TIMESTAMP, 10),             /* 6 */
+	SETTING_FIELD (NM_SETTING_CONNECTION_READ_ONLY, 10),             /* 7 */
+	SETTING_FIELD (NM_SETTING_CONNECTION_PERMISSIONS, 30),           /* 8 */
+	SETTING_FIELD (NM_SETTING_CONNECTION_ZONE, 10),                  /* 9 */
+	SETTING_FIELD (NM_SETTING_CONNECTION_MASTER, 20),                /* 10 */
+	SETTING_FIELD (NM_SETTING_CONNECTION_SLAVE_TYPE, 20),            /* 11 */
+	SETTING_FIELD (NM_SETTING_CONNECTION_SECONDARIES, 40),           /* 12 */
+	SETTING_FIELD (NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT, 30),  /* 13 */
+	{NULL, NULL, 0, NULL, FALSE, FALSE, 0}
 };
 #define NMC_FIELDS_SETTING_CONNECTION_ALL     "name"","\
                                               NM_SETTING_CONNECTION_ID","\
                                               NM_SETTING_CONNECTION_UUID","\
+                                              NM_SETTING_CONNECTION_INTERFACE_NAME","\
                                               NM_SETTING_CONNECTION_TYPE","\
                                               NM_SETTING_CONNECTION_AUTOCONNECT","\
                                               NM_SETTING_CONNECTION_TIMESTAMP","\
@@ -59,11 +66,12 @@ static NmcOutputField nmc_fields_setting_connection[] = {
                                               NM_SETTING_CONNECTION_ZONE","\
                                               NM_SETTING_CONNECTION_MASTER","\
                                               NM_SETTING_CONNECTION_SLAVE_TYPE","\
-                                              NM_SETTING_CONNECTION_SECONDARIES
+                                              NM_SETTING_CONNECTION_SECONDARIES","\
+                                              NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT
 #define NMC_FIELDS_SETTING_CONNECTION_COMMON  NMC_FIELDS_SETTING_CONNECTION_ALL
 
 /* Available fields for NM_SETTING_WIRED_SETTING_NAME */
-static NmcOutputField nmc_fields_setting_wired[] = {
+NmcOutputField nmc_fields_setting_wired[] = {
 	SETTING_FIELD ("name",  17),                                  /* 0 */
 	SETTING_FIELD (NM_SETTING_WIRED_PORT, 8),                     /* 1 */
 	SETTING_FIELD (NM_SETTING_WIRED_SPEED, 10),                   /* 2 */
@@ -76,7 +84,7 @@ static NmcOutputField nmc_fields_setting_wired[] = {
 	SETTING_FIELD (NM_SETTING_WIRED_S390_SUBCHANNELS, 20),        /* 9 */
 	SETTING_FIELD (NM_SETTING_WIRED_S390_NETTYPE, 15),            /* 10 */
 	SETTING_FIELD (NM_SETTING_WIRED_S390_OPTIONS, 20),            /* 11 */
-	{NULL, NULL, 0, NULL, 0}
+	{NULL, NULL, 0, NULL, FALSE, FALSE, 0}
 };
 #define NMC_FIELDS_SETTING_WIRED_ALL     "name"","\
                                          NM_SETTING_WIRED_PORT","\
@@ -93,7 +101,7 @@ static NmcOutputField nmc_fields_setting_wired[] = {
 #define NMC_FIELDS_SETTING_WIRED_COMMON  NMC_FIELDS_SETTING_WIRED_ALL
 
 /* Available fields for NM_SETTING_802_1X_SETTING_NAME */
-static NmcOutputField nmc_fields_setting_8021X[] = {
+NmcOutputField nmc_fields_setting_8021X[] = {
 	SETTING_FIELD ("name", 10),                                              /* 0 */
 	SETTING_FIELD (NM_SETTING_802_1X_EAP, 10),                               /* 1 */
 	SETTING_FIELD (NM_SETTING_802_1X_IDENTITY, 15),                          /* 2 */
@@ -127,7 +135,7 @@ static NmcOutputField nmc_fields_setting_8021X[] = {
 	SETTING_FIELD (NM_SETTING_802_1X_PIN, 8),                                /* 30 */
 	SETTING_FIELD (NM_SETTING_802_1X_PIN_FLAGS, 20),                         /* 31 */
 	SETTING_FIELD (NM_SETTING_802_1X_SYSTEM_CA_CERTS, 17),                   /* 32 */
-	{NULL, NULL, 0, NULL, 0}
+	{NULL, NULL, 0, NULL, FALSE, FALSE, 0}
 };
 #define NMC_FIELDS_SETTING_802_1X_ALL     "name"","\
                                           NM_SETTING_802_1X_EAP","\
@@ -165,7 +173,7 @@ static NmcOutputField nmc_fields_setting_8021X[] = {
 #define NMC_FIELDS_SETTING_802_1X_COMMON  NMC_FIELDS_SETTING_802_1X_ALL
 
 /* Available fields for NM_SETTING_WIRELESS_SETTING_NAME */
-static NmcOutputField nmc_fields_setting_wireless[] = {
+NmcOutputField nmc_fields_setting_wireless[] = {
 	SETTING_FIELD ("name", 17),                                        /* 0 */
 	SETTING_FIELD (NM_SETTING_WIRELESS_SSID, 34),                      /* 1 */
 	SETTING_FIELD (NM_SETTING_WIRELESS_MODE, 15),                      /* 2 */
@@ -179,9 +187,8 @@ static NmcOutputField nmc_fields_setting_wireless[] = {
 	SETTING_FIELD (NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST, 39),     /* 10 */
 	SETTING_FIELD (NM_SETTING_WIRELESS_MTU, 6),                        /* 11 */
 	SETTING_FIELD (NM_SETTING_WIRELESS_SEEN_BSSIDS, 35),               /* 12 */
-	SETTING_FIELD (NM_SETTING_WIRELESS_SEC, 25),                       /* 13 */
-	SETTING_FIELD (NM_SETTING_WIRELESS_HIDDEN, 10),                    /* 14 */
-	{NULL, NULL, 0, NULL, 0}
+	SETTING_FIELD (NM_SETTING_WIRELESS_HIDDEN, 10),                    /* 13 */
+	{NULL, NULL, 0, NULL, FALSE, FALSE, 0}
 };
 #define NMC_FIELDS_SETTING_WIRELESS_ALL     "name"","\
                                             NM_SETTING_WIRELESS_SSID","\
@@ -196,12 +203,11 @@ static NmcOutputField nmc_fields_setting_wireless[] = {
                                             NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST","\
                                             NM_SETTING_WIRELESS_MTU","\
                                             NM_SETTING_WIRELESS_SEEN_BSSIDS","\
-                                            NM_SETTING_WIRELESS_SEC","\
                                             NM_SETTING_WIRELESS_HIDDEN
 #define NMC_FIELDS_SETTING_WIRELESS_COMMON  NMC_FIELDS_SETTING_WIRELESS_ALL
 
 /* Available fields for NM_SETTING_WIRELESS_SECURITY_SETTING_NAME */
-static NmcOutputField nmc_fields_setting_wireless_security[] = {
+NmcOutputField nmc_fields_setting_wireless_security[] = {
 	SETTING_FIELD ("name", 25),                                           /* 0 */
 	SETTING_FIELD (NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, 10),            /* 1 */
 	SETTING_FIELD (NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX, 15),       /* 2 */
@@ -220,7 +226,7 @@ static NmcOutputField nmc_fields_setting_wireless_security[] = {
 	SETTING_FIELD (NM_SETTING_WIRELESS_SECURITY_PSK_FLAGS, 20),           /* 15 */
 	SETTING_FIELD (NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD, 15),       /* 16 */
 	SETTING_FIELD (NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD_FLAGS, 20), /* 17 */
-	{NULL, NULL, 0, NULL, 0}
+	{NULL, NULL, 0, NULL, FALSE, FALSE, 0}
 };
 #define NMC_FIELDS_SETTING_WIRELESS_SECURITY_ALL     "name"","\
                                                      NM_SETTING_WIRELESS_SECURITY_KEY_MGMT","\
@@ -243,7 +249,7 @@ static NmcOutputField nmc_fields_setting_wireless_security[] = {
 #define NMC_FIELDS_SETTING_WIRELESS_SECURITY_COMMON  NMC_FIELDS_SETTING_WIRELESS_SECURITY_ALL
 
 /* Available fields for NM_SETTING_IP4_CONFIG_SETTING_NAME */
-static NmcOutputField nmc_fields_setting_ip4_config[] = {
+NmcOutputField nmc_fields_setting_ip4_config[] = {
 	SETTING_FIELD ("name", 8),                                         /* 0 */
 	SETTING_FIELD (NM_SETTING_IP4_CONFIG_METHOD, 10),                  /* 1 */
 	SETTING_FIELD (NM_SETTING_IP4_CONFIG_DNS, 20),                     /* 2 */
@@ -257,7 +263,7 @@ static NmcOutputField nmc_fields_setting_ip4_config[] = {
 	SETTING_FIELD (NM_SETTING_IP4_CONFIG_DHCP_HOSTNAME, 14),           /* 10 */
 	SETTING_FIELD (NM_SETTING_IP4_CONFIG_NEVER_DEFAULT, 15),           /* 11 */
 	SETTING_FIELD (NM_SETTING_IP4_CONFIG_MAY_FAIL, 12),                /* 12 */
-	{NULL, NULL, 0, NULL, 0}
+	{NULL, NULL, 0, NULL, FALSE, FALSE, 0}
 };
 #define NMC_FIELDS_SETTING_IP4_CONFIG_ALL     "name"","\
                                               NM_SETTING_IP4_CONFIG_METHOD","\
@@ -275,7 +281,7 @@ static NmcOutputField nmc_fields_setting_ip4_config[] = {
 #define NMC_FIELDS_SETTING_IP4_CONFIG_COMMON  NMC_FIELDS_SETTING_IP4_CONFIG_ALL
 
 /* Available fields for NM_SETTING_IP6_CONFIG_SETTING_NAME */
-static NmcOutputField nmc_fields_setting_ip6_config[] = {
+NmcOutputField nmc_fields_setting_ip6_config[] = {
 	SETTING_FIELD ("name", 8),                                         /* 0 */
 	SETTING_FIELD (NM_SETTING_IP6_CONFIG_METHOD, 10),                  /* 1 */
 	SETTING_FIELD (NM_SETTING_IP6_CONFIG_DNS, 20),                     /* 2 */
@@ -288,7 +294,7 @@ static NmcOutputField nmc_fields_setting_ip6_config[] = {
 	SETTING_FIELD (NM_SETTING_IP6_CONFIG_MAY_FAIL, 12),                /* 9 */
 	SETTING_FIELD (NM_SETTING_IP6_CONFIG_IP6_PRIVACY, 15),             /* 10 */
 	SETTING_FIELD (NM_SETTING_IP6_CONFIG_DHCP_HOSTNAME, 14),           /* 11 */
-	{NULL, NULL, 0, NULL, 0}
+	{NULL, NULL, 0, NULL, FALSE, FALSE, 0}
 };
 #define NMC_FIELDS_SETTING_IP6_CONFIG_ALL     "name"","\
                                               NM_SETTING_IP6_CONFIG_METHOD","\
@@ -305,14 +311,14 @@ static NmcOutputField nmc_fields_setting_ip6_config[] = {
 #define NMC_FIELDS_SETTING_IP6_CONFIG_COMMON  NMC_FIELDS_SETTING_IP4_CONFIG_ALL
 
 /* Available fields for NM_SETTING_SERIAL_SETTING_NAME */
-static NmcOutputField nmc_fields_setting_serial[] = {
+NmcOutputField nmc_fields_setting_serial[] = {
 	SETTING_FIELD ("name", 10),                                        /* 0 */
 	SETTING_FIELD (NM_SETTING_SERIAL_BAUD, 10),                        /* 1 */
 	SETTING_FIELD (NM_SETTING_SERIAL_BITS, 10),                        /* 2 */
 	SETTING_FIELD (NM_SETTING_SERIAL_PARITY, 10),                      /* 3 */
 	SETTING_FIELD (NM_SETTING_SERIAL_STOPBITS, 10),                    /* 4 */
 	SETTING_FIELD (NM_SETTING_SERIAL_SEND_DELAY, 12),                  /* 5 */
-	{NULL, NULL, 0, NULL, 0}
+	{NULL, NULL, 0, NULL, FALSE, FALSE, 0}
 };
 #define NMC_FIELDS_SETTING_SERIAL_ALL     "name"","\
                                           NM_SETTING_SERIAL_BAUD","\
@@ -323,7 +329,7 @@ static NmcOutputField nmc_fields_setting_serial[] = {
 #define NMC_FIELDS_SETTING_SERIAL_COMMON  NMC_FIELDS_SETTING_SERIAL_ALL
 
 /* Available fields for NM_SETTING_PPP_SETTING_NAME */
-static NmcOutputField nmc_fields_setting_ppp[] = {
+NmcOutputField nmc_fields_setting_ppp[] = {
 	SETTING_FIELD ("name", 10),                                        /* 0 */
 	SETTING_FIELD (NM_SETTING_PPP_NOAUTH, 10),                         /* 1 */
 	SETTING_FIELD (NM_SETTING_PPP_REFUSE_EAP, 10),                     /* 2 */
@@ -343,7 +349,7 @@ static NmcOutputField nmc_fields_setting_ppp[] = {
 	SETTING_FIELD (NM_SETTING_PPP_MTU, 10),                            /* 16 */
 	SETTING_FIELD (NM_SETTING_PPP_LCP_ECHO_FAILURE, 17),               /* 17 */
 	SETTING_FIELD (NM_SETTING_PPP_LCP_ECHO_INTERVAL, 18),              /* 18 */
-	{NULL, NULL, 0, NULL, 0}
+	{NULL, NULL, 0, NULL, FALSE, FALSE, 0}
 };
 #define NMC_FIELDS_SETTING_PPP_ALL     "name"","\
                                        NM_SETTING_PPP_NOAUTH","\
@@ -367,13 +373,13 @@ static NmcOutputField nmc_fields_setting_ppp[] = {
 #define NMC_FIELDS_SETTING_PPP_COMMON  NMC_FIELDS_SETTING_PPP_ALL
 
 /* Available fields for NM_SETTING_PPPOE_SETTING_NAME */
-static NmcOutputField nmc_fields_setting_pppoe[] = {
+NmcOutputField nmc_fields_setting_pppoe[] = {
 	SETTING_FIELD ("name", 10),                                        /* 0 */
 	SETTING_FIELD (NM_SETTING_PPPOE_SERVICE, 12),                      /* 1 */
 	SETTING_FIELD (NM_SETTING_PPPOE_USERNAME, 15),                     /* 2 */
 	SETTING_FIELD (NM_SETTING_PPPOE_PASSWORD, 15),                     /* 3 */
 	SETTING_FIELD (NM_SETTING_PPPOE_PASSWORD_FLAGS, 20),               /* 4 */
-	{NULL, NULL, 0, NULL, 0}
+	{NULL, NULL, 0, NULL, FALSE, FALSE, 0}
 };
 #define NMC_FIELDS_SETTING_PPPOE_ALL     "name"","\
                                          NM_SETTING_PPPOE_SERVICE","\
@@ -383,7 +389,7 @@ static NmcOutputField nmc_fields_setting_pppoe[] = {
 #define NMC_FIELDS_SETTING_PPPOE_COMMON  NMC_FIELDS_SETTING_PPPOE_ALL
 
 /* Available fields for NM_SETTING_ADSL_SETTING_NAME */
-static NmcOutputField nmc_fields_setting_adsl[] = {
+NmcOutputField nmc_fields_setting_adsl[] = {
 	SETTING_FIELD ("name", 10),                                /* 0 */
 	SETTING_FIELD (NM_SETTING_ADSL_USERNAME, 15),              /* 1 */
 	SETTING_FIELD (NM_SETTING_ADSL_PASSWORD, 15),              /* 2 */
@@ -392,7 +398,7 @@ static NmcOutputField nmc_fields_setting_adsl[] = {
 	SETTING_FIELD (NM_SETTING_ADSL_ENCAPSULATION, 10),         /* 5 */
 	SETTING_FIELD (NM_SETTING_ADSL_VPI, 10),                   /* 6 */
 	SETTING_FIELD (NM_SETTING_ADSL_VCI, 10),                   /* 7 */
-	{NULL, NULL, 0, NULL, 0}
+	{NULL, NULL, 0, NULL, FALSE, FALSE, 0}
 };
 #define NMC_FIELDS_SETTING_ADSL_ALL     "name"","\
                                         NM_SETTING_ADSL_USERNAME","\
@@ -405,7 +411,7 @@ static NmcOutputField nmc_fields_setting_adsl[] = {
 #define NMC_FIELDS_SETTING_ADSL_COMMON  NMC_FIELDS_SETTING_ADSL_ALL
 
 /* Available fields for NM_SETTING_GSM_SETTING_NAME */
-static NmcOutputField nmc_fields_setting_gsm[] = {
+NmcOutputField nmc_fields_setting_gsm[] = {
 	SETTING_FIELD ("name", 10),                                        /* 0 */
 	SETTING_FIELD (NM_SETTING_GSM_NUMBER, 10),                         /* 1 */
 	SETTING_FIELD (NM_SETTING_GSM_USERNAME, 15),                       /* 2 */
@@ -418,7 +424,7 @@ static NmcOutputField nmc_fields_setting_gsm[] = {
 	SETTING_FIELD (NM_SETTING_GSM_PIN, 10),                            /* 9 */
 	SETTING_FIELD (NM_SETTING_GSM_PIN_FLAGS, 20),                      /* 10 */
 	SETTING_FIELD (NM_SETTING_GSM_HOME_ONLY, 10),                      /* 11 */
-	{NULL, NULL, 0, NULL, 0}
+	{NULL, NULL, 0, NULL, FALSE, FALSE, 0}
 };
 #define NMC_FIELDS_SETTING_GSM_ALL     "name"","\
                                        NM_SETTING_GSM_NUMBER","\
@@ -435,13 +441,13 @@ static NmcOutputField nmc_fields_setting_gsm[] = {
 #define NMC_FIELDS_SETTING_GSM_COMMON  NMC_FIELDS_SETTING_GSM_ALL
 
 /* Available fields for NM_SETTING_CDMA_SETTING_NAME */
-static NmcOutputField nmc_fields_setting_cdma[] = {
+NmcOutputField nmc_fields_setting_cdma[] = {
 	SETTING_FIELD ("name", 10),                                        /* 0 */
 	SETTING_FIELD (NM_SETTING_CDMA_NUMBER, 15),                        /* 1 */
 	SETTING_FIELD (NM_SETTING_CDMA_USERNAME, 15),                      /* 2 */
 	SETTING_FIELD (NM_SETTING_CDMA_PASSWORD, 15),                      /* 3 */
 	SETTING_FIELD (NM_SETTING_CDMA_PASSWORD_FLAGS, 20),                /* 4 */
-	{NULL, NULL, 0, NULL, 0}
+	{NULL, NULL, 0, NULL, FALSE, FALSE, 0}
 };
 #define NMC_FIELDS_SETTING_CDMA_ALL     "name"","\
                                         NM_SETTING_CDMA_NUMBER","\
@@ -451,11 +457,11 @@ static NmcOutputField nmc_fields_setting_cdma[] = {
 #define NMC_FIELDS_SETTING_CDMA_COMMON  NMC_FIELDS_SETTING_CDMA_ALL
 
 /* Available fields for NM_SETTING_BLUETOOTH_SETTING_NAME */
-static NmcOutputField nmc_fields_setting_bluetooth[] = {
+NmcOutputField nmc_fields_setting_bluetooth[] = {
 	SETTING_FIELD ("name", 11),                                        /* 0 */
 	SETTING_FIELD (NM_SETTING_BLUETOOTH_BDADDR, 19),                   /* 1 */
 	SETTING_FIELD (NM_SETTING_BLUETOOTH_TYPE, 10),                     /* 2 */
-	{NULL, NULL, 0, NULL, 0}
+	{NULL, NULL, 0, NULL, FALSE, FALSE, 0}
 };
 #define NMC_FIELDS_SETTING_BLUETOOTH_ALL     "name"","\
                                              NM_SETTING_BLUETOOTH_BDADDR","\
@@ -463,12 +469,12 @@ static NmcOutputField nmc_fields_setting_bluetooth[] = {
 #define NMC_FIELDS_SETTING_BLUETOOTH_COMMON  NMC_FIELDS_SETTING_BLUETOOTH_ALL
 
 /* Available fields for NM_SETTING_OLPC_MESH_SETTING_NAME */
-static NmcOutputField nmc_fields_setting_olpc_mesh[] = {
+NmcOutputField nmc_fields_setting_olpc_mesh[] = {
 	SETTING_FIELD ("name", 18),                                        /* 0 */
 	SETTING_FIELD (NM_SETTING_OLPC_MESH_SSID, 34),                     /* 1 */
 	SETTING_FIELD (NM_SETTING_OLPC_MESH_CHANNEL, 12),                  /* 2 */
 	SETTING_FIELD (NM_SETTING_OLPC_MESH_DHCP_ANYCAST_ADDRESS, 17),     /* 3 */
-	{NULL, NULL, 0, NULL, 0}
+	{NULL, NULL, 0, NULL, FALSE, FALSE, 0}
 };
 #define NMC_FIELDS_SETTING_OLPC_MESH_ALL     "name"","\
                                              NM_SETTING_OLPC_MESH_SSID","\
@@ -477,13 +483,13 @@ static NmcOutputField nmc_fields_setting_olpc_mesh[] = {
 #define NMC_FIELDS_SETTING_OLPC_MESH_COMMON  NMC_FIELDS_SETTING_OLPC_MESH_ALL
 
 /* Available fields for NM_SETTING_VPN_SETTING_NAME */
-static NmcOutputField nmc_fields_setting_vpn[] = {
+NmcOutputField nmc_fields_setting_vpn[] = {
 	SETTING_FIELD ("name", 6),                                         /* 0 */
 	SETTING_FIELD (NM_SETTING_VPN_SERVICE_TYPE, 40),                   /* 1 */
 	SETTING_FIELD (NM_SETTING_VPN_USER_NAME, 12),                      /* 2 */
 	SETTING_FIELD (NM_SETTING_VPN_DATA, 30),                           /* 3 */
 	SETTING_FIELD (NM_SETTING_VPN_SECRETS, 15),                        /* 4 */
-	{NULL, NULL, 0, NULL, 0}
+	{NULL, NULL, 0, NULL, FALSE, FALSE, 0}
 };
 #define NMC_FIELDS_SETTING_VPN_ALL     "name"","\
                                        NM_SETTING_VPN_SERVICE_TYPE","\
@@ -493,11 +499,11 @@ static NmcOutputField nmc_fields_setting_vpn[] = {
 #define NMC_FIELDS_SETTING_VPN_COMMON  NMC_FIELDS_SETTING_VPN_ALL
 
 /* Available fields for NM_SETTING_WIMAX_SETTING_NAME */
-static NmcOutputField nmc_fields_setting_wimax[] = {
+NmcOutputField nmc_fields_setting_wimax[] = {
 	SETTING_FIELD ("name", 6),                                         /* 0 */
 	SETTING_FIELD (NM_SETTING_WIMAX_MAC_ADDRESS, 19),                  /* 1 */
 	SETTING_FIELD (NM_SETTING_WIMAX_NETWORK_NAME, 40),                 /* 2 */
-	{NULL, NULL, 0, NULL, 0}
+	{NULL, NULL, 0, NULL, FALSE, FALSE, 0}
 };
 #define NMC_FIELDS_SETTING_WIMAX_ALL     "name"","\
                                          NM_SETTING_WIMAX_MAC_ADDRESS","\
@@ -505,25 +511,29 @@ static NmcOutputField nmc_fields_setting_wimax[] = {
 #define NMC_FIELDS_SETTING_WIMAX_COMMON  NMC_FIELDS_SETTING_WIMAX_ALL
 
 /* Available fields for NM_SETTING_INFINIBAND_SETTING_NAME */
-static NmcOutputField nmc_fields_setting_infiniband[] = {
+NmcOutputField nmc_fields_setting_infiniband[] = {
 	SETTING_FIELD ("name",  12),                                       /* 0 */
 	SETTING_FIELD (NM_SETTING_INFINIBAND_MAC_ADDRESS, 61),             /* 1 */
 	SETTING_FIELD (NM_SETTING_INFINIBAND_MTU, 6),                      /* 2 */
 	SETTING_FIELD (NM_SETTING_INFINIBAND_TRANSPORT_MODE, 12),          /* 3 */
-	{NULL, NULL, 0, NULL, 0}
+	SETTING_FIELD (NM_SETTING_INFINIBAND_P_KEY, 6),                    /* 4 */
+	SETTING_FIELD (NM_SETTING_INFINIBAND_PARENT, 16),                  /* 5 */
+	{NULL, NULL, 0, NULL, FALSE, FALSE, 0}
 };
 #define NMC_FIELDS_SETTING_INFINIBAND_ALL     "name"","\
                                               NM_SETTING_INFINIBAND_MAC_ADDRESS","\
-                                              NM_SETTING_INFINIBAND_MTU","\
-                                              NM_SETTING_INFINIBAND_TRANSPORT_MODE
-#define NMC_FIELDS_SETTING_INFINIBAND_COMMON  NMC_FIELDS_SETTING_INFINIBAND_ALL
+                                              NM_SETTING_INFINIBAND_MTU"," \
+                                              NM_SETTING_INFINIBAND_TRANSPORT_MODE"," \
+                                              NM_SETTING_INFINIBAND_P_KEY"," \
+                                              NM_SETTING_INFINIBAND_PARENT
+#define NMC_FIELDS_SETTING_INFINIBAND_COMMON  NMC_FIELDS_SETTING_INFINIBAND_ALL \
 
 /* Available fields for NM_SETTING_BOND_SETTING_NAME */
-static NmcOutputField nmc_fields_setting_bond[] = {
+NmcOutputField nmc_fields_setting_bond[] = {
 	SETTING_FIELD ("name",  8),                                        /* 0 */
 	SETTING_FIELD (NM_SETTING_BOND_INTERFACE_NAME, 15),                /* 1 */
 	SETTING_FIELD (NM_SETTING_BOND_OPTIONS, 30),                       /* 2 */
-	{NULL, NULL, 0, NULL, 0}
+	{NULL, NULL, 0, NULL, FALSE, FALSE, 0}
 };
 #define NMC_FIELDS_SETTING_BOND_ALL     "name"","\
                                         NM_SETTING_BOND_INTERFACE_NAME","\
@@ -531,7 +541,7 @@ static NmcOutputField nmc_fields_setting_bond[] = {
 #define NMC_FIELDS_SETTING_BOND_COMMON  NMC_FIELDS_SETTING_BOND_ALL
 
 /* Available fields for NM_SETTING_VLAN_SETTING_NAME */
-static NmcOutputField nmc_fields_setting_vlan[] = {
+NmcOutputField nmc_fields_setting_vlan[] = {
 	SETTING_FIELD ("name",  6),                                        /* 0 */
 	SETTING_FIELD (NM_SETTING_VLAN_INTERFACE_NAME, 15),                /* 1 */
 	SETTING_FIELD (NM_SETTING_VLAN_PARENT, 8),                         /* 2 */
@@ -539,7 +549,7 @@ static NmcOutputField nmc_fields_setting_vlan[] = {
 	SETTING_FIELD (NM_SETTING_VLAN_FLAGS, 45),                         /* 4 */
 	SETTING_FIELD (NM_SETTING_VLAN_INGRESS_PRIORITY_MAP, 22),          /* 5 */
 	SETTING_FIELD (NM_SETTING_VLAN_EGRESS_PRIORITY_MAP, 22),           /* 6 */
-	{NULL, NULL, 0, NULL, 0}
+	{NULL, NULL, 0, NULL, FALSE, FALSE, 0}
 };
 #define NMC_FIELDS_SETTING_VLAN_ALL     "name"","\
                                         NM_SETTING_VLAN_INTERFACE_NAME","\
@@ -551,19 +561,21 @@ static NmcOutputField nmc_fields_setting_vlan[] = {
 #define NMC_FIELDS_SETTING_VLAN_COMMON  NMC_FIELDS_SETTING_VLAN_ALL
 
 /* Available fields for NM_SETTING_BRIDGE_SETTING_NAME */
-static NmcOutputField nmc_fields_setting_bridge[] = {
+NmcOutputField nmc_fields_setting_bridge[] = {
 	SETTING_FIELD ("name",  8),                                        /* 0 */
 	SETTING_FIELD (NM_SETTING_BRIDGE_INTERFACE_NAME, 15),              /* 1 */
-	SETTING_FIELD (NM_SETTING_BRIDGE_STP, 5),                          /* 2 */
-	SETTING_FIELD (NM_SETTING_BRIDGE_PRIORITY, 6),                     /* 3 */
-	SETTING_FIELD (NM_SETTING_BRIDGE_FORWARD_DELAY, 6),                /* 4 */
-	SETTING_FIELD (NM_SETTING_BRIDGE_HELLO_TIME, 6),                   /* 5 */
-	SETTING_FIELD (NM_SETTING_BRIDGE_MAX_AGE, 6),                      /* 6 */
-	SETTING_FIELD (NM_SETTING_BRIDGE_AGEING_TIME, 6),                  /* 7 */
-	{NULL, NULL, 0, NULL, 0}
+	SETTING_FIELD (NM_SETTING_BRIDGE_MAC_ADDRESS, 19),                 /* 2 */
+	SETTING_FIELD (NM_SETTING_BRIDGE_STP, 5),                          /* 3 */
+	SETTING_FIELD (NM_SETTING_BRIDGE_PRIORITY, 6),                     /* 4 */
+	SETTING_FIELD (NM_SETTING_BRIDGE_FORWARD_DELAY, 6),                /* 5 */
+	SETTING_FIELD (NM_SETTING_BRIDGE_HELLO_TIME, 6),                   /* 6 */
+	SETTING_FIELD (NM_SETTING_BRIDGE_MAX_AGE, 6),                      /* 7 */
+	SETTING_FIELD (NM_SETTING_BRIDGE_AGEING_TIME, 6),                  /* 8 */
+	{NULL, NULL, 0, NULL, FALSE, FALSE, 0}
 };
 #define NMC_FIELDS_SETTING_BRIDGE_ALL    "name"","\
                                          NM_SETTING_BRIDGE_INTERFACE_NAME","\
+                                         NM_SETTING_BRIDGE_MAC_ADDRESS","\
                                          NM_SETTING_BRIDGE_STP","\
                                          NM_SETTING_BRIDGE_PRIORITY","\
                                          NM_SETTING_BRIDGE_FORWARD_DELAY","\
@@ -573,12 +585,12 @@ static NmcOutputField nmc_fields_setting_bridge[] = {
 #define NMC_FIELDS_SETTING_BRIDGE_COMMON NMC_FIELDS_SETTING_BRIDGE_ALL
 
 /* Available fields for NM_SETTING_BRIDGE_PORT_SETTING_NAME */
-static NmcOutputField nmc_fields_setting_bridge_port[] = {
+NmcOutputField nmc_fields_setting_bridge_port[] = {
 	SETTING_FIELD ("name",  8),                                        /* 0 */
 	SETTING_FIELD (NM_SETTING_BRIDGE_PORT_PRIORITY, 10),               /* 1 */
 	SETTING_FIELD (NM_SETTING_BRIDGE_PORT_PATH_COST, 12),              /* 2 */
 	SETTING_FIELD (NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, 15),           /* 3 */
-	{NULL, NULL, 0, NULL, 0}
+	{NULL, NULL, 0, NULL, FALSE, FALSE, 0}
 };
 #define NMC_FIELDS_SETTING_BRIDGE_PORT_ALL    "name"","\
                                               NM_SETTING_BRIDGE_PORT_PRIORITY","\
@@ -586,15 +598,76 @@ static NmcOutputField nmc_fields_setting_bridge_port[] = {
                                               NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE
 #define NMC_FIELDS_SETTING_BRIDGE_PORT_COMMON NMC_FIELDS_SETTING_BRIDGE_PORT_ALL
 
+/* Available fields for NM_SETTING_TEAM_SETTING_NAME */
+NmcOutputField nmc_fields_setting_team[] = {
+	SETTING_FIELD ("name",  8),                                        /* 0 */
+	SETTING_FIELD (NM_SETTING_TEAM_INTERFACE_NAME, 15),                /* 1 */
+	SETTING_FIELD (NM_SETTING_TEAM_CONFIG, 30),                        /* 2 */
+	{NULL, NULL, 0, NULL, FALSE, FALSE, 0}
+};
+#define NMC_FIELDS_SETTING_TEAM_ALL     "name"","\
+                                        NM_SETTING_TEAM_INTERFACE_NAME","\
+                                        NM_SETTING_TEAM_CONFIG
+#define NMC_FIELDS_SETTING_TEAM_COMMON  NMC_FIELDS_SETTING_TEAM_ALL
+
+/* Available fields for NM_SETTING_TEAM_PORT_SETTING_NAME */
+NmcOutputField nmc_fields_setting_team_port[] = {
+	SETTING_FIELD ("name",  8),                                        /* 0 */
+	SETTING_FIELD (NM_SETTING_TEAM_PORT_CONFIG, 30),                   /* 1 */
+	{NULL, NULL, 0, NULL, FALSE, FALSE, 0}
+};
+#define NMC_FIELDS_SETTING_TEAM_PORT_ALL     "name"","\
+                                             NM_SETTING_TEAM_PORT_CONFIG
+#define NMC_FIELDS_SETTING_TEAM_PORT_COMMON  NMC_FIELDS_SETTING_TEAM_PORT_ALL
+
+/* Available fields for NM_SETTING_DCB_SETTING_NAME */
+NmcOutputField nmc_fields_setting_dcb[] = {
+	SETTING_FIELD ("name",  8),                                        /* 0 */
+	SETTING_FIELD (NM_SETTING_DCB_APP_FCOE_FLAGS, 5),                  /* 1 */
+	SETTING_FIELD (NM_SETTING_DCB_APP_FCOE_PRIORITY, 5),               /* 2 */
+	SETTING_FIELD (NM_SETTING_DCB_APP_FCOE_MODE, 8),                   /* 3 */
+	SETTING_FIELD (NM_SETTING_DCB_APP_ISCSI_FLAGS, 5),                 /* 4 */
+	SETTING_FIELD (NM_SETTING_DCB_APP_ISCSI_PRIORITY, 5),              /* 5 */
+	SETTING_FIELD (NM_SETTING_DCB_APP_FIP_FLAGS, 5),                   /* 6 */
+	SETTING_FIELD (NM_SETTING_DCB_APP_FIP_PRIORITY, 5),                /* 7 */
+	SETTING_FIELD (NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS, 5),     /* 8 */
+	SETTING_FIELD (NM_SETTING_DCB_PRIORITY_FLOW_CONTROL, 10),          /* 9 */
+	SETTING_FIELD (NM_SETTING_DCB_PRIORITY_GROUP_FLAGS, 5),            /* 10 */
+	SETTING_FIELD (NM_SETTING_DCB_PRIORITY_GROUP_ID, 10),              /* 11 */
+	SETTING_FIELD (NM_SETTING_DCB_PRIORITY_GROUP_BANDWIDTH, 30),       /* 12 */
+	SETTING_FIELD (NM_SETTING_DCB_PRIORITY_BANDWIDTH, 30),             /* 13 */
+	SETTING_FIELD (NM_SETTING_DCB_PRIORITY_STRICT_BANDWIDTH, 10),      /* 14 */
+	SETTING_FIELD (NM_SETTING_DCB_PRIORITY_TRAFFIC_CLASS, 30),         /* 15 */
+	{NULL, NULL, 0, NULL, FALSE, FALSE, 0}
+};
+#define NMC_FIELDS_SETTING_DCB_ALL     "name"","\
+                                       NM_SETTING_DCB_APP_FCOE_FLAGS","\
+                                       NM_SETTING_DCB_APP_FCOE_PRIORITY","\
+                                       NM_SETTING_DCB_APP_FCOE_MODE","\
+                                       NM_SETTING_DCB_APP_ISCSI_FLAGS","\
+                                       NM_SETTING_DCB_APP_ISCSI_PRIORITY","\
+                                       NM_SETTING_DCB_APP_FIP_FLAGS","\
+                                       NM_SETTING_DCB_APP_FIP_PRIORITY","\
+                                       NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS","\
+                                       NM_SETTING_DCB_PRIORITY_FLOW_CONTROL","\
+                                       NM_SETTING_DCB_PRIORITY_GROUP_FLAGS","\
+                                       NM_SETTING_DCB_PRIORITY_GROUP_ID","\
+                                       NM_SETTING_DCB_PRIORITY_GROUP_BANDWIDTH","\
+                                       NM_SETTING_DCB_PRIORITY_BANDWIDTH","\
+                                       NM_SETTING_DCB_PRIORITY_STRICT_BANDWIDTH","\
+                                       NM_SETTING_DCB_PRIORITY_TRAFFIC_CLASS
+#define NMC_FIELDS_SETTING_DCB_COMMON  NMC_FIELDS_SETTING_DCB_ALL
+
+/*----------------------------------------------------------------------------*/
 
 static char *
 wep_key_type_to_string (NMWepKeyType type)
 {
 	switch (type) {
 	case NM_WEP_KEY_TYPE_KEY:
-		return g_strdup_printf (_("%d (hex-ascii-key)"), type);
+		return g_strdup_printf (_("%d (key)"), type);
 	case NM_WEP_KEY_TYPE_PASSPHRASE:
-		return g_strdup_printf (_("%d (104/128-bit passphrase)"), type);
+		return g_strdup_printf (_("%d (passphrase)"), type);
 	case NM_WEP_KEY_TYPE_UNKNOWN:
 	default:
 		return g_strdup_printf (_("%d (unknown)"), type);
@@ -658,7 +731,7 @@ allowed_bands_to_string (guint32 bands)
 		g_string_append (band_str, _("WCDMA 3GPP UMTS 2600 MHz, "));
 
 	if (band_str->str[band_str->len-1] == '(')
-		g_string_assign (band_str, _("unknown"));
+		g_string_append (band_str, _("unknown"));
 	else
 		g_string_truncate (band_str, band_str->len-2);  /* chop off trailing ', ' */
 
@@ -686,7 +759,7 @@ vlan_flags_to_string (guint32 flags)
 		g_string_append (flag_str, _("LOOSE_BINDING, "));
 
 	if (flag_str->str[flag_str->len-1] == '(')
-		g_string_assign (flag_str, _("unknown"));
+		g_string_append (flag_str, _("unknown"));
 	else
 		g_string_truncate (flag_str, flag_str->len-2);  /* chop off trailing ', ' */
 
@@ -748,7 +821,7 @@ secret_flags_to_string (guint32 flags)
 		g_string_append (flag_str, _("not required, "));
 
 	if (flag_str->str[flag_str->len-1] == '(')
-		g_string_assign (flag_str, _("unknown"));
+		g_string_append (flag_str, _("unknown"));
 	else
 		g_string_truncate (flag_str, flag_str->len-2);  /* chop off trailing ', ' */
 
@@ -757,1335 +830,6504 @@ secret_flags_to_string (guint32 flags)
 	return g_string_free (flag_str, FALSE);
 }
 
-/*----------------------------------------------------------------------------*/
-
-gboolean
-setting_details (NMSetting *setting, NmCli *nmc)
+static void
+vpn_data_item (const char *key, const char *value, gpointer user_data)
 {
-	GType setting_type;
+	GString *ret_str = (GString *) user_data;
 
-	g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
+	if (ret_str->len != 0)
+		g_string_append (ret_str, ", ");
 
-	setting_type = G_OBJECT_TYPE (setting);
-
-	if (setting_type == NM_TYPE_SETTING_CONNECTION)
-		return setting_connection_details (NM_SETTING_CONNECTION (setting), nmc);
-	else if (setting_type == NM_TYPE_SETTING_WIRED)
-		return setting_wired_details (NM_SETTING_WIRED (setting), nmc);
-	else if (setting_type == NM_TYPE_SETTING_802_1X)
-		return setting_802_1X_details (NM_SETTING_802_1X (setting), nmc);
-	else if (setting_type == NM_TYPE_SETTING_WIRELESS)
-		return setting_wireless_details (NM_SETTING_WIRELESS (setting), nmc);
-	else if (setting_type == NM_TYPE_SETTING_WIRELESS_SECURITY)
-		return setting_wireless_security_details (NM_SETTING_WIRELESS_SECURITY (setting), nmc);
-	else if (setting_type == NM_TYPE_SETTING_IP4_CONFIG)
-		return setting_ip4_config_details (NM_SETTING_IP4_CONFIG (setting), nmc);
-	else if (setting_type == NM_TYPE_SETTING_IP6_CONFIG)
-		return setting_ip6_config_details (NM_SETTING_IP6_CONFIG (setting), nmc);
-	else if (setting_type == NM_TYPE_SETTING_SERIAL)
-		return setting_serial_details (NM_SETTING_SERIAL (setting), nmc);
-	else if (setting_type == NM_TYPE_SETTING_PPP)
-		return setting_ppp_details (NM_SETTING_PPP (setting), nmc);
-	else if (setting_type == NM_TYPE_SETTING_PPPOE)
-		return setting_pppoe_details (NM_SETTING_PPPOE (setting), nmc);
-	else if (setting_type == NM_TYPE_SETTING_GSM)
-		return setting_gsm_details (NM_SETTING_GSM (setting), nmc);
-	else if (setting_type == NM_TYPE_SETTING_CDMA)
-		return setting_cdma_details (NM_SETTING_CDMA (setting), nmc);
-	else if (setting_type == NM_TYPE_SETTING_BLUETOOTH)
-		return setting_bluetooth_details (NM_SETTING_BLUETOOTH (setting), nmc);
-	else if (setting_type == NM_TYPE_SETTING_OLPC_MESH)
-		return setting_olpc_mesh_details (NM_SETTING_OLPC_MESH (setting), nmc);
-	else if (setting_type == NM_TYPE_SETTING_VPN)
-		return setting_vpn_details (NM_SETTING_VPN (setting), nmc);
-	else if (setting_type == NM_TYPE_SETTING_WIMAX)
-		return setting_wimax_details (NM_SETTING_WIMAX (setting), nmc);
-	else if (setting_type == NM_TYPE_SETTING_INFINIBAND)
-		return setting_infiniband_details (NM_SETTING_INFINIBAND (setting), nmc);
-	else if (setting_type == NM_TYPE_SETTING_BOND)
-		return setting_bond_details (NM_SETTING_BOND (setting), nmc);
-	else if (setting_type == NM_TYPE_SETTING_VLAN)
-		return setting_vlan_details (NM_SETTING_VLAN (setting), nmc);
-	else if (setting_type == NM_TYPE_SETTING_ADSL)
-		return setting_adsl_details (NM_SETTING_ADSL (setting), nmc);
-	else if (setting_type == NM_TYPE_SETTING_BRIDGE)
-		return setting_bridge_details (NM_SETTING_BRIDGE (setting), nmc);
-	else if (setting_type == NM_TYPE_SETTING_BRIDGE_PORT)
-		return setting_bridge_port_details (NM_SETTING_BRIDGE_PORT (setting), nmc);
-	else
-		/* should not be reached */
-		return FALSE;
+	g_string_append_printf (ret_str, "%s = %s", key, value);
 }
 
-gboolean
-setting_connection_details (NMSettingConnection *s_con, NmCli *nmc)
-{
-	guint64 timestamp;
-	char *timestamp_str;
-	const char *perm_item;
-	const char *perm_type;
-	GString *perm = NULL;
-	GString *secondaries = NULL;
-	int i;
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
-
-	g_return_val_if_fail (NM_IS_SETTING_CONNECTION (s_con), FALSE);
 
-	nmc->allowed_fields = nmc_fields_setting_connection;
-	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_CONNECTION_ALL, nmc->allowed_fields, NULL);
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-	print_fields (nmc->print_fields, nmc->allowed_fields);  /* Print field names */
-
-	timestamp = nm_setting_connection_get_timestamp (s_con);
-	timestamp_str = g_strdup_printf ("%" G_GUINT64_FORMAT, timestamp);
-
-	/* get permissions */
-	perm = g_string_new (NULL);
-	for (i = 0; i < nm_setting_connection_get_num_permissions (s_con); i++) {
-		nm_setting_connection_get_permission (s_con, i, &perm_type, &perm_item, NULL);
-		g_string_append_printf (perm, "%s:%s,", perm_type, perm_item);
+/* === property get functions === */
+#define DEFINE_GETTER(func_name, property_name) \
+	static char * \
+	func_name (NMSetting *setting) \
+	{ \
+		char *s; \
+		GValue val = G_VALUE_INIT; \
+		g_value_init (&val, G_TYPE_STRING); \
+		g_object_get_property (G_OBJECT (setting), property_name, &val); \
+		/* Getters return allocated values, and returning the string \
+		 * the GValue copied from the object without unsetting the \
+		 * GValue fulfills that requirement. */ \
+		s = g_value_dup_string (&val); \
+		g_value_unset (&val); \
+		return s; \
 	}
-	if (perm->len > 0)
-		g_string_truncate (perm, perm->len-1); /* remove trailing , */
 
-	/* get secondaries */
-	secondaries = g_string_new (NULL);
-	for (i = 0; i < nm_setting_connection_get_num_secondaries (s_con); i++) {
-		const char *sec_uuid = nm_setting_connection_get_secondary (s_con, i);
-		g_string_append_printf (secondaries, "%s,", sec_uuid);
+#define DEFINE_SECRET_FLAGS_GETTER(func_name, property_name) \
+	static char * \
+	func_name (NMSetting *setting) \
+	{ \
+		guint v; \
+		GValue val = G_VALUE_INIT; \
+		g_value_init (&val, G_TYPE_UINT); \
+		g_object_get_property (G_OBJECT (setting), property_name, &val); \
+		v = g_value_get_uint (&val); \
+		g_value_unset (&val); \
+		return secret_flags_to_string (v); \
 	}
-	if (secondaries->len > 0)
-		g_string_truncate (secondaries, secondaries->len-1); /* remove trailing , */
-
-	nmc->allowed_fields[0].value = NM_SETTING_CONNECTION_SETTING_NAME;
-	nmc->allowed_fields[1].value = nm_setting_connection_get_id (s_con);
-	nmc->allowed_fields[2].value = nm_setting_connection_get_uuid (s_con);
-	nmc->allowed_fields[3].value = nm_setting_connection_get_connection_type (s_con);
-	nmc->allowed_fields[4].value = nm_setting_connection_get_autoconnect (s_con) ? _("yes") : _("no");
-	nmc->allowed_fields[5].value = timestamp_str;
-	nmc->allowed_fields[6].value = nm_setting_connection_get_read_only (s_con) ? ("yes") : _("no");
-	nmc->allowed_fields[7].value = perm->str;
-	nmc->allowed_fields[8].value = nm_setting_connection_get_zone (s_con);
-	nmc->allowed_fields[9].value = nm_setting_connection_get_master (s_con);
-	nmc->allowed_fields[10].value = nm_setting_connection_get_slave_type (s_con);
-	nmc->allowed_fields[11].value = secondaries->str;
-
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
-
-	g_free (timestamp_str);
-	g_string_free (perm, TRUE);
-	g_string_free (secondaries, TRUE);
 
-	return TRUE;
-}
-
-gboolean
-setting_wired_details (NMSettingWired *s_wired, NmCli *nmc)
-{
-	const GByteArray *mac;
-	const GSList *iter;
-	const GPtrArray *s390_channels;
-	int i;
-	char *speed_str, *mtu_str, *device_mac_str = NULL, *cloned_mac_str = NULL;
-	GString *mac_blacklist_s, *s390_channels_s, *s390_options_s;
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
-
-	g_return_val_if_fail (NM_IS_SETTING_WIRED (s_wired), FALSE);
-
-	nmc->allowed_fields = nmc_fields_setting_wired;
-	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_WIRED_ALL, nmc->allowed_fields, NULL);
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-	print_fields (nmc->print_fields, nmc->allowed_fields);  /* Print field names */
-
-	speed_str = g_strdup_printf ("%d", nm_setting_wired_get_speed (s_wired));
-	mtu_str = g_strdup_printf ("%d", nm_setting_wired_get_mtu (s_wired));
-	mac = nm_setting_wired_get_mac_address (s_wired);
-	if (mac)
-		device_mac_str = nm_utils_hwaddr_ntoa (mac->data, ARPHRD_ETHER);
-	mac = nm_setting_wired_get_cloned_mac_address (s_wired);
-	if (mac)
-		cloned_mac_str = nm_utils_hwaddr_ntoa (mac->data, ARPHRD_ETHER);
-
-	mac_blacklist_s = g_string_new (NULL);
-	iter = nm_setting_wired_get_mac_address_blacklist (s_wired);
-	while (iter) {
-		g_string_append_printf (mac_blacklist_s, "%s,", (char *) iter->data);
-		iter = iter->next;
-	}
-	g_string_truncate (mac_blacklist_s, mac_blacklist_s->len-1);  /* chop off trailing ',' */
-
-	s390_channels_s = g_string_new (NULL);
-	s390_channels = nm_setting_wired_get_s390_subchannels (s_wired);
-	for (i = 0; s390_channels && i < s390_channels->len; i++)
-		g_string_append_printf (s390_channels_s, "%s,", (char *) g_ptr_array_index (s390_channels, i));
-	g_string_truncate (s390_channels_s, s390_channels_s->len-1);  /* chop off trailing ',' */
-
-	s390_options_s = g_string_new (NULL);
-	for (i = 0; i < nm_setting_wired_get_num_s390_options (s_wired); i++) {
-		const char *key, *value;
-
-		nm_setting_wired_get_s390_option (s_wired, i, &key, &value);
-		g_string_append_printf (s390_options_s, "%s=%s,", key, value);
+#define DEFINE_HWADDR_GETTER(func_name, property_name) \
+	static char * \
+	func_name (NMSetting *setting) \
+	{ \
+		GValue val = G_VALUE_INIT; \
+		GArray *array; \
+		char *hwaddr = NULL; \
+		g_value_init (&val, DBUS_TYPE_G_UCHAR_ARRAY); \
+		g_object_get_property (G_OBJECT (setting), property_name, &val); \
+		array = g_value_get_boxed (&val); \
+		if (array && array->len) \
+			hwaddr = nm_utils_hwaddr_ntoa_len (array->data, array->len); \
+		g_value_unset (&val); \
+		return hwaddr; \
 	}
-	g_string_truncate (s390_options_s, s390_options_s->len-1);  /* chop off trailing ',' */
-
-	nmc->allowed_fields[0].value = NM_SETTING_WIRED_SETTING_NAME;
-	nmc->allowed_fields[1].value = nm_setting_wired_get_port (s_wired);
-	nmc->allowed_fields[2].value = speed_str;
-	nmc->allowed_fields[3].value = nm_setting_wired_get_duplex (s_wired);
-	nmc->allowed_fields[4].value = nm_setting_wired_get_auto_negotiate (s_wired) ? _("yes") : _("no");
-	nmc->allowed_fields[5].value = device_mac_str;
-	nmc->allowed_fields[6].value = cloned_mac_str;
-	nmc->allowed_fields[7].value = mac_blacklist_s->str;
-	nmc->allowed_fields[8].value = strcmp (mtu_str, "0") ? mtu_str : _("auto");
-	nmc->allowed_fields[9].value = s390_channels_s->str;
-	nmc->allowed_fields[10].value = nm_setting_wired_get_s390_nettype (s_wired);
-	nmc->allowed_fields[11].value = s390_options_s->str;
-
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
 
-	g_free (speed_str);
-	g_free (device_mac_str);
-	g_free (cloned_mac_str);
-	g_free (mtu_str);
-	g_string_free (mac_blacklist_s, TRUE);
-	g_string_free (s390_channels_s, TRUE);
-	g_string_free (s390_options_s, TRUE);
-
-	return TRUE;
-}
+/* --- NM_SETTING_802_1X_SETTING_NAME property get functions --- */
+DEFINE_GETTER (nmc_property_802_1X_get_eap, NM_SETTING_802_1X_EAP)
+DEFINE_GETTER (nmc_property_802_1X_get_identity, NM_SETTING_802_1X_IDENTITY)
+DEFINE_GETTER (nmc_property_802_1X_get_anonymous_identity, NM_SETTING_802_1X_ANONYMOUS_IDENTITY)
+DEFINE_GETTER (nmc_property_802_1X_get_pac_file, NM_SETTING_802_1X_PAC_FILE)
+DEFINE_GETTER (nmc_property_802_1X_get_ca_path, NM_SETTING_802_1X_CA_PATH)
+DEFINE_GETTER (nmc_property_802_1X_get_subject_match, NM_SETTING_802_1X_SUBJECT_MATCH)
+DEFINE_GETTER (nmc_property_802_1X_get_altsubject_matches, NM_SETTING_802_1X_ALTSUBJECT_MATCHES)
+DEFINE_GETTER (nmc_property_802_1X_get_phase1_peapver, NM_SETTING_802_1X_PHASE1_PEAPVER)
+DEFINE_GETTER (nmc_property_802_1X_get_phase1_peaplabel, NM_SETTING_802_1X_PHASE1_PEAPLABEL)
+DEFINE_GETTER (nmc_property_802_1X_get_phase1_fast_provisioning, NM_SETTING_802_1X_PHASE1_FAST_PROVISIONING)
+DEFINE_GETTER (nmc_property_802_1X_get_phase2_auth, NM_SETTING_802_1X_PHASE2_AUTH)
+DEFINE_GETTER (nmc_property_802_1X_get_phase2_autheap, NM_SETTING_802_1X_PHASE2_AUTHEAP)
+DEFINE_GETTER (nmc_property_802_1X_get_phase2_ca_path, NM_SETTING_802_1X_PHASE2_CA_PATH)
+DEFINE_GETTER (nmc_property_802_1X_get_phase2_subject_match, NM_SETTING_802_1X_PHASE2_SUBJECT_MATCH)
+DEFINE_GETTER (nmc_property_802_1X_get_phase2_altsubject_matches, NM_SETTING_802_1X_PHASE2_ALTSUBJECT_MATCHES)
+DEFINE_GETTER (nmc_property_802_1X_get_password, NM_SETTING_802_1X_PASSWORD)
+DEFINE_SECRET_FLAGS_GETTER (nmc_property_802_1X_get_password_flags, NM_SETTING_802_1X_PASSWORD_FLAGS)
+DEFINE_SECRET_FLAGS_GETTER (nmc_property_802_1X_get_password_raw_flags, NM_SETTING_802_1X_PASSWORD_RAW_FLAGS)
+DEFINE_GETTER (nmc_property_802_1X_get_private_key_password, NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD)
+DEFINE_SECRET_FLAGS_GETTER (nmc_property_802_1X_get_private_key_password_flags, NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD_FLAGS)
+DEFINE_GETTER (nmc_property_802_1X_get_phase2_private_key_password, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD)
+DEFINE_SECRET_FLAGS_GETTER (nmc_property_802_1X_get_phase2_private_key_password_flags, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD_FLAGS)
+DEFINE_GETTER (nmc_property_802_1X_get_pin, NM_SETTING_802_1X_PIN)
+DEFINE_SECRET_FLAGS_GETTER (nmc_property_802_1X_get_pin_flags, NM_SETTING_802_1X_PIN_FLAGS)
+DEFINE_GETTER (nmc_property_802_1X_get_system_ca_certs, NM_SETTING_802_1X_SYSTEM_CA_CERTS)
 
-gboolean
-setting_802_1X_details (NMSetting8021x *s_8021X, NmCli *nmc)
+static char *
+nmc_property_802_1X_get_ca_cert (NMSetting *setting)
 {
+	NMSetting8021x *s_8021X = NM_SETTING_802_1X (setting);
 	NMSetting8021xCKScheme scheme;
-	GString *eap_str, *alt_sub_match, *phase2_alt_sub_match;
-	char *ca_cert_str = NULL, *client_cert_str = NULL, *phase2_ca_cert_str = NULL;
-	char *phase2_client_cert_str = NULL, *private_key_str = NULL, *phase2_private_key_str = NULL, *pswd_raw_str = NULL;
-	char *pswd_flags, *pswd_raw_flags, *priv_key_pswd_flags, *phase2_priv_key_pswd_flags, *pin_flags;
-	int i;
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
-
-	g_return_val_if_fail (NM_IS_SETTING_802_1X (s_8021X), FALSE);
+	char *ca_cert_str = NULL;
 
-	nmc->allowed_fields = nmc_fields_setting_8021X;
-	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_802_1X_ALL, nmc->allowed_fields, NULL);
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-	print_fields (nmc->print_fields, nmc->allowed_fields);  /* Print field names */
-
-	eap_str = g_string_new (NULL);
-	for (i = 0; i < nm_setting_802_1x_get_num_eap_methods (s_8021X); i++) {
-		if (i > 0)
-			g_string_append_c (eap_str, ',');
-		g_string_append (eap_str, nm_setting_802_1x_get_eap_method (s_8021X, i));
-	}
 	scheme = nm_setting_802_1x_get_ca_cert_scheme (s_8021X);
 	if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB)
 		ca_cert_str = byte_array_to_string (nm_setting_802_1x_get_ca_cert_blob (s_8021X));
 	if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH)
 		ca_cert_str = g_strdup (nm_setting_802_1x_get_ca_cert_path (s_8021X));
 
+	return ca_cert_str;
+}
+
+static char *
+nmc_property_802_1X_get_client_cert (NMSetting *setting)
+{
+	NMSetting8021x *s_8021X = NM_SETTING_802_1X (setting);
+	NMSetting8021xCKScheme scheme;
+	char *client_cert_str = NULL;
+
 	scheme = nm_setting_802_1x_get_client_cert_scheme (s_8021X);
 	if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB)
 		client_cert_str = byte_array_to_string (nm_setting_802_1x_get_client_cert_blob (s_8021X));
 	if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH)
 		client_cert_str = g_strdup (nm_setting_802_1x_get_client_cert_path (s_8021X));
 
+	return client_cert_str;
+}
+
+static char *
+nmc_property_802_1X_get_phase2_ca_cert (NMSetting *setting)
+{
+	NMSetting8021x *s_8021X = NM_SETTING_802_1X (setting);
+	NMSetting8021xCKScheme scheme;
+	char *phase2_ca_cert_str = NULL;
+
 	scheme = nm_setting_802_1x_get_phase2_ca_cert_scheme (s_8021X);
 	if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB)
 		phase2_ca_cert_str = byte_array_to_string (nm_setting_802_1x_get_phase2_ca_cert_blob (s_8021X));
 	if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH)
 		phase2_ca_cert_str = g_strdup (nm_setting_802_1x_get_phase2_ca_cert_path (s_8021X));
 
+	return phase2_ca_cert_str;
+}
+
+static char *
+nmc_property_802_1X_get_phase2_client_cert (NMSetting *setting)
+{
+	NMSetting8021x *s_8021X = NM_SETTING_802_1X (setting);
+	NMSetting8021xCKScheme scheme;
+	char *phase2_client_cert_str = NULL;
+
 	scheme = nm_setting_802_1x_get_phase2_client_cert_scheme (s_8021X);
 	if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB)
 		phase2_client_cert_str = byte_array_to_string (nm_setting_802_1x_get_phase2_client_cert_blob (s_8021X));
 	if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH)
 		phase2_client_cert_str = g_strdup (nm_setting_802_1x_get_phase2_client_cert_path (s_8021X));
 
+	return phase2_client_cert_str;
+}
+
+static char *
+nmc_property_802_1X_get_password_raw (NMSetting *setting)
+{
+	NMSetting8021x *s_8021X = NM_SETTING_802_1X (setting);
+	return byte_array_to_string (nm_setting_802_1x_get_password_raw (s_8021X));
+}
+
+static char *
+nmc_property_802_1X_get_private_key (NMSetting *setting)
+{
+	NMSetting8021x *s_8021X = NM_SETTING_802_1X (setting);
+	NMSetting8021xCKScheme scheme;
+	char *private_key_str = NULL;
+
 	scheme = nm_setting_802_1x_get_private_key_scheme (s_8021X);
 	if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB)
 		private_key_str = byte_array_to_string (nm_setting_802_1x_get_private_key_blob (s_8021X));
 	if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH)
 		private_key_str = g_strdup (nm_setting_802_1x_get_private_key_path (s_8021X));
 
+	return private_key_str;
+}
+
+static char *
+nmc_property_802_1X_get_phase2_private_key (NMSetting *setting)
+{
+	NMSetting8021x *s_8021X = NM_SETTING_802_1X (setting);
+	NMSetting8021xCKScheme scheme;
+	char *phase2_private_key_str = NULL;
+
 	scheme = nm_setting_802_1x_get_phase2_private_key_scheme (s_8021X);
 	if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB)
 		phase2_private_key_str = byte_array_to_string (nm_setting_802_1x_get_phase2_private_key_blob (s_8021X));
 	if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH)
 		phase2_private_key_str = g_strdup (nm_setting_802_1x_get_phase2_private_key_path (s_8021X));
 
-	alt_sub_match = g_string_new (NULL);
-	for (i = 0; i < nm_setting_802_1x_get_num_altsubject_matches (s_8021X); i++)
-		g_string_append_printf (alt_sub_match, "%s,", nm_setting_802_1x_get_altsubject_match (s_8021X, i));
-	g_string_truncate (alt_sub_match, alt_sub_match->len-1);  /* chop off trailing ',' */
-
-	phase2_alt_sub_match = g_string_new (NULL);
-	for (i = 0; i < nm_setting_802_1x_get_num_phase2_altsubject_matches (s_8021X); i++)
-		g_string_append_printf (phase2_alt_sub_match, "%s,", nm_setting_802_1x_get_phase2_altsubject_match (s_8021X, i));
-	g_string_truncate (phase2_alt_sub_match, phase2_alt_sub_match->len-1);  /* chop off trailing ',' */
-
-	pswd_raw_str = byte_array_to_string (nm_setting_802_1x_get_password_raw (s_8021X));
-
-	pswd_flags = secret_flags_to_string (nm_setting_802_1x_get_password_flags (s_8021X));
-	pswd_raw_flags = secret_flags_to_string (nm_setting_802_1x_get_password_raw_flags (s_8021X));
-	priv_key_pswd_flags = secret_flags_to_string (nm_setting_802_1x_get_private_key_password_flags (s_8021X));
-	phase2_priv_key_pswd_flags = secret_flags_to_string (nm_setting_802_1x_get_phase2_private_key_password_flags (s_8021X));
-	pin_flags = secret_flags_to_string (nm_setting_802_1x_get_pin_flags (s_8021X));
-
-	nmc->allowed_fields[0].value = NM_SETTING_802_1X_SETTING_NAME;
-	nmc->allowed_fields[1].value = eap_str->str;
-	nmc->allowed_fields[2].value = nm_setting_802_1x_get_identity (s_8021X);
-	nmc->allowed_fields[3].value = nm_setting_802_1x_get_anonymous_identity (s_8021X);
-	nmc->allowed_fields[4].value = nm_setting_802_1x_get_pac_file (s_8021X);
-	nmc->allowed_fields[5].value = ca_cert_str;
-	nmc->allowed_fields[6].value = nm_setting_802_1x_get_ca_path (s_8021X);
-	nmc->allowed_fields[7].value = nm_setting_802_1x_get_subject_match (s_8021X);
-	nmc->allowed_fields[8].value = alt_sub_match->str;
-	nmc->allowed_fields[9].value = client_cert_str;
-	nmc->allowed_fields[10].value = nm_setting_802_1x_get_phase1_peapver (s_8021X);
-	nmc->allowed_fields[11].value = nm_setting_802_1x_get_phase1_peaplabel (s_8021X);
-	nmc->allowed_fields[12].value = nm_setting_802_1x_get_phase1_fast_provisioning (s_8021X);
-	nmc->allowed_fields[13].value = nm_setting_802_1x_get_phase2_auth (s_8021X);
-	nmc->allowed_fields[14].value = nm_setting_802_1x_get_phase2_autheap (s_8021X);
-	nmc->allowed_fields[15].value = phase2_ca_cert_str;
-	nmc->allowed_fields[16].value = nm_setting_802_1x_get_phase2_ca_path (s_8021X);
-	nmc->allowed_fields[17].value = nm_setting_802_1x_get_phase2_subject_match (s_8021X);
-	nmc->allowed_fields[18].value = phase2_alt_sub_match->str;
-	nmc->allowed_fields[19].value = phase2_client_cert_str;
-	nmc->allowed_fields[20].value = nm_setting_802_1x_get_password (s_8021X);
-	nmc->allowed_fields[21].value = pswd_flags;
-	nmc->allowed_fields[22].value = pswd_raw_str;
-	nmc->allowed_fields[23].value = pswd_raw_flags;
-	nmc->allowed_fields[24].value = private_key_str;
-	nmc->allowed_fields[25].value = nm_setting_802_1x_get_private_key_password (s_8021X);
-	nmc->allowed_fields[26].value = priv_key_pswd_flags;
-	nmc->allowed_fields[27].value = phase2_private_key_str;
-	nmc->allowed_fields[28].value = nm_setting_802_1x_get_phase2_private_key_password (s_8021X);
-	nmc->allowed_fields[29].value = phase2_priv_key_pswd_flags;
-	nmc->allowed_fields[30].value = nm_setting_802_1x_get_pin (s_8021X);
-	nmc->allowed_fields[31].value = pin_flags;
-	nmc->allowed_fields[32].value = nm_setting_802_1x_get_system_ca_certs (s_8021X) ? _("yes") : _("no");
-
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
-
-	g_free (ca_cert_str);
-	g_free (client_cert_str);
-	g_free (phase2_ca_cert_str);
-	g_free (phase2_client_cert_str);
-	g_free (private_key_str);
-	g_free (phase2_private_key_str);
-	g_free (pswd_flags);
-	g_free (pswd_raw_str);
-	g_free (pswd_raw_flags);
-	g_free (priv_key_pswd_flags);
-	g_free (phase2_priv_key_pswd_flags);
-	g_free (pin_flags);
-	g_string_free (eap_str, TRUE);
-	g_string_free (alt_sub_match, TRUE);
-	g_string_free (phase2_alt_sub_match, TRUE);
+	return phase2_private_key_str;
+}
 
-	return TRUE;
+/* --- NM_SETTING_ADSL_SETTING_NAME property get functions --- */
+DEFINE_GETTER (nmc_property_adsl_get_username, NM_SETTING_ADSL_USERNAME)
+DEFINE_GETTER (nmc_property_adsl_get_password, NM_SETTING_ADSL_PASSWORD)
+DEFINE_SECRET_FLAGS_GETTER (nmc_property_adsl_get_password_flags, NM_SETTING_ADSL_PASSWORD_FLAGS)
+DEFINE_GETTER (nmc_property_adsl_get_protocol, NM_SETTING_ADSL_PROTOCOL)
+DEFINE_GETTER (nmc_property_adsl_get_encapsulation, NM_SETTING_ADSL_ENCAPSULATION)
+DEFINE_GETTER (nmc_property_adsl_get_vpi, NM_SETTING_ADSL_VPI)
+DEFINE_GETTER (nmc_property_adsl_get_vci, NM_SETTING_ADSL_VCI)
+
+/* --- NM_SETTING_BLUETOOTH_SETTING_NAME property get functions --- */
+DEFINE_HWADDR_GETTER (nmc_property_bluetooth_get_bdaddr, NM_SETTING_BLUETOOTH_BDADDR)
+DEFINE_GETTER (nmc_property_bluetooth_get_type, NM_SETTING_BLUETOOTH_TYPE)
+
+/* --- NM_SETTING_BOND_SETTING_NAME property get functions --- */
+DEFINE_GETTER (nmc_property_bond_get_interface_name, NM_SETTING_BOND_INTERFACE_NAME)
+
+static char *
+nmc_property_bond_get_options (NMSetting *setting)
+{
+	NMSettingBond *s_bond = NM_SETTING_BOND (setting);
+	GString *bond_options_s;
+	int i;
+
+	bond_options_s = g_string_new (NULL);
+	for (i = 0; i < nm_setting_bond_get_num_options (s_bond); i++) {
+		const char *key, *value;
+
+		nm_setting_bond_get_option (s_bond, i, &key, &value);
+		g_string_append_printf (bond_options_s, "%s=%s,", key, value);
+	}
+	g_string_truncate (bond_options_s, bond_options_s->len-1);  /* chop off trailing ',' */
+
+	return g_string_free (bond_options_s, FALSE);
 }
 
-gboolean
-setting_wireless_details (NMSettingWireless *s_wireless, NmCli *nmc)
+/* --- NM_SETTING_BRIDGE_SETTING_NAME property get functions --- */
+DEFINE_GETTER (nmc_property_bridge_get_interface_name, NM_SETTING_BRIDGE_INTERFACE_NAME)
+DEFINE_HWADDR_GETTER (nmc_property_bridge_get_mac_address, NM_SETTING_BRIDGE_MAC_ADDRESS)
+DEFINE_GETTER (nmc_property_bridge_get_stp, NM_SETTING_BRIDGE_STP)
+DEFINE_GETTER (nmc_property_bridge_get_priority, NM_SETTING_BRIDGE_PRIORITY)
+DEFINE_GETTER (nmc_property_bridge_get_forward_delay, NM_SETTING_BRIDGE_FORWARD_DELAY)
+DEFINE_GETTER (nmc_property_bridge_get_hello_time, NM_SETTING_BRIDGE_HELLO_TIME)
+DEFINE_GETTER (nmc_property_bridge_get_max_age, NM_SETTING_BRIDGE_MAX_AGE)
+DEFINE_GETTER (nmc_property_bridge_get_ageing_time, NM_SETTING_BRIDGE_AGEING_TIME)
+
+/* --- NM_SETTING_BRIDGE_PORT_SETTING_NAME property get functions --- */
+DEFINE_GETTER (nmc_property_bridge_port_get_priority, NM_SETTING_BRIDGE_PORT_PRIORITY)
+DEFINE_GETTER (nmc_property_bridge_port_get_path_cost, NM_SETTING_BRIDGE_PORT_PATH_COST)
+DEFINE_GETTER (nmc_property_bridge_port_get_hairpin_mode, NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE)
+
+/* --- NM_SETTING_TEAM_SETTING_NAME property get functions --- */
+DEFINE_GETTER (nmc_property_team_get_interface_name, NM_SETTING_TEAM_INTERFACE_NAME)
+DEFINE_GETTER (nmc_property_team_get_config, NM_SETTING_TEAM_CONFIG)
+
+/* --- NM_SETTING_TEAM_PORT_SETTING_NAME property get functions --- */
+DEFINE_GETTER (nmc_property_team_port_get_config, NM_SETTING_TEAM_PORT_CONFIG)
+
+/* --- NM_SETTING_CDMA_SETTING_NAME property get functions --- */
+DEFINE_GETTER (nmc_property_cdma_get_number, NM_SETTING_CDMA_NUMBER)
+DEFINE_GETTER (nmc_property_cdma_get_username, NM_SETTING_CDMA_USERNAME)
+DEFINE_GETTER (nmc_property_cdma_get_password, NM_SETTING_CDMA_PASSWORD)
+
+DEFINE_SECRET_FLAGS_GETTER (nmc_property_cdma_get_password_flags, NM_SETTING_CDMA_PASSWORD_FLAGS)
+
+/* --- NM_SETTING_CONNECTION_SETTING_NAME property get functions --- */
+DEFINE_GETTER (nmc_property_connection_get_id, NM_SETTING_CONNECTION_ID)
+DEFINE_GETTER (nmc_property_connection_get_uuid, NM_SETTING_CONNECTION_UUID)
+DEFINE_GETTER (nmc_property_connection_get_interface_name, NM_SETTING_CONNECTION_INTERFACE_NAME)
+DEFINE_GETTER (nmc_property_connection_get_type, NM_SETTING_CONNECTION_TYPE)
+DEFINE_GETTER (nmc_property_connection_get_autoconnect, NM_SETTING_CONNECTION_AUTOCONNECT)
+DEFINE_GETTER (nmc_property_connection_get_timestamp, NM_SETTING_CONNECTION_TIMESTAMP)
+DEFINE_GETTER (nmc_property_connection_get_read_only, NM_SETTING_CONNECTION_READ_ONLY)
+
+static char *
+nmc_property_connection_get_permissions (NMSetting *setting)
 {
+	NMSettingConnection *s_con = NM_SETTING_CONNECTION (setting);
+	GString *perm = NULL;
+	const char *perm_item;
+	const char *perm_type;
 	int i;
-	const GByteArray *ssid, *bssid, *mac;
-	char *channel_str, *rate_str, *tx_power_str, *mtu_str;
-	char *device_mac_str = NULL, *cloned_mac_str = NULL, *ssid_str = NULL, *bssid_str = NULL;
-	GString *mac_blacklist, *seen_bssids;
-	const GSList *iter;
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
 
-	g_return_val_if_fail (NM_IS_SETTING_WIRELESS (s_wireless), FALSE);
+	perm = g_string_new (NULL);
+	for (i = 0; i < nm_setting_connection_get_num_permissions (s_con); i++) {
+		if (nm_setting_connection_get_permission (s_con, i, &perm_type, &perm_item, NULL))
+			g_string_append_printf (perm, "%s:%s,", perm_type, perm_item);
+	}
+	if (perm->len > 0)
+		g_string_truncate (perm, perm->len-1); /* remove trailing , */
+
+	return g_string_free (perm, FALSE);
+}
+
+DEFINE_GETTER (nmc_property_connection_get_zone, NM_SETTING_CONNECTION_ZONE)
+DEFINE_GETTER (nmc_property_connection_get_master, NM_SETTING_CONNECTION_MASTER)
+DEFINE_GETTER (nmc_property_connection_get_slave_type, NM_SETTING_CONNECTION_SLAVE_TYPE)
+DEFINE_GETTER (nmc_property_connection_get_secondaries, NM_SETTING_CONNECTION_SECONDARIES)
+DEFINE_GETTER (nmc_property_connection_get_gateway_ping_timeout, NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT)
+
+/* --- NM_SETTING_DCB_SETTING_NAME property get functions --- */
+static char *
+dcb_flags_to_string (NMSettingDcbFlags flags)
+{
+	GString *flag_str;
+
+	if (flags == 0)
+		return g_strdup (_("0 (disabled)"));
+
+	flag_str = g_string_new (NULL);
+	g_string_printf (flag_str, "%d (", flags);
+
+	if (flags & NM_SETTING_DCB_FLAG_ENABLE)
+		g_string_append (flag_str, _("enabled, "));
+	if (flags & NM_SETTING_DCB_FLAG_ADVERTISE)
+		g_string_append (flag_str, _("advertise, "));
+	if (flags & NM_SETTING_DCB_FLAG_WILLING)
+		g_string_append (flag_str, _("willing, "));
+
+	if (flag_str->str[flag_str->len-1] == '(')
+		g_string_append (flag_str, _("unknown"));
+	else
+		g_string_truncate (flag_str, flag_str->len-2);  /* chop off trailing ', ' */
+
+	g_string_append_c (flag_str, ')');
+
+	return g_string_free (flag_str, FALSE);
+}
+
+#define DEFINE_DCB_FLAGS_GETTER(func_name, property_name) \
+	static char * \
+	func_name (NMSetting *setting) \
+	{ \
+		guint v; \
+		GValue val = G_VALUE_INIT; \
+		g_value_init (&val, G_TYPE_UINT); \
+		g_object_get_property (G_OBJECT (setting), property_name, &val); \
+		v = g_value_get_uint (&val); \
+		g_value_unset (&val); \
+		return dcb_flags_to_string (v); \
+	}
+
+static char *
+dcb_app_priority_to_string (gint priority)
+{
+	return (priority == -1) ? g_strdup (_("-1 (unset)")) : g_strdup_printf ("%d", priority);
+}
+
+#define DEFINE_DCB_APP_PRIORITY_GETTER(func_name, property_name) \
+	static char * \
+	func_name (NMSetting *setting) \
+	{ \
+		int v; \
+		GValue val = G_VALUE_INIT; \
+		g_value_init (&val, G_TYPE_INT); \
+		g_object_get_property (G_OBJECT (setting), property_name, &val); \
+		v = g_value_get_int (&val); \
+		g_value_unset (&val); \
+		return dcb_app_priority_to_string (v); \
+	}
 
-	nmc->allowed_fields = nmc_fields_setting_wireless;
-	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_WIRELESS_ALL, nmc->allowed_fields, NULL);
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-	print_fields (nmc->print_fields, nmc->allowed_fields);  /* Print field names */
+#define DEFINE_DCB_BOOL_GETTER(func_name, getter_func_name) \
+	static char * \
+	func_name (NMSetting *setting) \
+	{ \
+		NMSettingDcb *s_dcb = NM_SETTING_DCB (setting); \
+		GString *str; \
+		guint i; \
+ \
+		str = g_string_new (NULL); \
+		for (i = 0; i < 8; i++) { \
+			if (getter_func_name (s_dcb,  i)) \
+				g_string_append_c (str, '1'); \
+			else \
+				g_string_append_c (str, '0'); \
+\
+			if (i < 7) \
+				g_string_append_c (str, ','); \
+		} \
+\
+		return g_string_free (str, FALSE); \
+	}
+
+#define DEFINE_DCB_UINT_GETTER(func_name, getter_func_name) \
+	static char * \
+	func_name (NMSetting *setting) \
+	{ \
+		NMSettingDcb *s_dcb = NM_SETTING_DCB (setting); \
+		GString *str; \
+		guint i; \
+ \
+		str = g_string_new (NULL); \
+		for (i = 0; i < 8; i++) { \
+			g_string_append_printf (str, "%u", getter_func_name (s_dcb, i)); \
+			if (i < 7) \
+				g_string_append_c (str, ','); \
+		} \
+\
+		return g_string_free (str, FALSE); \
+	}
+
+DEFINE_DCB_FLAGS_GETTER (nmc_property_dcb_get_app_fcoe_flags, NM_SETTING_DCB_APP_FCOE_FLAGS)
+DEFINE_DCB_APP_PRIORITY_GETTER (nmc_property_dcb_get_app_fcoe_priority, NM_SETTING_DCB_APP_FCOE_PRIORITY)
+DEFINE_GETTER (nmc_property_dcb_get_app_fcoe_mode, NM_SETTING_DCB_APP_FCOE_MODE)
+DEFINE_DCB_FLAGS_GETTER (nmc_property_dcb_get_app_iscsi_flags, NM_SETTING_DCB_APP_ISCSI_FLAGS)
+DEFINE_DCB_APP_PRIORITY_GETTER (nmc_property_dcb_get_app_iscsi_priority, NM_SETTING_DCB_APP_ISCSI_PRIORITY)
+DEFINE_DCB_FLAGS_GETTER (nmc_property_dcb_get_app_fip_flags, NM_SETTING_DCB_APP_FIP_FLAGS)
+DEFINE_DCB_APP_PRIORITY_GETTER (nmc_property_dcb_get_app_fip_priority, NM_SETTING_DCB_APP_FIP_PRIORITY)
+
+DEFINE_DCB_FLAGS_GETTER (nmc_property_dcb_get_pfc_flags, NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS)
+DEFINE_DCB_BOOL_GETTER (nmc_property_dcb_get_pfc, nm_setting_dcb_get_priority_flow_control)
+
+DEFINE_DCB_FLAGS_GETTER (nmc_property_dcb_get_pg_flags, NM_SETTING_DCB_PRIORITY_GROUP_FLAGS)
+DEFINE_DCB_UINT_GETTER (nmc_property_dcb_get_pg_group_id, nm_setting_dcb_get_priority_group_id)
+DEFINE_DCB_UINT_GETTER (nmc_property_dcb_get_pg_group_bandwidth, nm_setting_dcb_get_priority_group_bandwidth)
+DEFINE_DCB_UINT_GETTER (nmc_property_dcb_get_pg_bandwidth, nm_setting_dcb_get_priority_bandwidth)
+DEFINE_DCB_BOOL_GETTER (nmc_property_dcb_get_pg_strict, nm_setting_dcb_get_priority_strict_bandwidth)
+DEFINE_DCB_UINT_GETTER (nmc_property_dcb_get_pg_traffic_class, nm_setting_dcb_get_priority_traffic_class)
+
+/* --- NM_SETTING_GSM_SETTING_NAME property get functions --- */
+DEFINE_GETTER (nmc_property_gsm_get_number, NM_SETTING_GSM_NUMBER)
+DEFINE_GETTER (nmc_property_gsm_get_username, NM_SETTING_GSM_USERNAME)
+DEFINE_GETTER (nmc_property_gsm_get_password, NM_SETTING_GSM_PASSWORD)
+DEFINE_SECRET_FLAGS_GETTER (nmc_property_gsm_get_password_flags, NM_SETTING_GSM_PASSWORD_FLAGS)
+DEFINE_GETTER (nmc_property_gsm_get_apn, NM_SETTING_GSM_APN)
+DEFINE_GETTER (nmc_property_gsm_get_network_id, NM_SETTING_GSM_NETWORK_ID)
+DEFINE_GETTER (nmc_property_gsm_get_network_type, NM_SETTING_GSM_NETWORK_TYPE)
+
+static char *
+nmc_property_gsm_get_allowed_bands (NMSetting *setting)
+{
+	NMSettingGsm *s_gsm = NM_SETTING_GSM (setting);
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+	return allowed_bands_to_string (nm_setting_gsm_get_allowed_bands (s_gsm));
+G_GNUC_END_IGNORE_DEPRECATIONS
+}
+
+DEFINE_GETTER (nmc_property_gsm_get_pin, NM_SETTING_GSM_PIN)
+DEFINE_SECRET_FLAGS_GETTER (nmc_property_gsm_get_pin_flags, NM_SETTING_GSM_PIN_FLAGS)
+DEFINE_GETTER (nmc_property_gsm_get_home_only, NM_SETTING_GSM_HOME_ONLY)
+
+/* --- NM_SETTING_INFINIBAND_SETTING_NAME property get functions --- */
+DEFINE_HWADDR_GETTER (nmc_property_ib_get_mac_address, NM_SETTING_INFINIBAND_MAC_ADDRESS)
+DEFINE_GETTER (nmc_property_ib_get_transport_mode, NM_SETTING_INFINIBAND_TRANSPORT_MODE)
+
+static char *
+nmc_property_ib_get_mtu (NMSetting *setting)
+{
+	NMSettingInfiniband *s_infiniband = NM_SETTING_INFINIBAND (setting);
+	int mtu;
+
+	mtu = nm_setting_infiniband_get_mtu (s_infiniband);
+	if (mtu == 0)
+		return g_strdup (_("auto"));
+	else
+		return g_strdup_printf ("%d", mtu);
+}
+
+static char *
+nmc_property_ib_get_p_key (NMSetting *setting)
+{
+	NMSettingInfiniband *s_infiniband = NM_SETTING_INFINIBAND (setting);
+	int p_key;
+
+	p_key = nm_setting_infiniband_get_p_key (s_infiniband);
+	if (p_key == -1)
+		return g_strdup (_("default"));
+	else
+		return g_strdup_printf ("0x%04x", p_key);
+}
+
+DEFINE_GETTER (nmc_property_ib_get_parent, NM_SETTING_INFINIBAND_PARENT)
+
+/* --- NM_SETTING_IP4_CONFIG_SETTING_NAME property get functions --- */
+DEFINE_GETTER (nmc_property_ipv4_get_method, NM_SETTING_IP4_CONFIG_METHOD)
+DEFINE_GETTER (nmc_property_ipv4_get_dns, NM_SETTING_IP4_CONFIG_DNS)
+DEFINE_GETTER (nmc_property_ipv4_get_dns_search, NM_SETTING_IP4_CONFIG_DNS_SEARCH)
+DEFINE_GETTER (nmc_property_ipv4_get_addresses, NM_SETTING_IP4_CONFIG_ADDRESSES)
+DEFINE_GETTER (nmc_property_ipv4_get_routes, NM_SETTING_IP4_CONFIG_ROUTES)
+DEFINE_GETTER (nmc_property_ipv4_get_ignore_auto_routes, NM_SETTING_IP4_CONFIG_IGNORE_AUTO_ROUTES)
+DEFINE_GETTER (nmc_property_ipv4_get_ignore_auto_dns, NM_SETTING_IP4_CONFIG_IGNORE_AUTO_DNS)
+DEFINE_GETTER (nmc_property_ipv4_get_dhcp_client_id, NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID)
+DEFINE_GETTER (nmc_property_ipv4_get_dhcp_send_hostname, NM_SETTING_IP4_CONFIG_DHCP_SEND_HOSTNAME)
+DEFINE_GETTER (nmc_property_ipv4_get_dhcp_hostname, NM_SETTING_IP4_CONFIG_DHCP_HOSTNAME)
+DEFINE_GETTER (nmc_property_ipv4_get_never_default, NM_SETTING_IP4_CONFIG_NEVER_DEFAULT)
+DEFINE_GETTER (nmc_property_ipv4_get_may_fail, NM_SETTING_IP4_CONFIG_MAY_FAIL)
+
+/* --- NM_SETTING_IP6_CONFIG_SETTING_NAME property get functions --- */
+DEFINE_GETTER (nmc_property_ipv6_get_method, NM_SETTING_IP6_CONFIG_METHOD)
+DEFINE_GETTER (nmc_property_ipv6_get_dns, NM_SETTING_IP6_CONFIG_DNS)
+DEFINE_GETTER (nmc_property_ipv6_get_dns_search, NM_SETTING_IP6_CONFIG_DNS_SEARCH)
+DEFINE_GETTER (nmc_property_ipv6_get_addresses, NM_SETTING_IP6_CONFIG_ADDRESSES)
+DEFINE_GETTER (nmc_property_ipv6_get_routes, NM_SETTING_IP6_CONFIG_ROUTES)
+DEFINE_GETTER (nmc_property_ipv6_get_ignore_auto_routes, NM_SETTING_IP6_CONFIG_IGNORE_AUTO_ROUTES)
+DEFINE_GETTER (nmc_property_ipv6_get_ignore_auto_dns, NM_SETTING_IP6_CONFIG_IGNORE_AUTO_DNS)
+DEFINE_GETTER (nmc_property_ipv6_get_never_default, NM_SETTING_IP6_CONFIG_NEVER_DEFAULT)
+DEFINE_GETTER (nmc_property_ipv6_get_may_fail, NM_SETTING_IP6_CONFIG_MAY_FAIL)
+DEFINE_GETTER (nmc_property_ipv6_get_dhcp_hostname, NM_SETTING_IP6_CONFIG_DHCP_HOSTNAME)
+
+static char *
+nmc_property_ipv6_get_ip6_privacy (NMSetting *setting)
+{
+	NMSettingIP6Config *s_ip6 = NM_SETTING_IP6_CONFIG (setting);
+	return ip6_privacy_to_string (nm_setting_ip6_config_get_ip6_privacy (s_ip6));
+}
+
+/* --- NM_SETTING_OLPC_MESH_SETTING_NAME property get functions --- */
+DEFINE_GETTER (nmc_property_olpc_get_channel, NM_SETTING_OLPC_MESH_CHANNEL)
+DEFINE_HWADDR_GETTER (nmc_property_olpc_get_anycast_address, NM_SETTING_OLPC_MESH_DHCP_ANYCAST_ADDRESS)
+
+static char *
+nmc_property_olpc_get_ssid (NMSetting *setting)
+{
+	NMSettingOlpcMesh *s_olpc_mesh = NM_SETTING_OLPC_MESH (setting);
+	const GByteArray *ssid;
+	char *ssid_str = NULL;
+
+	ssid = nm_setting_olpc_mesh_get_ssid (s_olpc_mesh);
+	if (ssid)
+		ssid_str = nm_utils_ssid_to_utf8 (ssid);
+
+	return ssid_str;
+}
+
+/* --- NM_SETTING_PPP_SETTING_NAME property get functions --- */
+DEFINE_GETTER (nmc_property_ppp_get_noauth, NM_SETTING_PPP_NOAUTH)
+DEFINE_GETTER (nmc_property_ppp_get_refuse_eap, NM_SETTING_PPP_REFUSE_EAP)
+DEFINE_GETTER (nmc_property_ppp_get_refuse_pap, NM_SETTING_PPP_REFUSE_PAP)
+DEFINE_GETTER (nmc_property_ppp_get_refuse_chap, NM_SETTING_PPP_REFUSE_CHAP)
+DEFINE_GETTER (nmc_property_ppp_get_refuse_mschap, NM_SETTING_PPP_REFUSE_MSCHAP)
+DEFINE_GETTER (nmc_property_ppp_get_refuse_mschapv2, NM_SETTING_PPP_REFUSE_MSCHAPV2)
+DEFINE_GETTER (nmc_property_ppp_get_nobsdcomp, NM_SETTING_PPP_NOBSDCOMP)
+DEFINE_GETTER (nmc_property_ppp_get_nodeflate, NM_SETTING_PPP_NODEFLATE)
+DEFINE_GETTER (nmc_property_ppp_get_no_vj_comp, NM_SETTING_PPP_NO_VJ_COMP)
+DEFINE_GETTER (nmc_property_ppp_get_require_mppe, NM_SETTING_PPP_REQUIRE_MPPE)
+DEFINE_GETTER (nmc_property_ppp_get_require_mppe_128, NM_SETTING_PPP_REQUIRE_MPPE_128)
+DEFINE_GETTER (nmc_property_ppp_get_mppe_stateful, NM_SETTING_PPP_MPPE_STATEFUL)
+DEFINE_GETTER (nmc_property_ppp_get_crtscts, NM_SETTING_PPP_CRTSCTS)
+DEFINE_GETTER (nmc_property_ppp_get_baud, NM_SETTING_PPP_BAUD)
+DEFINE_GETTER (nmc_property_ppp_get_mru, NM_SETTING_PPP_MRU)
+DEFINE_GETTER (nmc_property_ppp_get_mtu, NM_SETTING_PPP_MTU)
+DEFINE_GETTER (nmc_property_ppp_get_lcp_echo_failure, NM_SETTING_PPP_LCP_ECHO_FAILURE)
+DEFINE_GETTER (nmc_property_ppp_get_lcp_echo_interval, NM_SETTING_PPP_LCP_ECHO_INTERVAL)
+
+/* --- NM_SETTING_PPPOE_SETTING_NAME property get functions --- */
+DEFINE_GETTER (nmc_property_pppoe_get_service, NM_SETTING_PPPOE_SERVICE)
+DEFINE_GETTER (nmc_property_pppoe_get_username, NM_SETTING_PPPOE_USERNAME)
+DEFINE_GETTER (nmc_property_pppoe_get_password, NM_SETTING_PPPOE_PASSWORD)
+DEFINE_SECRET_FLAGS_GETTER (nmc_property_pppoe_get_password_flags, NM_SETTING_PPPOE_PASSWORD_FLAGS)
+
+/* --- NM_SETTING_SERIAL_SETTING_NAME property get functions --- */
+DEFINE_GETTER (nmc_property_serial_get_baud, NM_SETTING_SERIAL_BAUD)
+DEFINE_GETTER (nmc_property_serial_get_bits, NM_SETTING_SERIAL_BITS)
+DEFINE_GETTER (nmc_property_serial_get_parity, NM_SETTING_SERIAL_PARITY)
+DEFINE_GETTER (nmc_property_serial_get_stopbits, NM_SETTING_SERIAL_STOPBITS)
+DEFINE_GETTER (nmc_property_serial_get_send_delay, NM_SETTING_SERIAL_SEND_DELAY)
+
+/* --- NM_SETTING_VLAN_SETTING_NAME property get functions --- */
+DEFINE_GETTER (nmc_property_vlan_get_interface_name, NM_SETTING_VLAN_INTERFACE_NAME)
+DEFINE_GETTER (nmc_property_vlan_get_parent, NM_SETTING_VLAN_PARENT)
+DEFINE_GETTER (nmc_property_vlan_get_id, NM_SETTING_VLAN_ID)
+
+
+static char *
+nmc_property_vlan_get_flags (NMSetting *setting)
+{
+	NMSettingVlan *s_vlan = NM_SETTING_VLAN (setting);
+	return vlan_flags_to_string (nm_setting_vlan_get_flags (s_vlan));
+}
+
+static char *
+nmc_property_vlan_get_ingress_priority_map (NMSetting *setting)
+{
+	NMSettingVlan *s_vlan = NM_SETTING_VLAN (setting);
+	return vlan_priorities_to_string (s_vlan, NM_VLAN_INGRESS_MAP);
+}
+
+static char *
+nmc_property_vlan_get_egress_priority_map (NMSetting *setting)
+{
+	NMSettingVlan *s_vlan = NM_SETTING_VLAN (setting);
+	return vlan_priorities_to_string (s_vlan, NM_VLAN_EGRESS_MAP);
+}
+
+/* --- NM_SETTING_VPN_SETTING_NAME property get functions --- */
+DEFINE_GETTER (nmc_property_vpn_get_service_type, NM_SETTING_VPN_SERVICE_TYPE)
+DEFINE_GETTER (nmc_property_vpn_get_user_name, NM_SETTING_VPN_USER_NAME)
+
+static char *
+nmc_property_vpn_get_data (NMSetting *setting)
+{
+	NMSettingVPN *s_vpn = NM_SETTING_VPN (setting);
+	GString *data_item_str;
+
+	data_item_str = g_string_new (NULL);
+	nm_setting_vpn_foreach_data_item (s_vpn, &vpn_data_item, data_item_str);
+
+	return g_string_free (data_item_str, FALSE);
+}
+
+static char *
+nmc_property_vpn_get_secrets (NMSetting *setting)
+{
+	NMSettingVPN *s_vpn = NM_SETTING_VPN (setting);
+	GString *secret_str;
+
+	secret_str = g_string_new (NULL);
+	nm_setting_vpn_foreach_secret (s_vpn, &vpn_data_item, secret_str);
+
+	return g_string_free (secret_str, FALSE);
+}
+
+/* --- NM_SETTING_WIMAX_SETTING_NAME property get functions --- */
+DEFINE_GETTER (nmc_property_wimax_get_network_name, NM_SETTING_WIMAX_NETWORK_NAME)
+DEFINE_HWADDR_GETTER (nmc_property_wimax_get_mac_address, NM_SETTING_WIMAX_MAC_ADDRESS)
+
+/* --- NM_SETTING_WIRED_SETTING_NAME property get functions --- */
+DEFINE_GETTER (nmc_property_wired_get_port, NM_SETTING_WIRED_PORT)
+DEFINE_GETTER (nmc_property_wired_get_speed, NM_SETTING_WIRED_SPEED)
+DEFINE_GETTER (nmc_property_wired_get_duplex, NM_SETTING_WIRED_DUPLEX)
+DEFINE_GETTER (nmc_property_wired_get_auto_negotiate, NM_SETTING_WIRED_AUTO_NEGOTIATE)
+DEFINE_HWADDR_GETTER (nmc_property_wired_get_mac_address, NM_SETTING_WIRED_MAC_ADDRESS)
+DEFINE_HWADDR_GETTER (nmc_property_wired_get_cloned_mac_address, NM_SETTING_WIRED_CLONED_MAC_ADDRESS)
+DEFINE_GETTER (nmc_property_wired_get_mac_address_blacklist, NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST)
+DEFINE_GETTER (nmc_property_wired_get_s390_subchannels, NM_SETTING_WIRED_S390_SUBCHANNELS)
+DEFINE_GETTER (nmc_property_wired_get_s390_nettype, NM_SETTING_WIRED_S390_NETTYPE)
+DEFINE_GETTER (nmc_property_wired_get_s390_options, NM_SETTING_WIRED_S390_OPTIONS)
+
+static char *
+nmc_property_wired_get_mtu (NMSetting *setting)
+{
+	NMSettingWired *s_wired = NM_SETTING_WIRED (setting);
+	int mtu;
+
+	mtu = nm_setting_wired_get_mtu (s_wired);
+	if (mtu == 0)
+		return g_strdup (_("auto"));
+	else
+		return g_strdup_printf ("%d", mtu);
+}
+
+/* --- NM_SETTING_WIRELESS_SETTING_NAME property get functions --- */
+DEFINE_GETTER (nmc_property_wireless_get_mode, NM_SETTING_WIRELESS_MODE)
+DEFINE_GETTER (nmc_property_wireless_get_band, NM_SETTING_WIRELESS_BAND)
+DEFINE_GETTER (nmc_property_wireless_get_channel, NM_SETTING_WIRELESS_CHANNEL)
+DEFINE_HWADDR_GETTER (nmc_property_wireless_get_bssid, NM_SETTING_WIRELESS_BSSID)
+DEFINE_GETTER (nmc_property_wireless_get_rate, NM_SETTING_WIRELESS_RATE)
+DEFINE_GETTER (nmc_property_wireless_get_tx_power, NM_SETTING_WIRELESS_TX_POWER)
+DEFINE_HWADDR_GETTER (nmc_property_wireless_get_mac_address, NM_SETTING_WIRELESS_MAC_ADDRESS)
+DEFINE_HWADDR_GETTER (nmc_property_wireless_get_cloned_mac_address, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS)
+DEFINE_GETTER (nmc_property_wireless_get_mac_address_blacklist, NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST)
+DEFINE_GETTER (nmc_property_wireless_get_seen_bssids, NM_SETTING_WIRELESS_SEEN_BSSIDS)
+DEFINE_GETTER (nmc_property_wireless_get_hidden, NM_SETTING_WIRELESS_HIDDEN)
+
+static char *
+nmc_property_wireless_get_ssid (NMSetting *setting)
+{
+	NMSettingWireless *s_wireless = NM_SETTING_WIRELESS (setting);
+	const GByteArray *ssid;
+	char *ssid_str = NULL;
 
 	ssid = nm_setting_wireless_get_ssid (s_wireless);
 	if (ssid)
-		ssid_str = ssid_to_printable ((const char *) ssid->data, ssid->len);
-	channel_str = g_strdup_printf ("%d", nm_setting_wireless_get_channel (s_wireless));
-	rate_str = g_strdup_printf ("%d", nm_setting_wireless_get_rate (s_wireless));
-	bssid = nm_setting_wireless_get_bssid (s_wireless);
-	if (bssid)
-		bssid_str = nm_utils_hwaddr_ntoa (bssid->data, ARPHRD_ETHER);
-	tx_power_str = g_strdup_printf ("%d", nm_setting_wireless_get_tx_power (s_wireless));
-	mtu_str = g_strdup_printf ("%d", nm_setting_wireless_get_mtu (s_wireless));
-	mac = nm_setting_wireless_get_mac_address (s_wireless);
-	if (mac)
-		device_mac_str = nm_utils_hwaddr_ntoa (mac->data, ARPHRD_ETHER);
-	mac = nm_setting_wireless_get_cloned_mac_address (s_wireless);
-	if (mac)
-		cloned_mac_str = nm_utils_hwaddr_ntoa (mac->data, ARPHRD_ETHER);
-
-	mac_blacklist = g_string_new (NULL);
-	iter = nm_setting_wireless_get_mac_address_blacklist (s_wireless);
-	while (iter) {
-		g_string_append_printf (mac_blacklist, "%s,", (char *) iter->data);
-		iter = iter->next;
-	}
-	g_string_truncate (mac_blacklist, mac_blacklist->len-1);  /* chop off trailing ',' */
-
-	seen_bssids = g_string_new (NULL);
-	for (i = 0; i < nm_setting_wireless_get_num_seen_bssids (s_wireless); i++) {
-		if (i > 0)
-			g_string_append_c (seen_bssids, ',');
-		g_string_append (seen_bssids, nm_setting_wireless_get_seen_bssid (s_wireless, i));
-	}
-
-	nmc->allowed_fields[0].value = NM_SETTING_WIRELESS_SETTING_NAME;
-	nmc->allowed_fields[1].value = ssid_str;
-	nmc->allowed_fields[2].value = nm_setting_wireless_get_mode (s_wireless);
-	nmc->allowed_fields[3].value = nm_setting_wireless_get_band (s_wireless);
-	nmc->allowed_fields[4].value = channel_str;
-	nmc->allowed_fields[5].value = bssid_str;
-	nmc->allowed_fields[6].value = rate_str;
-	nmc->allowed_fields[7].value = tx_power_str;
-	nmc->allowed_fields[8].value = device_mac_str;
-	nmc->allowed_fields[9].value = cloned_mac_str;
-	nmc->allowed_fields[10].value = mac_blacklist->str;
-	nmc->allowed_fields[11].value = strcmp (mtu_str, "0") ?  mtu_str : _("auto");
-	nmc->allowed_fields[12].value = seen_bssids->str;
-	nmc->allowed_fields[13].value = nm_setting_wireless_get_security (s_wireless);
-	nmc->allowed_fields[14].value = nm_setting_wireless_get_hidden (s_wireless) ? _("yes") : _("no");
-
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
-
-	g_free (ssid_str);
-	g_free (channel_str);
-	g_free (bssid_str);
-	g_free (rate_str);
-	g_free (tx_power_str);
-	g_free (device_mac_str);
-	g_free (cloned_mac_str);
-	g_free (mtu_str);
-	g_string_free (seen_bssids, TRUE);
-	g_string_free (mac_blacklist, TRUE);
+		ssid_str = nm_utils_ssid_to_utf8 (ssid);
+
+	return ssid_str;
+}
+
+static char *
+nmc_property_wireless_get_mtu (NMSetting *setting)
+{
+	NMSettingWireless *s_wireless = NM_SETTING_WIRELESS (setting);
+	int mtu;
+
+	mtu = nm_setting_wireless_get_mtu (s_wireless);
+	if (mtu == 0)
+		return g_strdup (_("auto"));
+	else
+		return g_strdup_printf ("%d", mtu);
+}
+
+/* --- NM_SETTING_WIRELESS_SECURITY_SETTING_NAME property get functions --- */
+DEFINE_GETTER (nmc_property_wifi_sec_get_key_mgmt, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT)
+DEFINE_GETTER (nmc_property_wifi_sec_get_wep_tx_keyidx, NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX)
+DEFINE_GETTER (nmc_property_wifi_sec_get_auth_alg, NM_SETTING_WIRELESS_SECURITY_AUTH_ALG)
+DEFINE_GETTER (nmc_property_wifi_sec_get_proto, NM_SETTING_WIRELESS_SECURITY_PROTO)
+DEFINE_GETTER (nmc_property_wifi_sec_get_pairwise, NM_SETTING_WIRELESS_SECURITY_PAIRWISE)
+DEFINE_GETTER (nmc_property_wifi_sec_get_group, NM_SETTING_WIRELESS_SECURITY_GROUP)
+DEFINE_GETTER (nmc_property_wifi_sec_get_leap_username, NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME)
+DEFINE_SECRET_FLAGS_GETTER (nmc_property_wifi_sec_get_wep_key_flags, NM_SETTING_WIRELESS_SECURITY_WEP_KEY_FLAGS)
+DEFINE_GETTER (nmc_property_wifi_sec_get_psk, NM_SETTING_WIRELESS_SECURITY_PSK)
+DEFINE_SECRET_FLAGS_GETTER (nmc_property_wifi_sec_get_psk_flags, NM_SETTING_WIRELESS_SECURITY_PSK_FLAGS)
+DEFINE_GETTER (nmc_property_wifi_sec_get_leap_password, NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD)
+DEFINE_SECRET_FLAGS_GETTER (nmc_property_wifi_sec_get_leap_password_flags, NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD_FLAGS)
+
+static char *
+nmc_property_wifi_sec_get_wep_key0 (NMSetting *setting)
+{
+	NMSettingWirelessSecurity *s_wireless_sec = NM_SETTING_WIRELESS_SECURITY (setting);
+	return g_strdup (nm_setting_wireless_security_get_wep_key (s_wireless_sec, 0));
+}
+
+static char *
+nmc_property_wifi_sec_get_wep_key1 (NMSetting *setting)
+{
+	NMSettingWirelessSecurity *s_wireless_sec = NM_SETTING_WIRELESS_SECURITY (setting);
+	return g_strdup (nm_setting_wireless_security_get_wep_key (s_wireless_sec, 1));
+}
+
+static char *
+nmc_property_wifi_sec_get_wep_key2 (NMSetting *setting)
+{
+	NMSettingWirelessSecurity *s_wireless_sec = NM_SETTING_WIRELESS_SECURITY (setting);
+	return g_strdup (nm_setting_wireless_security_get_wep_key (s_wireless_sec, 2));
+}
+
+static char *
+nmc_property_wifi_sec_get_wep_key3 (NMSetting *setting)
+{
+	NMSettingWirelessSecurity *s_wireless_sec = NM_SETTING_WIRELESS_SECURITY (setting);
+	return g_strdup (nm_setting_wireless_security_get_wep_key (s_wireless_sec, 3));
+}
+
+static char *
+nmc_property_wifi_sec_get_wep_key_type (NMSetting *setting)
+{
+	NMSettingWirelessSecurity *s_wireless_sec = NM_SETTING_WIRELESS_SECURITY (setting);
+	return wep_key_type_to_string (nm_setting_wireless_security_get_wep_key_type (s_wireless_sec));
+}
+
+/*----------------------------------------------------------------------------*/
+
+static void
+nmc_value_transform_bool_string (const GValue *src_value,
+                                 GValue       *dest_value)
+{
+	dest_value->data[0].v_pointer = g_strdup (src_value->data[0].v_int ? "yes" : "no");
+}
+
+static void
+nmc_value_transform_char_string (const GValue *src_value,
+                                 GValue       *dest_value)
+{
+	dest_value->data[0].v_pointer = g_strdup_printf ("%c", src_value->data[0].v_uint);
+}
+
+static void __attribute__((constructor))
+register_nmcli_value_transforms (void)
+{
+	g_value_register_transform_func (G_TYPE_BOOLEAN, G_TYPE_STRING, nmc_value_transform_bool_string);
+	g_value_register_transform_func (G_TYPE_CHAR, G_TYPE_STRING, nmc_value_transform_char_string);
+}
+
+/*----------------------------------------------------------------------------*/
+
+/* Main hash table storing function pointer for manipulating properties */
+static GHashTable *nmc_properties = NULL;
+typedef	char *       (*NmcPropertyGetFunc)      (NMSetting *);
+typedef	gboolean     (*NmcPropertySetFunc)      (NMSetting *, const char *, const char *, GError **);
+typedef	gboolean     (*NmcPropertyRemoveFunc)   (NMSetting *, const char *, const char *, guint32, GError **);
+typedef	const char * (*NmcPropertyDescribeFunc) (NMSetting *, const char *);
+typedef	const char * (*NmcPropertyValuesFunc)   (NMSetting *, const char *);
+typedef	      char * (*NmcPropertyOut2InFunc)   (const char *);
+
+typedef struct {
+	NmcPropertyGetFunc get_func;           /* func getting property values */
+	NmcPropertySetFunc set_func;           /* func adding/setting property values */
+	NmcPropertyRemoveFunc remove_func;     /* func removing items from container options */
+	NmcPropertyDescribeFunc describe_func; /* func returning property description */
+	NmcPropertyValuesFunc values_func;     /* func returning allowed property values */
+	NmcPropertyOut2InFunc out2in_func;     /* func converting property values from output to input format */
+} NmcPropertyFuncs;
+
+/*
+ * We need NmCli in some _set_property functions, and they aren't passed NmCli.
+ * So use the global variable.
+ */
+/* Global variable defined in nmcli.c */
+extern NmCli nm_cli;
+
+NMSetting *
+nmc_setting_new_for_name (const char *name)
+{
+	GType stype;
+	NMSetting *setting = NULL;
+
+	if (name) {
+		stype = nm_connection_lookup_setting_type (name);
+		if (stype != G_TYPE_INVALID) {
+			setting = g_object_new (stype, NULL);
+			g_warn_if_fail (NM_IS_SETTING (setting));
+		}
+	}
+	return setting;
+}
+
+static gboolean
+get_answer (const char *prop, const char *value)
+{
+	char *tmp_str;
+	char *question;
+	gboolean answer = FALSE;
+
+	if (value)
+		question = g_strdup_printf (_("Do you also want to set '%s' to '%s'? [yes]: "), prop, value);
+	else
+		question = g_strdup_printf (_("Do you also want to clear '%s'? [yes]: "), prop);
+	tmp_str = nmc_get_user_input (question);
+	if (!tmp_str || matches (tmp_str, "yes") == 0)
+		answer = TRUE;
+	g_free (tmp_str);
+	g_free (question);
+	return answer;
+}
+
+static void ipv4_method_changed_cb (GObject *object, GParamSpec *pspec, gpointer user_data);
+static void ipv6_method_changed_cb (GObject *object, GParamSpec *pspec, gpointer user_data);
+
+static void
+ipv4_addresses_changed_cb (GObject *object, GParamSpec *pspec, gpointer user_data)
+{
+	static gboolean answered = FALSE;
+	static gboolean answer = FALSE;
+
+	g_signal_handlers_block_by_func (object, G_CALLBACK (ipv4_method_changed_cb), NULL);
+
+	/* If we have some IP addresses set method to 'manual'.
+	 * Else if the method was 'manual', change it back to 'auto'.
+	 */
+	if (nm_setting_ip4_config_get_num_addresses (NM_SETTING_IP4_CONFIG (object))) {
+		if (g_strcmp0 (nm_setting_ip4_config_get_method (NM_SETTING_IP4_CONFIG (object)), NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) {
+			if (!answered) {
+				answered = TRUE;
+				answer = get_answer ("ipv4.method", "manual");
+			}
+			if (answer)
+				g_object_set (object, NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL, NULL);
+		}
+	} else {
+		answered = FALSE;
+		if (!g_strcmp0 (nm_setting_ip4_config_get_method (NM_SETTING_IP4_CONFIG (object)), NM_SETTING_IP4_CONFIG_METHOD_MANUAL))
+			g_object_set (object, NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);
+	}
+
+	g_signal_handlers_unblock_by_func (object, G_CALLBACK (ipv4_method_changed_cb), NULL);
+}
+
+static void
+ipv4_method_changed_cb (GObject *object, GParamSpec *pspec, gpointer user_data)
+{
+	static GValue value = G_VALUE_INIT;
+	static gboolean answered = FALSE;
+	static gboolean answer = FALSE;
+
+	g_signal_handlers_block_by_func (object, G_CALLBACK (ipv4_addresses_changed_cb), NULL);
+
+	/* If method != manual, remove addresses (save them for restoring them later when method becomes 'manual' */
+	if (g_strcmp0 (nm_setting_ip4_config_get_method (NM_SETTING_IP4_CONFIG (object)), NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) {
+		if (nm_setting_ip4_config_get_num_addresses (NM_SETTING_IP4_CONFIG (object))) {
+			if (!answered) {
+				answered = TRUE;
+				answer = get_answer ("ipv4.addresses", NULL);
+			}
+			if (answer) {
+				if (G_IS_VALUE (&value))
+					g_value_unset (&value);
+				nmc_property_get_gvalue (NM_SETTING (object), NM_SETTING_IP4_CONFIG_ADDRESSES, &value);
+				g_object_set (object, NM_SETTING_IP4_CONFIG_ADDRESSES, NULL, NULL);
+			}
+		}
+	} else {
+		answered = FALSE;
+		if (G_IS_VALUE (&value)) {
+			nmc_property_set_gvalue (NM_SETTING (object), NM_SETTING_IP4_CONFIG_ADDRESSES, &value);
+			g_value_unset (&value);
+		}
+	}
+
+	g_signal_handlers_unblock_by_func (object, G_CALLBACK (ipv4_addresses_changed_cb), NULL);
+}
+
+static void
+ipv6_addresses_changed_cb (GObject *object, GParamSpec *pspec, gpointer user_data)
+{
+	static gboolean answered = FALSE;
+	static gboolean answer = FALSE;
+
+	g_signal_handlers_block_by_func (object, G_CALLBACK (ipv6_method_changed_cb), NULL);
+
+	/* If we have some IP addresses set method to 'manual'.
+	 * Else if the method was 'manual', change it back to 'auto'.
+	 */
+	if (nm_setting_ip6_config_get_num_addresses (NM_SETTING_IP6_CONFIG (object))) {
+		if (g_strcmp0 (nm_setting_ip6_config_get_method (NM_SETTING_IP6_CONFIG (object)), NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) {
+			if (!answered) {
+				answered = TRUE;
+				answer = get_answer ("ipv6.method", "manual");
+			}
+			if (answer)
+				g_object_set (object, NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_MANUAL, NULL);
+		}
+	} else {
+		answered = FALSE;
+		if (!g_strcmp0 (nm_setting_ip6_config_get_method (NM_SETTING_IP6_CONFIG (object)), NM_SETTING_IP6_CONFIG_METHOD_MANUAL))
+			g_object_set (object, NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO, NULL);
+	}
+
+	g_signal_handlers_unblock_by_func (object, G_CALLBACK (ipv6_method_changed_cb), NULL);
+}
+
+static void
+ipv6_method_changed_cb (GObject *object, GParamSpec *pspec, gpointer user_data)
+{
+	static GValue value = G_VALUE_INIT;
+	static gboolean answered = FALSE;
+	static gboolean answer = FALSE;
+
+	g_signal_handlers_block_by_func (object, G_CALLBACK (ipv6_addresses_changed_cb), NULL);
+
+	/* If method != manual, remove addresses (save them for restoring them later when method becomes 'manual' */
+	if (g_strcmp0 (nm_setting_ip6_config_get_method (NM_SETTING_IP6_CONFIG (object)), NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) {
+		if (nm_setting_ip6_config_get_num_addresses (NM_SETTING_IP6_CONFIG (object))) {
+			if (!answered) {
+				answered = TRUE;
+				answer = get_answer ("ipv6.addresses", NULL);
+			}
+			if (answer) {
+				if (G_IS_VALUE (&value))
+					g_value_unset (&value);
+				nmc_property_get_gvalue (NM_SETTING (object), NM_SETTING_IP6_CONFIG_ADDRESSES, &value);
+				g_object_set (object, NM_SETTING_IP6_CONFIG_ADDRESSES, NULL, NULL);
+			}
+		}
+	} else {
+		answered = FALSE;
+		if (G_IS_VALUE (&value)) {
+			nmc_property_set_gvalue (NM_SETTING (object), NM_SETTING_IP6_CONFIG_ADDRESSES, &value);
+			g_value_unset (&value);
+		}
+	}
 
+	g_signal_handlers_unblock_by_func (object, G_CALLBACK (ipv6_addresses_changed_cb), NULL);
+}
+
+static void
+wireless_band_channel_changed_cb (GObject *object, GParamSpec *pspec, gpointer user_data)
+{
+	const char *value = NULL, *mode;
+	char str[16];
+	NMSettingWireless *s_wireless = NM_SETTING_WIRELESS (object);
+
+	if (strcmp (g_param_spec_get_name (pspec), NM_SETTING_WIRELESS_BAND) == 0) {
+		value = nm_setting_wireless_get_band (s_wireless);
+		if (!value)
+			return;
+	} else {
+		guint32 channel = nm_setting_wireless_get_channel (s_wireless);
+
+		if (channel == 0)
+			return;
+
+		g_snprintf (str, sizeof (str), "%d", nm_setting_wireless_get_channel (s_wireless));
+		value = str;
+	}
+
+	mode = nm_setting_wireless_get_mode (NM_SETTING_WIRELESS (object));
+	if (!mode || !*mode || strcmp (mode, NM_SETTING_WIRELESS_MODE_INFRA) == 0) {
+		printf (_("Warning: %s.%s set to '%s', but it might be ignored in infrastructure mode\n"),
+		        nm_setting_get_name (NM_SETTING (s_wireless)), g_param_spec_get_name (pspec),
+		        value);
+	}
+}
+
+void
+nmc_setting_ip4_connect_handlers (NMSettingIP4Config *setting)
+{
+	g_return_if_fail (NM_IS_SETTING_IP4_CONFIG (setting));
+
+	g_signal_connect (setting, "notify::" NM_SETTING_IP4_CONFIG_ADDRESSES,
+	                  G_CALLBACK (ipv4_addresses_changed_cb), NULL);
+	g_signal_connect (setting, "notify::" NM_SETTING_IP4_CONFIG_METHOD,
+	                  G_CALLBACK (ipv4_method_changed_cb), NULL);
+}
+
+void
+nmc_setting_ip6_connect_handlers (NMSettingIP6Config *setting)
+{
+	g_return_if_fail (NM_IS_SETTING_IP6_CONFIG (setting));
+
+	g_signal_connect (setting, "notify::" NM_SETTING_IP6_CONFIG_ADDRESSES,
+	                  G_CALLBACK (ipv6_addresses_changed_cb), NULL);
+	g_signal_connect (setting, "notify::" NM_SETTING_IP6_CONFIG_METHOD,
+	                  G_CALLBACK (ipv6_method_changed_cb), NULL);
+}
+
+void
+nmc_setting_wireless_connect_handlers (NMSettingWireless *setting)
+{
+	g_return_if_fail (NM_IS_SETTING_WIRELESS (setting));
+
+	g_signal_connect (setting, "notify::" NM_SETTING_WIRELESS_BAND,
+	                  G_CALLBACK (wireless_band_channel_changed_cb), NULL);
+	g_signal_connect (setting, "notify::" NM_SETTING_WIRELESS_CHANNEL,
+	                  G_CALLBACK (wireless_band_channel_changed_cb), NULL);
+}
+
+/*
+ * Customize some properties of the setting so that the setting has sensible
+ * values.
+ */
+void
+nmc_setting_custom_init (NMSetting *setting)
+{
+	g_return_if_fail (NM_IS_SETTING (setting));
+
+	if (NM_IS_SETTING_IP4_CONFIG (setting)) {
+		g_object_set (NM_SETTING_IP4_CONFIG (setting),
+		              NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO,
+		              NULL);
+		nmc_setting_ip4_connect_handlers (NM_SETTING_IP4_CONFIG (setting));
+	} else if (NM_IS_SETTING_IP6_CONFIG (setting)) {
+		g_object_set (NM_SETTING_IP6_CONFIG (setting),
+		              NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO,
+		              NULL);
+		nmc_setting_ip6_connect_handlers (NM_SETTING_IP6_CONFIG (setting));
+	} else if (NM_IS_SETTING_WIRELESS (setting)) {
+		g_object_set (NM_SETTING_WIRELESS (setting),
+		              NM_SETTING_WIRELESS_MODE, NM_SETTING_WIRELESS_MODE_INFRA,
+		              NULL);
+		nmc_setting_wireless_connect_handlers (NM_SETTING_WIRELESS (setting));
+	}
+}
+
+/* === SetFunc, RemoveFunc, DescribeFunc, ValuesFunc functions === */
+static gboolean
+verify_string_list (char **strv,
+                    const char *prop,
+                    gboolean (*validate_func) (const char *),
+                    GError **error)
+{
+	char **iter;
+
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	for (iter = strv; iter && *iter; iter++) {
+		if (**iter == '\0')
+			continue;
+		if (validate_func) {
+			if (!validate_func (*iter)) {
+				g_set_error (error, 1, 0, _("'%s' is not valid"),
+				             *iter);
+				return FALSE;
+			}
+		}
+	}
 	return TRUE;
 }
 
-gboolean
-setting_wireless_security_details (NMSettingWirelessSecurity *s_wireless_sec, NmCli *nmc)
+/* Validate 'val' number against to int property spec */
+static gboolean
+validate_int (NMSetting *setting, const char* prop, gint val, GError **error)
 {
-	int i;
-	char *wep_tx_keyidx_str, *wep_key_type_str, *wep_flags, *psk_flags, *leap_flags;
-	GString *protos, *pairwises, *groups;
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+	GParamSpec *pspec;
+	GValue value = G_VALUE_INIT;
+	gboolean success = TRUE;
+
+	g_value_init (&value, G_TYPE_INT);
+	g_value_set_int (&value, val);
+	pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (G_OBJECT (setting)), prop);
+	g_assert (G_IS_PARAM_SPEC (pspec));
+	if (g_param_value_validate (pspec, &value)) {
+		GParamSpecInt *pspec_int = (GParamSpecInt *) pspec;
+		g_set_error (error, 1, 0, _("'%d' is not valid; use <%d-%d>"),
+		             val, pspec_int->minimum, pspec_int->maximum);
+		success = FALSE;
+	}
+	g_value_unset (&value);
+	return success;
+}
 
-	g_return_val_if_fail (NM_IS_SETTING_WIRELESS_SECURITY (s_wireless_sec), FALSE);
+/* Validate 'val' number against to uint property spec */
+static gboolean
+validate_uint (NMSetting *setting, const char* prop, guint val, GError **error)
+{
+	GParamSpec *pspec;
+	GValue value = G_VALUE_INIT;
+	gboolean success = TRUE;
+
+	g_value_init (&value, G_TYPE_UINT);
+	g_value_set_uint (&value, val);
+	pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (G_OBJECT (setting)), prop);
+	g_assert (G_IS_PARAM_SPEC (pspec));
+	if (g_param_value_validate (pspec, &value)) {
+		GParamSpecUInt *pspec_uint = (GParamSpecUInt *) pspec;
+		g_set_error (error, 1, 0, _("'%u' is not valid; use <%d-%d>"),
+		             val, pspec_uint->minimum, pspec_uint->maximum);
+		success = FALSE;
+	}
+	g_value_unset (&value);
+	return success;
+}
+
+static gboolean
+check_and_set_string (NMSetting *setting,
+                      const char *prop,
+                      const char *val,
+                      const char **valid_strv,
+                      GError **error)
+{
+	const char *checked_val;
+
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-	nmc->allowed_fields = nmc_fields_setting_wireless_security;
-	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_WIRELESS_SECURITY_ALL, nmc->allowed_fields, NULL);
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-	print_fields (nmc->print_fields, nmc->allowed_fields);  /* Print field names */
-
-	wep_tx_keyidx_str = g_strdup_printf ("%d", nm_setting_wireless_security_get_wep_tx_keyidx (s_wireless_sec));
-	protos = g_string_new (NULL);
-	for (i = 0; i < nm_setting_wireless_security_get_num_protos (s_wireless_sec); i++) {
-		if (i > 0)
-		g_string_append_c (protos, ',');
-		g_string_append (protos, nm_setting_wireless_security_get_proto (s_wireless_sec, i));
-	}
-	pairwises = g_string_new (NULL);
-	for (i = 0; i < nm_setting_wireless_security_get_num_pairwise (s_wireless_sec); i++) {
-		if (i > 0)
-		g_string_append_c (pairwises, ',');
-		g_string_append (pairwises, nm_setting_wireless_security_get_pairwise (s_wireless_sec, i));
-	}
-	groups = g_string_new (NULL);
-	for (i = 0; i < nm_setting_wireless_security_get_num_groups (s_wireless_sec); i++) {
-		if (i > 0)
-		g_string_append_c (groups, ',');
-		g_string_append (groups, nm_setting_wireless_security_get_group (s_wireless_sec, i));
-	}
-	wep_key_type_str = wep_key_type_to_string (nm_setting_wireless_security_get_wep_key_type (s_wireless_sec));
-
-	wep_flags = secret_flags_to_string (nm_setting_wireless_security_get_wep_key_flags (s_wireless_sec));
-	psk_flags = secret_flags_to_string (nm_setting_wireless_security_get_psk_flags (s_wireless_sec));
-	leap_flags = secret_flags_to_string (nm_setting_wireless_security_get_leap_password_flags (s_wireless_sec));
-
-	nmc->allowed_fields[0].value = NM_SETTING_WIRELESS_SECURITY_SETTING_NAME;
-	nmc->allowed_fields[1].value = nm_setting_wireless_security_get_key_mgmt (s_wireless_sec);
-	nmc->allowed_fields[2].value = wep_tx_keyidx_str;
-	nmc->allowed_fields[3].value = nm_setting_wireless_security_get_auth_alg (s_wireless_sec);
-	nmc->allowed_fields[4].value = protos->str;
-	nmc->allowed_fields[5].value = pairwises->str;
-	nmc->allowed_fields[6].value = groups->str;
-	nmc->allowed_fields[7].value = nm_setting_wireless_security_get_leap_username (s_wireless_sec);
-	nmc->allowed_fields[8].value = nm_setting_wireless_security_get_wep_key (s_wireless_sec, 0);
-	nmc->allowed_fields[9].value = nm_setting_wireless_security_get_wep_key (s_wireless_sec, 1);
-	nmc->allowed_fields[10].value = nm_setting_wireless_security_get_wep_key (s_wireless_sec, 2);
-	nmc->allowed_fields[11].value = nm_setting_wireless_security_get_wep_key (s_wireless_sec, 3);
-	nmc->allowed_fields[12].value = wep_flags;
-	nmc->allowed_fields[13].value = wep_key_type_str;
-	nmc->allowed_fields[14].value = nm_setting_wireless_security_get_psk (s_wireless_sec);
-	nmc->allowed_fields[15].value = psk_flags;
-	nmc->allowed_fields[16].value = nm_setting_wireless_security_get_leap_password (s_wireless_sec);
-	nmc->allowed_fields[17].value = leap_flags;
-
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
-
-	g_free (wep_tx_keyidx_str);
-	g_free (wep_key_type_str);
-	g_free (wep_flags);
-	g_free (psk_flags);
-	g_free (leap_flags);
-	g_string_free (protos, TRUE);
-	g_string_free (pairwises, TRUE);
-	g_string_free (groups, TRUE);
+	checked_val = nmc_string_is_valid (val, valid_strv, error);
+	if (!checked_val)
+		return FALSE;
 
+	g_object_set (setting, prop, checked_val, NULL);
 	return TRUE;
 }
 
-gboolean
-setting_ip4_config_details (NMSettingIP4Config *s_ip4, NmCli *nmc)
+#define DEFINE_SETTER_STR_LIST_MULTI(def_func, s_macro, set_func) \
+	static gboolean \
+	def_func (NMSetting *setting, \
+	          const char *prop, \
+	          const char *val, \
+	          const char **valid_strv, \
+	          GError **error) \
+	{ \
+		char **strv = NULL, **iter; \
+		const char *item; \
+		g_return_val_if_fail (error == NULL || *error == NULL, FALSE); \
+		strv = nmc_strsplit_set (val, " \t,", 0); \
+		for (iter = strv; iter && *iter; iter++) { \
+			if (!(item = nmc_string_is_valid (g_strstrip (*iter), valid_strv, error))) { \
+				g_strfreev (strv); \
+				return FALSE; \
+			} \
+			set_func (s_macro (setting), item); \
+		} \
+		g_strfreev (strv); \
+		return TRUE; \
+	}
+
+#define DEFINE_SETTER_OPTIONS(def_func, s_macro, s_type, add_func, valid_func1, valid_func2) \
+	static gboolean \
+	def_func (NMSetting *setting, const char *prop, const char *val, GError **error) \
+	{ \
+		char **strv = NULL, **iter; \
+		const char **(*valid_func1_p) (s_type *) = valid_func1; \
+		const char * (*valid_func2_p) (const char *, const char *, GError **) = valid_func2; \
+		const char *opt_name, *opt_val; \
+		\
+		g_return_val_if_fail (error == NULL || *error == NULL, FALSE); \
+		\
+		strv = nmc_strsplit_set (val, ",", 0); \
+		for (iter = strv; iter && *iter; iter++) { \
+			char *left = g_strstrip (*iter); \
+			char *right = strchr (left, '='); \
+			if (!right) { \
+				g_set_error (error, 1, 0, _("'%s' is not valid; use <option>=<value>"), *iter); \
+				g_strfreev (strv); \
+				return FALSE; \
+			} \
+			*right++ = '\0'; \
+			\
+			if (valid_func1_p) { \
+				const char **valid_options = valid_func1_p (s_macro (setting)); \
+				if (!(opt_name = nmc_string_is_valid (g_strstrip (left), valid_options, error))) { \
+					g_strfreev (strv); \
+					return FALSE; \
+				} \
+			} else \
+				opt_name = g_strstrip (left);\
+			\
+			opt_val = g_strstrip (right); \
+			if (valid_func2_p) { \
+				if (!(opt_val = valid_func2_p ((const char *) left, (const char *) opt_val, error))) { \
+					g_strfreev (strv); \
+					return FALSE; \
+				}\
+			}\
+			add_func (s_macro (setting), opt_name, opt_val); \
+		} \
+		g_strfreev (strv); \
+		return TRUE; \
+	}
+
+#define DEFINE_REMOVER_INDEX(def_func, s_macro, num_func, rem_func) \
+	static gboolean \
+	def_func (NMSetting *setting, const char *prop, const char *option, guint32 idx, GError **error) \
+	{ \
+		guint32 num; \
+		if (option) { \
+			g_set_error (error, 1, 0, _("index '%s' is not valid"), option); \
+			return FALSE; \
+		} \
+		num = num_func (s_macro (setting)); \
+		if (num == 0) { \
+			g_set_error_literal (error, 1, 0, _("no item to remove")); \
+			return FALSE; \
+		} \
+		if (idx >= num) { \
+			g_set_error (error, 1, 0, _("index '%d' is not in range <0-%d>"), idx, num - 1); \
+			return FALSE; \
+		} \
+		rem_func (s_macro (setting), idx); \
+		return TRUE; \
+	}
+
+#define DEFINE_REMOVER_INDEX_OR_VALUE(def_func, s_macro, num_func, rem_func_idx, rem_func_val) \
+	static gboolean \
+	def_func (NMSetting *setting, const char *prop, const char *value, guint32 idx, GError **error) \
+	{ \
+		guint32 num; \
+		if (value) { \
+			gboolean ret; \
+			char *value_stripped = g_strstrip (g_strdup (value)); \
+			ret = rem_func_val (s_macro (setting), value_stripped, error); \
+			g_free (value_stripped); \
+			return ret; \
+		} \
+		num = num_func (s_macro (setting)); \
+		if (num == 0) { \
+			g_set_error_literal (error, 1, 0, _("no item to remove")); \
+			return FALSE; \
+		} \
+		if (idx >= num) { \
+			g_set_error (error, 1, 0, _("index '%d' is not in range <0-%d>"), idx, num - 1); \
+			return FALSE; \
+		} \
+		rem_func_idx (s_macro (setting), idx); \
+		return TRUE; \
+	}
+
+#define DEFINE_REMOVER_OPTION(def_func, s_macro, rem_func) \
+	static gboolean \
+	def_func (NMSetting *setting, const char *prop, const char *option, guint32 idx, GError **error) \
+	{ \
+		gboolean success = FALSE; \
+		if (option && *option) { \
+			success = rem_func (s_macro (setting), option); \
+			if (!success) \
+				g_set_error (error, 1, 0, _("invalid option '%s'"), option); \
+		} else \
+			g_set_error_literal (error, 1, 0, _("missing option")); \
+		return success; \
+	}
+
+#define DEFINE_ALLOWED_VAL_FUNC(def_func, valid_values) \
+	static const char * \
+	def_func (NMSetting *setting, const char *prop) \
+	{ \
+		static char *values = NULL; \
+		if (G_UNLIKELY (values == NULL)) \
+			values = g_strjoinv (", ", (char **) valid_values); \
+		return values; \
+	}
+
+/* --- generic property setter functions --- */
+static gboolean
+nmc_property_set_string (NMSetting *setting, const char *prop, const char *val, GError **error)
 {
-	GString *dns_str, *dns_search_str, *addr_str, *route_str;
-	int i, num;
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+	g_object_set (setting, prop, val, NULL);
+	return TRUE;
+}
 
-	g_return_val_if_fail (NM_IS_SETTING_IP4_CONFIG (s_ip4), FALSE);
+static gboolean
+nmc_property_set_int (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	long val_int;
 
-	nmc->allowed_fields = nmc_fields_setting_ip4_config;
-	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_IP4_CONFIG_ALL, nmc->allowed_fields, NULL);
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-	print_fields (nmc->print_fields, nmc->allowed_fields);  /* Print field names */
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-	dns_str = g_string_new (NULL);
-	num = nm_setting_ip4_config_get_num_dns (s_ip4);
-	for (i = 0; i < num; i++) {
-		char buf[INET_ADDRSTRLEN];
-		guint32 ip;
-
-		ip = nm_setting_ip4_config_get_dns (s_ip4, i);
-		memset (buf, 0, sizeof (buf));
-		inet_ntop (AF_INET, (const void *) &ip, buf, sizeof (buf));
-		if (i > 0)
-			g_string_append (dns_str, ", ");
-		g_string_append (dns_str, buf);
+	if (!nmc_string_to_int (val, TRUE, G_MININT, G_MAXINT, &val_int)) {
+		g_set_error (error, 1, 0, _("'%s' is not a valid number (or out of range)"), val);
+		return FALSE;
 	}
 
-	dns_search_str = g_string_new (NULL);
-	num = nm_setting_ip4_config_get_num_dns_searches (s_ip4);
-	for (i = 0; i < num; i++) {
-		const char *domain;
-
-		domain = nm_setting_ip4_config_get_dns_search (s_ip4, i);
-		if (i > 0)
-			g_string_append (dns_search_str, ", ");
-		g_string_append (dns_search_str, domain);
+	/* Validate the number according to the property spec */
+	if (!validate_int (setting, prop, (gint) val_int, error))
+		return FALSE;
+
+	g_object_set (setting, prop, val_int, NULL);
+	return TRUE;
+}
+
+static gboolean
+nmc_property_set_uint (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	unsigned long val_int;
+
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	if (!nmc_string_to_uint (val, TRUE, 0, G_MAXUINT, &val_int)) {
+		g_set_error (error, 1, 0, _("'%s' is not a valid number (or out of range)"), val);
+		return FALSE;
+	}
+
+	/* Validate the number according to the property spec */
+	if (!validate_uint (setting, prop, (guint) val_int, error))
+		return FALSE;
+
+	g_object_set (setting, prop, val_int, NULL);
+	return TRUE;
+}
+
+static gboolean
+nmc_property_set_bool (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	gboolean val_bool;
+
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	if (!nmc_string_to_bool (val, &val_bool, error))
+		return FALSE;
+
+	g_object_set (setting, prop, val_bool, NULL);
+	return TRUE;
+}
+
+static gboolean
+nmc_property_set_ssid (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	GByteArray *ssid_arr;
+
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	if (strlen (val) > 32) {
+		g_set_error (error, 1, 0, _("'%s' is not valid"), val);
+		return FALSE;
 	}
 
-	addr_str = g_string_new (NULL);
-	num = nm_setting_ip4_config_get_num_addresses (s_ip4);
-	for (i = 0; i < num; i++) {
-		char buf[INET_ADDRSTRLEN];
-		char *tmp;
-		NMIP4Address *addr;
-		guint32 ip;
+	ssid_arr = g_byte_array_sized_new (strlen (val));
+	g_byte_array_append (ssid_arr, (const guint8 *) val, strlen (val));
+	g_object_set (setting, prop, ssid_arr, NULL);
+
+	return TRUE;
+}
+
+static gboolean
+nmc_property_set_mac (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	GByteArray *array;
 
-		if (i > 0)
-			g_string_append (addr_str, "; ");
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-		g_string_append (addr_str, "{ ");
+	array = nm_utils_hwaddr_atoba (val, ARPHRD_ETHER);
+	if (!array) {
+		g_set_error (error, 1, 0, _("'%s' is not a valid Ethernet MAC"), val);
+		return FALSE;
+	}
 
-		addr = nm_setting_ip4_config_get_address (s_ip4, i);
+	g_object_set (setting, prop, array, NULL);
+	g_byte_array_free (array, TRUE);
+	return TRUE;
+}
 
-		memset (buf, 0, sizeof (buf));
-		ip = nm_ip4_address_get_address (addr);
-		inet_ntop (AF_INET, (const void *) &ip, buf, sizeof (buf));
-		g_string_append_printf (addr_str, "ip = %s", buf);
+static gboolean
+nmc_property_set_mtu (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	const char *mtu = val;
 
-		tmp = g_strdup_printf ("/%u", nm_ip4_address_get_prefix (addr));
-		g_string_append (addr_str, tmp);
-		g_free (tmp);
+	if (strcmp (mtu, "auto") == 0)
+		mtu = "0";
 
-		memset (buf, 0, sizeof (buf));
-		ip = nm_ip4_address_get_gateway (addr);
-		inet_ntop (AF_INET, (const void *) &ip, buf, sizeof (buf));
-		g_string_append_printf (addr_str, ", gw = %s", buf);
+	return nmc_property_set_uint (setting, prop, mtu, error);
+}
 
-		g_string_append (addr_str, " }");
+static gboolean
+nmc_property_set_ifname (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	if (!nm_utils_iface_valid_name (val)) {
+		g_set_error (error, 1, 0, _("'%s' is not a valid interface name"), val);
+		return FALSE;
+	}
+	g_object_set (setting, prop, val, NULL);
+	return TRUE;
+}
+
+static gboolean
+nmc_property_set_flags (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	char **strv = NULL, **iter;
+	unsigned long flags = 0, val_int;
+
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	strv = nmc_strsplit_set (val, " \t,", 0);
+	for (iter = strv; iter && *iter; iter++) {
+		if (!nmc_string_to_uint (*iter, TRUE, 0, G_MAXUINT32, &val_int)) {
+			g_set_error (error, 1, 0, _("'%s' is not a number"), *iter);
+			g_strfreev (strv);
+			return FALSE;
+		}
+		flags += val_int;
 	}
+	g_strfreev (strv);
 
-	route_str = g_string_new (NULL);
-	num = nm_setting_ip4_config_get_num_routes (s_ip4);
-	for (i = 0; i < num; i++) {
-		char buf[INET_ADDRSTRLEN];
-		char *tmp;
-		NMIP4Route *route;
-		guint32 ip;
+	/* Validate the number according to the property spec */
+	if (!validate_uint (setting, prop, (guint) flags, error))
+		return FALSE;
 
-		if (i > 0)
-			g_string_append (route_str, "; ");
+	g_object_set (setting, prop, (guint) flags, NULL);
+	return TRUE;
+}
+
+static gboolean
+nmc_util_is_domain (const char *domain)
+{
+	//FIXME: implement
+	return TRUE;
+}
+
+static gboolean
+nmc_property_set_byte_array (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	char **strv = NULL, **iter;
+	char *val_strip;
+	const char *delimiters = " \t,";
+	long int val_int;
+	char *bin;
+	GByteArray *array = NULL;
+	gboolean success = TRUE;
+
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	val_strip = g_strstrip (g_strdup (val));
+
+	/* First try hex string in the format of AAbbCCDd */
+	bin = nm_utils_hexstr2bin (val_strip, strlen (val_strip));
+	if (bin) {
+		array = g_byte_array_sized_new (strlen (val_strip)/2);
+		g_byte_array_append (array, (const guint8 *) bin, strlen (val_strip)/2);
+		g_free (bin);
+		goto done;
+	}
+
+	/* Otherwise, consider the following format: AA b 0xCc D */
+	strv = nmc_strsplit_set (val_strip, delimiters, 0);
+	array = g_byte_array_sized_new (g_strv_length (strv));
+	for (iter = strv; iter && *iter; iter++) {
+		if (!nmc_string_to_int_base (g_strstrip (*iter), 16, TRUE, 0, 255, &val_int)) {
+			g_set_error (error, 1, 0, _("'%s' is not a valid hex character"), *iter);
+			success = FALSE;
+			goto done;
+		}
+		g_byte_array_append (array, (const guint8 *) &val_int, 1);
+	}
 
-		g_string_append (route_str, "{ ");
+done:
+	if (success)
+		g_object_set (setting, prop, array, NULL);
 
-		route = nm_setting_ip4_config_get_route (s_ip4, i);
+	g_strfreev (strv);
+	if (array)
+		g_byte_array_free (array, TRUE);
+	return success;
+}
 
-		memset (buf, 0, sizeof (buf));
-		ip = nm_ip4_route_get_dest (route);
-		inet_ntop (AF_INET, (const void *) &ip, buf, sizeof (buf));
-		g_string_append_printf (route_str, "dst = %s", buf);
+#define DEFINE_SETTER_MAC_BLACKLIST(def_func, s_macro, add_func) \
+	static gboolean \
+	def_func (NMSetting *setting, const char *prop, const char *val, GError **error) \
+	{ \
+		guint8 buf[32]; \
+		char **list = NULL, **iter; \
+		GSList *macaddr_blacklist = NULL; \
+		\
+		g_return_val_if_fail (error == NULL || *error == NULL, FALSE); \
+		\
+		list = nmc_strsplit_set (val, " \t,", 0); \
+		for (iter = list; iter && *iter; iter++) { \
+			if (!nm_utils_hwaddr_aton (*iter, ARPHRD_ETHER, buf)) { \
+				g_set_error (error, 1, 0, _("'%s' is not a valid MAC"), *iter); \
+				g_strfreev (list); \
+				g_slist_free (macaddr_blacklist); \
+				return FALSE; \
+			} \
+		} \
+		\
+		for (iter = list; iter && *iter; iter++) \
+			add_func (s_macro (setting), *iter); \
+		\
+		g_strfreev (list); \
+		return TRUE; \
+	}
 
-		tmp = g_strdup_printf ("/%u", nm_ip4_route_get_prefix (route));
-		g_string_append (route_str, tmp);
-		g_free (tmp);
+static char *
+nmc_property_out2in_cut_paren (const char *out_format)
+{
+	const char *p;
+	size_t n;
 
-		memset (buf, 0, sizeof (buf));
-		ip = nm_ip4_route_get_next_hop (route);
-		inet_ntop (AF_INET, (const void *) &ip, buf, sizeof (buf));
-		g_string_append_printf (route_str, ", nh = %s", buf);
+	p = strstr (out_format, " (");
+	n = p ? p - out_format : strlen (out_format);
+	return g_strndup (out_format, n);
+}
 
-		tmp = g_strdup_printf (", mt = %u", nm_ip4_route_get_metric (route));
-		g_string_append (route_str, tmp);
-		g_free (tmp);
+/* --- NM_SETTING_CONNECTION_SETTING_NAME property setter functions --- */
+#if 0
+/*
+ * Setting/removing UUID has been forbidden.
+ * Should it be enabled later, this function can be used.
+ */
+static gboolean
+nmc_property_con_set_uuid (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-		g_string_append (route_str, " }");
+	if (!nm_utils_is_uuid (val)) {
+		g_set_error (error, 1, 0, _("'%s' is not a valid UUID"), val);
+		return FALSE;
 	}
+	g_object_set (setting, prop, val, NULL);
+	return TRUE;
+}
+#endif
 
-	nmc->allowed_fields[0].value = NM_SETTING_IP4_CONFIG_SETTING_NAME;
-	nmc->allowed_fields[1].value = nm_setting_ip4_config_get_method (s_ip4);
-	nmc->allowed_fields[2].value = dns_str->str;
-	nmc->allowed_fields[3].value = dns_search_str->str;
-	nmc->allowed_fields[4].value = addr_str->str;
-	nmc->allowed_fields[5].value = route_str->str;
-	nmc->allowed_fields[6].value = nm_setting_ip4_config_get_ignore_auto_routes (s_ip4) ? _("yes") : _("no");
-	nmc->allowed_fields[7].value = nm_setting_ip4_config_get_ignore_auto_dns (s_ip4) ? _("yes") : _("no");
-	nmc->allowed_fields[8].value = nm_setting_ip4_config_get_dhcp_client_id (s_ip4);
-	nmc->allowed_fields[9].value = nm_setting_ip4_config_get_dhcp_send_hostname (s_ip4) ? _("yes") : _("no");
-	nmc->allowed_fields[10].value = nm_setting_ip4_config_get_dhcp_hostname (s_ip4);
-	nmc->allowed_fields[11].value = nm_setting_ip4_config_get_never_default (s_ip4) ? _("yes") : _("no");
-	nmc->allowed_fields[12].value = nm_setting_ip4_config_get_may_fail (s_ip4) ? _("yes") : _("no");
+/* 'permissions' */
+/* define from libnm-util/nm-setting-connection.c */
+#define PERM_USER_PREFIX  "user:"
 
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+static gboolean
+permissions_valid (const char *perm)
+{
+	if (!perm || perm[0] == '\0')
+		return FALSE;
 
-	g_string_free (dns_str, TRUE);
-	g_string_free (dns_search_str, TRUE);
-	g_string_free (addr_str, TRUE);
-	g_string_free (route_str, TRUE);
+	if (strncmp (perm, PERM_USER_PREFIX, strlen (PERM_USER_PREFIX)) == 0) {
+		if (   strlen (perm) <= strlen (PERM_USER_PREFIX)
+		    || strchr (perm + strlen (PERM_USER_PREFIX), ':'))
+			return  FALSE;
+	} else {
+		if (strchr (perm, ':'))
+			return  FALSE;
+	}
 
 	return TRUE;
 }
 
-gboolean
-setting_ip6_config_details (NMSettingIP6Config *s_ip6, NmCli *nmc)
+static gboolean
+nmc_property_connection_set_permissions (NMSetting *setting, const char *prop, const char *val, GError **error)
 {
-	GString *dns_str, *dns_search_str, *addr_str, *route_str;
-	char *ip6_privacy_str;
-	int i, num;
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+	char **strv = NULL;
+	guint i = 0;
 
-	g_return_val_if_fail (NM_IS_SETTING_IP6_CONFIG (s_ip6), FALSE);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-	nmc->allowed_fields = nmc_fields_setting_ip6_config;
-	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_IP6_CONFIG_ALL, nmc->allowed_fields, NULL);
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-	print_fields (nmc->print_fields, nmc->allowed_fields);  /* Print field names */
+	strv = nmc_strsplit_set (val, " \t,", 0);
+	if (!verify_string_list (strv, prop, permissions_valid, error)) {
+		g_strfreev (strv);
+		return FALSE;
+	}
+
+	for (i = 0; strv && strv[i]; i++) {
+		const char *user;
 
-	dns_str = g_string_new (NULL);
-	num = nm_setting_ip6_config_get_num_dns (s_ip6);
-	for (i = 0; i < num; i++) {
-		char buf[INET6_ADDRSTRLEN];
-		const struct in6_addr *ip;
+		if (strncmp (strv[i], PERM_USER_PREFIX, strlen (PERM_USER_PREFIX)) == 0)
+			user = strv[i]+strlen (PERM_USER_PREFIX);
+		else
+			user = strv[i];
 
-		ip = nm_setting_ip6_config_get_dns (s_ip6, i);
-		memset (buf, 0, sizeof (buf));
-		inet_ntop (AF_INET6, (const void *) ip, buf, sizeof (buf));
-		if (i > 0)
-			g_string_append (dns_str, ", ");
-		g_string_append (dns_str, buf);
+		nm_setting_connection_add_permission (NM_SETTING_CONNECTION (setting), "user", user, NULL);
 	}
 
-	dns_search_str = g_string_new (NULL);
-	num = nm_setting_ip6_config_get_num_dns_searches (s_ip6);
-	for (i = 0; i < num; i++) {
-		const char *domain;
+	return TRUE;
+}
+
+static gboolean
+_validate_and_remove_connection_permission (NMSettingConnection *setting,
+                                            const char *perm,
+                                            GError **error)
+{
+	gboolean ret;
+
+	ret = nm_setting_connection_remove_permission_by_value (setting, "user", perm, NULL);
+	if (!ret)
+		g_set_error (error, 1, 0, _("the property doesn't contain permission '%s'"), perm);
+	return ret;
+}
+DEFINE_REMOVER_INDEX_OR_VALUE (nmc_property_connection_remove_permissions,
+                               NM_SETTING_CONNECTION,
+                               nm_setting_connection_get_num_permissions,
+                               nm_setting_connection_remove_permission,
+                               _validate_and_remove_connection_permission)
+
+static const char *
+nmc_property_connection_describe_permissions (NMSetting *setting, const char *prop)
+{
+	return _("Enter a list of user permissions. This is a list of user names formatted as:\n"
+	         "  [user:]<user name 1>, [user:]<user name 2>,...\n"
+	         "The items can be separated by commas or spaces.\n\n"
+	         "Example: alice bob charlie\n");
+}
+
+/* 'master' */
+static gboolean
+nmc_property_con_set_master (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	if (!val)
+		;
+	else if (!*val)
+		val = NULL;
+	else if (   !nm_utils_iface_valid_name (val)
+	         && !nm_utils_is_uuid (val)) {
+		g_set_error (error, 1, 0,
+		             _("'%s' is not valid master; use ifname or connection UUID"),
+		             val);
+		return FALSE;
+	}
+	g_object_set (setting, prop, val, NULL);
+	return TRUE;
+}
+
+/* 'slave-type' */
+static const char *con_valid_slave_types[] = {
+	NM_SETTING_BOND_SETTING_NAME,
+	NM_SETTING_BRIDGE_SETTING_NAME,
+	NM_SETTING_VLAN_SETTING_NAME,
+	NULL
+};
+
+static gboolean
+nmc_property_con_set_slave_type (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	return check_and_set_string (setting, prop, val, con_valid_slave_types, error);
+}
+
+
+DEFINE_ALLOWED_VAL_FUNC (nmc_property_con_allowed_slave_type, con_valid_slave_types)
 
-		domain = nm_setting_ip6_config_get_dns_search (s_ip6, i);
-		if (i > 0)
-			g_string_append (dns_search_str, ", ");
-		g_string_append (dns_search_str, domain);
+/* 'secondaries' */
+static gboolean
+nmc_property_connection_set_secondaries (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	NMConnection *con;
+	char **strv = NULL, **iter;
+	guint i = 0;
+
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	strv = nmc_strsplit_set (val, " \t,", 0);
+	for (iter = strv; iter && *iter; iter++) {
+		if (**iter == '\0')
+			continue;
+
+		if (nm_utils_is_uuid (*iter)) {
+			con = nmc_find_connection (nm_cli.system_connections,
+			                           "uuid", *iter, NULL);
+			if (!con)
+				printf (_("Warning: %s is not an UUID of any existing connection profile\n"), *iter);
+			else {
+				/* Currenly NM only supports VPN connections as secondaries */
+				if (!nm_connection_is_type (con, NM_SETTING_VPN_SETTING_NAME)) {
+					g_set_error (error, 1, 0, _("'%s' is not a VPN connection profile"), *iter);
+					g_strfreev (strv);
+					return FALSE;
+				}
+			}
+		} else {
+			con = nmc_find_connection (nm_cli.system_connections,
+			                           "id", *iter, NULL);
+			if (!con) {
+				g_set_error (error, 1, 0, _("'%s' is not a name of any exiting profile"), *iter);
+				g_strfreev (strv);
+				return FALSE;
+			}
+
+			/* Currenly NM only supports VPN connections as secondaries */
+			if (!nm_connection_is_type (con, NM_SETTING_VPN_SETTING_NAME)) {
+				g_set_error (error, 1, 0, _("'%s' is not a VPN connection profile"), *iter);
+				g_strfreev (strv);
+				return FALSE;
+			}
+
+			/* translate id to uuid */
+			g_free (*iter);
+			*iter = g_strdup (nm_connection_get_uuid (con));
+		}
 	}
 
-	addr_str = g_string_new (NULL);
-	num = nm_setting_ip6_config_get_num_addresses (s_ip6);
-	for (i = 0; i < num; i++) {
-		char buf[INET6_ADDRSTRLEN];
-		char *tmp;
-		NMIP6Address *addr;
-		const struct in6_addr *ip;
+	while (strv && strv[i])
+		nm_setting_connection_add_secondary (NM_SETTING_CONNECTION (setting), strv[i++]);
+	g_strfreev (strv);
 
-		if (i > 0)
-			g_string_append (addr_str, "; ");
+	return TRUE;
+}
 
-		g_string_append (addr_str, "{ ");
+static gboolean
+_validate_and_remove_connection_secondary (NMSettingConnection *setting,
+                                           const char *secondary_uuid,
+                                           GError **error)
+{
+	gboolean ret;
 
-		addr = nm_setting_ip6_config_get_address (s_ip6, i);
+	if (!nm_utils_is_uuid (secondary_uuid)) {
+		g_set_error (error, 1, 0,
+		             _("the value '%s' is not a valid UUID"), secondary_uuid);
+		return FALSE;
+	}
 
-		memset (buf, 0, sizeof (buf));
-		ip = nm_ip6_address_get_address (addr);
-		inet_ntop (AF_INET6, (const void *) ip, buf, sizeof (buf));
-		g_string_append_printf (addr_str, "ip = %s", buf);
+	ret = nm_setting_connection_remove_secondary_by_value (setting, secondary_uuid);
+	if (!ret)
+		g_set_error (error, 1, 0,
+		             _("the property doesn't contain UUID '%s'"), secondary_uuid);
+	return ret;
+}
+DEFINE_REMOVER_INDEX_OR_VALUE (nmc_property_connection_remove_secondaries,
+                               NM_SETTING_CONNECTION,
+                               nm_setting_connection_get_num_secondaries,
+                               nm_setting_connection_remove_secondary,
+                               _validate_and_remove_connection_secondary)
+
+static const char *
+nmc_property_connection_describe_secondaries (NMSetting *setting, const char *prop)
+{
+	return _("Enter secondary connections that should be activated when this connection is\n"
+	         "activated. Connections can be specified either by UUID or ID (name). nmcli\n"
+	         "transparently translates names to UUIDs. Note that NetworkManager only supports\n"
+	         "VPNs as secondary connections at the moment.\n"
+	         "The items can be separated by commas or spaces.\n\n"
+	         "Example: private-openvpn, fe6ba5d8-c2fc-4aae-b2e3-97efddd8d9a7\n");
+}
 
-		tmp = g_strdup_printf ("/%u", nm_ip6_address_get_prefix (addr));
-		g_string_append (addr_str, tmp);
-		g_free (tmp);
+/* --- NM_SETTING_802_1X_SETTING_NAME property setter functions --- */
+#define DEFINE_SETTER_STR_LIST(def_func, set_func) \
+	static gboolean \
+	def_func (NMSetting *setting, const char *prop, const char *val, GError **error) \
+	{ \
+		char **strv = NULL; \
+		guint i = 0; \
+		\
+		g_return_val_if_fail (error == NULL || *error == NULL, FALSE); \
+		\
+		strv = nmc_strsplit_set (val, " \t,", 0); \
+		while (strv && strv[i]) \
+			set_func (NM_SETTING_802_1X (setting), strv[i++]); \
+		g_strfreev (strv); \
+		return TRUE; \
+	}
 
-		memset (buf, 0, sizeof (buf));
-		ip = nm_ip6_address_get_gateway (addr);
-		inet_ntop (AF_INET6, (const void *) ip, buf, sizeof (buf));
-		g_string_append_printf (addr_str, ", gw = %s", buf);
+#define DEFINE_SETTER_CERT(def_func, set_func) \
+	static gboolean \
+	def_func (NMSetting *setting, const char *prop, const char *val, GError **error) \
+	{ \
+		const char *SCHEME_PATH = "file://"; \
+		char *val_strip = g_strstrip (g_strdup (val)); \
+		char *p = val_strip; \
+		gboolean success; \
+		\
+		if (strncmp (val_strip, SCHEME_PATH, strlen (SCHEME_PATH)) == 0) \
+			p += strlen (SCHEME_PATH); \
+		\
+		success = set_func (NM_SETTING_802_1X (setting), \
+		                    p, \
+		                    NM_SETTING_802_1X_CK_SCHEME_PATH, \
+		                    NULL, \
+		                    error); \
+		g_free (val_strip); \
+		return success; \
+	}
 
-		g_string_append (addr_str, " }");
+#define DEFINE_SETTER_PRIV_KEY(def_func, pwd_func, set_func) \
+	static gboolean \
+	def_func (NMSetting *setting, const char *prop, const char *val, GError **error) \
+	{ \
+		char **strv = NULL; \
+		const char *SCHEME_PATH = "file://"; \
+		char *val_strip = g_strstrip (g_strdup (val)); \
+		char *p = val_strip; \
+		const char *path, *password; \
+		gboolean success; \
+		\
+		if (strncmp (val_strip, SCHEME_PATH, strlen (SCHEME_PATH)) == 0) \
+			p += strlen (SCHEME_PATH); \
+		\
+		strv = nmc_strsplit_set (p, " \t,", 2); \
+		path = strv[0]; \
+		if (g_strv_length (strv) == 2) \
+			password = strv[1]; \
+		else \
+			password = pwd_func (NM_SETTING_802_1X (setting)); \
+		if (password) { \
+			char *tmp_pwd = g_strdup (password); \
+			success = set_func (NM_SETTING_802_1X (setting), \
+			                    path, \
+			                    tmp_pwd, \
+			                    NM_SETTING_802_1X_CK_SCHEME_PATH, \
+			                    NULL, \
+			                    error); \
+			g_free (tmp_pwd); \
+		} else { \
+			success = FALSE; \
+			g_set_error_literal  (error, 1, 0, _("private key password not provided")); \
+		} \
+		g_free (val_strip); \
+		g_strfreev (strv); \
+		return success; \
 	}
 
-	route_str = g_string_new (NULL);
-	num = nm_setting_ip6_config_get_num_routes (s_ip6);
-	for (i = 0; i < num; i++) {
-		char buf[INET6_ADDRSTRLEN];
-		char *tmp;
-		NMIP6Route *route;
-		const struct in6_addr *ip;
+/* 'eap' */
+DEFINE_SETTER_STR_LIST_MULTI (check_and_add_802_1X_eap,
+                              NM_SETTING_802_1X,
+                              nm_setting_802_1x_add_eap_method)
+static gboolean
+nmc_property_802_1X_set_eap (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	const char *valid_eap[] = { "leap", "md5", "tls", "peap", "ttls", "sim", "fast", "pwd", NULL };
+	return check_and_add_802_1X_eap (setting, prop, val, valid_eap, error);
+}
+
+static gboolean
+_validate_and_remove_eap_method (NMSetting8021x *setting,
+                                 const char *eap,
+                                 GError **error)
+{
+	gboolean ret;
+
+	ret = nm_setting_802_1x_remove_eap_method_by_value(setting, eap);
+	if (!ret)
+		g_set_error (error, 1, 0, _("the property doesn't contain EAP method '%s'"), eap);
+	return ret;
+}
+DEFINE_REMOVER_INDEX_OR_VALUE (nmc_property_802_1X_remove_eap,
+                               NM_SETTING_802_1X,
+                               nm_setting_802_1x_get_num_eap_methods,
+                               nm_setting_802_1x_remove_eap_method,
+                               _validate_and_remove_eap_method)
+
+/* 'ca-cert' */
+DEFINE_SETTER_CERT (nmc_property_802_1X_set_ca_cert, nm_setting_802_1x_set_ca_cert)
+
+/* 'altsubject-matches' */
+DEFINE_SETTER_STR_LIST (nmc_property_802_1X_set_altsubject_matches, nm_setting_802_1x_add_altsubject_match)
+
+static gboolean
+_validate_and_remove_altsubject_match (NMSetting8021x *setting,
+                                       const char *altsubject_match,
+                                       GError **error)
+{
+	gboolean ret;
+
+	ret = nm_setting_802_1x_remove_altsubject_match_by_value (setting, altsubject_match);
+	if (!ret)
+		g_set_error (error, 1, 0,
+		             _("the property doesn't contain alternative subject match '%s'"),
+		             altsubject_match);
+	return ret;
+}
+DEFINE_REMOVER_INDEX_OR_VALUE (nmc_property_802_1X_remove_altsubject_matches,
+                               NM_SETTING_802_1X,
+                               nm_setting_802_1x_get_num_altsubject_matches,
+                               nm_setting_802_1x_remove_altsubject_match,
+                               _validate_and_remove_altsubject_match)
+
+/* 'client-cert' */
+DEFINE_SETTER_CERT (nmc_property_802_1X_set_client_cert, nm_setting_802_1x_set_client_cert)
+
+/* 'phase2-ca-cert' */
+DEFINE_SETTER_CERT (nmc_property_802_1X_set_phase2_ca_cert, nm_setting_802_1x_set_phase2_ca_cert)
+
+/* 'phase2-altsubject-matches' */
+DEFINE_SETTER_STR_LIST (nmc_property_802_1X_set_phase2_altsubject_matches, nm_setting_802_1x_add_phase2_altsubject_match)
+
+static gboolean
+_validate_and_remove_phase2_altsubject_match (NMSetting8021x *setting,
+                                              const char *phase2_altsubject_match,
+                                              GError **error)
+{
+	gboolean ret;
+
+	ret = nm_setting_802_1x_remove_phase2_altsubject_match_by_value (setting, phase2_altsubject_match);
+	if (!ret)
+		g_set_error (error, 1, 0,
+		             _("the property doesn't contain \"phase2\" alternative subject match '%s'"),
+		             phase2_altsubject_match);
+	return ret;
+}
+DEFINE_REMOVER_INDEX_OR_VALUE (nmc_property_802_1X_remove_phase2_altsubject_matches,
+                               NM_SETTING_802_1X,
+                               nm_setting_802_1x_get_num_phase2_altsubject_matches,
+                               nm_setting_802_1x_remove_phase2_altsubject_match,
+                               _validate_and_remove_phase2_altsubject_match)
+
+/* 'phase2-client-cert' */
+DEFINE_SETTER_CERT (nmc_property_802_1X_set_phase2_client_cert, nm_setting_802_1x_set_phase2_client_cert)
+
+/* 'private-key' */
+DEFINE_SETTER_PRIV_KEY (nmc_property_802_1X_set_private_key,
+                        nm_setting_802_1x_get_private_key_password,
+                        nm_setting_802_1x_set_private_key)
+
+/* 'phase2-private-key' */
+DEFINE_SETTER_PRIV_KEY (nmc_property_802_1X_set_phase2_private_key,
+                        nm_setting_802_1x_get_phase2_private_key_password,
+                        nm_setting_802_1x_set_phase2_private_key)
+
+static const char *
+nmc_property_802_1X_describe_private_key (NMSetting *setting, const char *prop)
+{
+	return _("Enter path to a private key and the key password (if not set yet):\n"
+	         "  <file path> [<password>]\n"
+	         "Example: /home/cimrman/jara-priv-key Dardanely\n");
+}
+
+/* 'phase1-peapver' */
+static const char *_802_1X_valid_phase1_peapvers[] = { "0", "1", NULL };
+
+static gboolean
+nmc_property_802_1X_set_phase1_peapver (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	return check_and_set_string (setting, prop, val, _802_1X_valid_phase1_peapvers, error);
+}
+
+DEFINE_ALLOWED_VAL_FUNC (nmc_property_802_1X_allowed_phase1_peapver, _802_1X_valid_phase1_peapvers)
+
+/* 'phase1-peaplabel' */
+static const char *_802_1X_valid_phase1_peaplabels[] = { "0", "1", NULL };
+
+static gboolean
+nmc_property_802_1X_set_phase1_peaplabel (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	return check_and_set_string (setting, prop, val, _802_1X_valid_phase1_peaplabels, error);
+}
+
+DEFINE_ALLOWED_VAL_FUNC (nmc_property_802_1X_allowed_phase1_peaplabel, _802_1X_valid_phase1_peaplabels)
+
+/* 'phase1-fast-provisioning' */
+static const char *_802_1X_valid_phase1_fast_provisionings[] = { "0", "1", "2", "3", NULL };
+
+static gboolean
+nmc_property_802_1X_set_phase1_fast_provisioning (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	return check_and_set_string (setting, prop, val, _802_1X_valid_phase1_fast_provisionings, error);
+}
+
+DEFINE_ALLOWED_VAL_FUNC (nmc_property_802_1X_allowed_phase1_fast_provisioning, _802_1X_valid_phase1_fast_provisionings)
+
+/* 'phase2-auth' */
+static const char *_802_1X_valid_phase2_auths[] =
+	{ "pap", "chap", "mschap", "mschapv2", "gtc", "otp", "md5", "tls", NULL };
+
+static gboolean
+nmc_property_802_1X_set_phase2_auth (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	return check_and_set_string (setting, prop, val, _802_1X_valid_phase2_auths, error);
+}
+
+DEFINE_ALLOWED_VAL_FUNC (nmc_property_802_1X_allowed_phase2_auth, _802_1X_valid_phase2_auths)
+
+/* 'phase2-autheap' */
+static const char *_802_1X_valid_phase2_autheaps[] = { "md5", "mschapv2", "otp", "gtc", "tls", NULL };
+static gboolean
+nmc_property_802_1X_set_phase2_autheap (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	return check_and_set_string (setting, prop, val, _802_1X_valid_phase2_autheaps, error);
+}
 
-		if (i > 0)
-			g_string_append (route_str, "; ");
+DEFINE_ALLOWED_VAL_FUNC (nmc_property_802_1X_allowed_phase2_autheap, _802_1X_valid_phase2_autheaps)
 
-		g_string_append (route_str, "{ ");
+/* 'password-raw' */
+static gboolean
+nmc_property_802_1X_set_password_raw (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	return nmc_property_set_byte_array (setting, prop, val, error);
+}
 
-		route = nm_setting_ip6_config_get_route (s_ip6, i);
+static const char *
+nmc_property_802_1X_describe_password_raw (NMSetting *setting, const char *prop)
+{
+	return _("Enter bytes as a list of hexadecimal values.\n"
+	         "Two formats are accepted:\n"
+	         "(a) a string of hexadecimal digits, where each two digits represent one byte\n"
+	         "(b) space-separated list of bytes written as hexadecimal digits "
+	         "(with optional 0x/0X prefix, and optional leading 0).\n\n"
+	         "Examples: ab0455a6ea3a74C2\n"
+	         "          ab 4 55 0xa6 ea 3a 74 C2\n");
+}
 
-		memset (buf, 0, sizeof (buf));
-		ip = nm_ip6_route_get_dest (route);
-		inet_ntop (AF_INET6, (const void *) ip, buf, sizeof (buf));
-		g_string_append_printf (route_str, "dst = %s", buf);
+/* --- NM_SETTING_ADSL_SETTING_NAME property setter functions --- */
+/* 'protocol' */
+static const char *adsl_valid_protocols[] = {
+	NM_SETTING_ADSL_PROTOCOL_PPPOA,
+	NM_SETTING_ADSL_PROTOCOL_PPPOE,
+	NM_SETTING_ADSL_PROTOCOL_IPOATM,
+	NULL
+};
 
-		tmp = g_strdup_printf ("/%u", nm_ip6_route_get_prefix (route));
-		g_string_append (route_str, tmp);
-		g_free (tmp);
+static gboolean
+nmc_property_adsl_set_protocol (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	return check_and_set_string (setting, prop, val, adsl_valid_protocols, error);
+}
 
-		memset (buf, 0, sizeof (buf));
-		ip = nm_ip6_route_get_next_hop (route);
-		inet_ntop (AF_INET6, (const void *) ip, buf, sizeof (buf));
-		g_string_append_printf (route_str, ", nh = %s", buf);
+DEFINE_ALLOWED_VAL_FUNC (nmc_property_adsl_allowed_protocol, adsl_valid_protocols)
 
-		tmp = g_strdup_printf (", mt = %u", nm_ip6_route_get_metric (route));
-		g_string_append (route_str, tmp);
-		g_free (tmp);
+/* 'encapsulation' */
+static const char *adsl_valid_encapsulations[] = {
+	NM_SETTING_ADSL_ENCAPSULATION_VCMUX,
+	NM_SETTING_ADSL_ENCAPSULATION_LLC,
+	NULL
+};
 
-		g_string_append (route_str, " }");
+static gboolean
+nmc_property_adsl_set_encapsulation (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	return check_and_set_string (setting, prop, val, adsl_valid_encapsulations, error);
+}
+
+DEFINE_ALLOWED_VAL_FUNC (nmc_property_adsl_allowed_encapsulation, adsl_valid_encapsulations)
+
+/* --- NM_SETTING_BLUETOOTH_SETTING_NAME property setter functions --- */
+/* 'type' */
+static gboolean
+nmc_property_bluetooth_set_type (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	const char *types[] = {
+	    NM_SETTING_BLUETOOTH_TYPE_DUN,
+	    NM_SETTING_BLUETOOTH_TYPE_PANU,
+	    NULL };
+
+	return check_and_set_string (setting, prop, val, types, error);
+}
+
+/* --- NM_SETTING_BOND_SETTING_NAME property setter functions --- */
+/* 'options' */
+/*  example: miimon=100,mode=balance-rr, updelay=5 */
+static gboolean
+_validate_and_remove_bond_option (NMSettingBond *setting, const char *option)
+{
+	const char *opt;
+	const char **valid_options;
+
+	valid_options = nm_setting_bond_get_valid_options (setting);
+	opt = nmc_string_is_valid (option, valid_options, NULL);
+
+	if (opt)
+		return nm_setting_bond_remove_option (setting, opt);
+	else
+		return FALSE;
+}
+
+/* Validate bonding 'options' values */
+static const char *
+_validate_bond_option_value (const char *option, const char *value, GError **error)
+{
+	if (!g_strcmp0 (option, NM_SETTING_BOND_OPTION_MODE))
+		return nmc_bond_validate_mode (value, error);
+
+	return value;
+}
+
+DEFINE_SETTER_OPTIONS (nmc_property_bond_set_options,
+                       NM_SETTING_BOND,
+                       NMSettingBond,
+                       nm_setting_bond_add_option,
+                       nm_setting_bond_get_valid_options,
+                       _validate_bond_option_value)
+DEFINE_REMOVER_OPTION (nmc_property_bond_remove_option_options,
+                       NM_SETTING_BOND,
+                       _validate_and_remove_bond_option)
+
+static const char *
+nmc_property_bond_describe_options (NMSetting *setting, const char *prop)
+{
+	static char *desc = NULL;
+	const char **valid_options;
+	char *options_str;
+
+	if (G_UNLIKELY (desc == NULL)) {
+		valid_options = nm_setting_bond_get_valid_options (NM_SETTING_BOND (setting));
+		options_str = g_strjoinv (", ", (char **) valid_options);
+
+		desc = g_strdup_printf (_("Enter a list of bonding options formatted as:\n"
+		                          "  option = <value>, option = <value>,... \n"
+		                          "Valid options are: %s\n"
+		                          "'mode' can be provided as a name or a number:\n"
+		                          "balance-rr    = 0\n"
+		                          "active-backup = 1\n"
+		                          "balance-xor   = 2\n"
+		                          "broadcast     = 3\n"
+		                          "802.3ad       = 4\n"
+		                          "balance-tlb   = 5\n"
+		                          "balance-alb   = 6\n\n"
+		                          "Example: mode=2,miimon=120\n"), options_str);
+		g_free (options_str);
 	}
+	return desc;
+}
+
+static const char *
+nmc_property_bond_allowed_options (NMSetting *setting, const char *prop)
+{
+	const char **valid_options;
+	static char *allowed_vals = NULL;
 
-	ip6_privacy_str = ip6_privacy_to_string (nm_setting_ip6_config_get_ip6_privacy (s_ip6));
+	if (G_UNLIKELY (allowed_vals == NULL)) {
+		valid_options = nm_setting_bond_get_valid_options (NM_SETTING_BOND (setting));
+		allowed_vals = g_strjoinv (", ", (char **) valid_options);
+	}
+	return allowed_vals;
+}
 
-	nmc->allowed_fields[0].value = NM_SETTING_IP6_CONFIG_SETTING_NAME;
-	nmc->allowed_fields[1].value = nm_setting_ip6_config_get_method (s_ip6);
-	nmc->allowed_fields[2].value = dns_str->str;
-	nmc->allowed_fields[3].value = dns_search_str->str;
-	nmc->allowed_fields[4].value = addr_str->str;
-	nmc->allowed_fields[5].value = route_str->str;
-	nmc->allowed_fields[6].value = nm_setting_ip6_config_get_ignore_auto_routes (s_ip6) ? _("yes") : _("no");
-	nmc->allowed_fields[7].value = nm_setting_ip6_config_get_ignore_auto_dns (s_ip6) ? _("yes") : _("no");
-	nmc->allowed_fields[8].value = nm_setting_ip6_config_get_never_default (s_ip6) ? _("yes") : _("no");
-	nmc->allowed_fields[9].value = nm_setting_ip6_config_get_may_fail (s_ip6) ? _("yes") : _("no");
-	nmc->allowed_fields[10].value = ip6_privacy_str;
-	nmc->allowed_fields[11].value = nm_setting_ip6_config_get_dhcp_hostname (s_ip6);
+/* --- NM_SETTING_INFINIBAND_SETTING_NAME property setter functions --- */
+/* 'mac-addresss' */
+static gboolean
+nmc_property_ib_set_mac (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	GByteArray *array;
 
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-	g_string_free (dns_str, TRUE);
-	g_string_free (dns_search_str, TRUE);
-	g_string_free (addr_str, TRUE);
-	g_string_free (route_str, TRUE);
-	g_free (ip6_privacy_str);
+	array = nm_utils_hwaddr_atoba (val, ARPHRD_INFINIBAND);
+	if (!array) {
+		g_set_error (error, 1, 0, _("'%s' is not a valid InfiniBand MAC"), val);
+		return FALSE;
+	}
 
+	g_object_set (setting, prop, array, NULL);
+	g_byte_array_free (array, TRUE);
 	return TRUE;
 }
 
-gboolean
-setting_serial_details (NMSettingSerial *s_serial, NmCli *nmc)
+/* 'transport-mode' */
+static const char *ib_valid_transport_modes[] = { "datagram", "connected", NULL };
+
+static gboolean
+nmc_property_ib_set_transport_mode (NMSetting *setting, const char *prop, const char *val, GError **error)
 {
-	char *baud_str, *bits_str, *parity_str, *stopbits_str, *send_delay_str;
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+	return check_and_set_string (setting, prop, val, ib_valid_transport_modes, error);
+}
 
-	g_return_val_if_fail (NM_IS_SETTING_SERIAL (s_serial), FALSE);
+DEFINE_ALLOWED_VAL_FUNC (nmc_property_ib_allowed_transport_mode, ib_valid_transport_modes)
 
-	nmc->allowed_fields = nmc_fields_setting_serial;
-	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_SERIAL_ALL, nmc->allowed_fields, NULL);
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-	print_fields (nmc->print_fields, nmc->allowed_fields);  /* Print field names */
+/* 'p-key' */
+static gboolean
+nmc_property_ib_set_p_key (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	gboolean p_key_valid = FALSE;
+	long p_key_int;
 
-	baud_str = g_strdup_printf ("%d", nm_setting_serial_get_baud (s_serial));
-	bits_str = g_strdup_printf ("%d", nm_setting_serial_get_bits (s_serial));
-	parity_str = g_strdup_printf ("%c", nm_setting_serial_get_parity (s_serial));
-	stopbits_str = g_strdup_printf ("%d", nm_setting_serial_get_stopbits (s_serial));
-	send_delay_str = g_strdup_printf ("%" G_GUINT64_FORMAT, nm_setting_serial_get_send_delay (s_serial));
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-	nmc->allowed_fields[0].value = NM_SETTING_SERIAL_SETTING_NAME;
-	nmc->allowed_fields[1].value = baud_str;
-	nmc->allowed_fields[2].value = bits_str;
-	nmc->allowed_fields[3].value = parity_str;
-	nmc->allowed_fields[4].value = stopbits_str;
-	nmc->allowed_fields[5].value = send_delay_str;
+	if (!strncasecmp (val, "0x", 2))
+		p_key_valid = nmc_string_to_int_base (val + 2, 16, TRUE, 0, G_MAXUINT16, &p_key_int);
+	else
+		p_key_valid = nmc_string_to_int (val, TRUE, -1, G_MAXUINT16, &p_key_int);
+
+	if (!p_key_valid) {
+		if (strcmp (val, "default") == 0)
+			p_key_int = -1;
+		else {
+			g_set_error (error, 1, 0, _("'%s' is not a valid IBoIP P_Key"), val);
+			return FALSE;
+		}
+	}
+	g_object_set (setting, prop, (gint) p_key_int, NULL);
+	return TRUE;
+}
 
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+/* --- NM_SETTING_IP4_CONFIG_SETTING_NAME property setter functions --- */
+/* 'method' */
+static const char *ipv4_valid_methods[] = {
+	NM_SETTING_IP4_CONFIG_METHOD_AUTO,
+	NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL,
+	NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
+	NM_SETTING_IP4_CONFIG_METHOD_SHARED,
+	NM_SETTING_IP4_CONFIG_METHOD_DISABLED,
+	NULL
+};
 
-	g_free (baud_str);
-	g_free (bits_str);
-	g_free (parity_str);
-	g_free (stopbits_str);
-	g_free (send_delay_str);
+static gboolean
+nmc_property_ipv4_set_method (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	/* Silently accept "static" and convert to "manual" */
+	if (val && strlen (val) > 1 && matches (val, "static") == 0)
+		val = NM_SETTING_IP4_CONFIG_METHOD_MANUAL;
 
+	return check_and_set_string (setting, prop, val, ipv4_valid_methods, error);
+}
+
+DEFINE_ALLOWED_VAL_FUNC (nmc_property_ipv4_allowed_method, ipv4_valid_methods)
+
+/* 'dns' */
+static gboolean
+nmc_property_ipv4_set_dns (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	char **strv = NULL, **iter;
+	guint32 ip4_addr;
+
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	strv = nmc_strsplit_set (val, " \t,", 0);
+	for (iter = strv; iter && *iter; iter++) {
+		if (inet_pton (AF_INET, g_strstrip (*iter), &ip4_addr) < 1) {
+			g_set_error (error, 1, 0, _("invalid IPv4 address '%s'"), *iter);
+			g_strfreev (strv);
+			return FALSE;
+		}
+		nm_setting_ip4_config_add_dns (NM_SETTING_IP4_CONFIG (setting), ip4_addr);
+	}
+	g_strfreev (strv);
 	return TRUE;
 }
 
-gboolean
-setting_ppp_details (NMSettingPPP *s_ppp, NmCli *nmc)
+static gboolean
+_validate_and_remove_ipv4_dns (NMSettingIP4Config *setting,
+                               const char *dns,
+                               GError **error)
 {
-	char *baud_str, *mru_str, *mtu_str, *lcp_echo_failure_str, *lcp_echo_interval_str;
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+	guint32 ip4_addr;
+	gboolean ret;
 
-	g_return_val_if_fail (NM_IS_SETTING_PPP (s_ppp), FALSE);
+	if (inet_pton (AF_INET, dns, &ip4_addr) < 1) {
+		g_set_error (error, 1, 0, _("invalid IPv4 address '%s'"), dns);
+		return FALSE;
+	}
 
-	nmc->allowed_fields = nmc_fields_setting_ppp;
-	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_PPP_ALL, nmc->allowed_fields, NULL);
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-	print_fields (nmc->print_fields, nmc->allowed_fields);  /* Print field names */
-
-	baud_str = g_strdup_printf ("%d", nm_setting_ppp_get_baud (s_ppp));
-	mru_str = g_strdup_printf ("%d", nm_setting_ppp_get_mru (s_ppp));
-	mtu_str = g_strdup_printf ("%d", nm_setting_ppp_get_mtu (s_ppp));
-	lcp_echo_failure_str = g_strdup_printf ("%d", nm_setting_ppp_get_lcp_echo_failure (s_ppp));
-	lcp_echo_interval_str = g_strdup_printf ("%d", nm_setting_ppp_get_lcp_echo_interval (s_ppp));
-
-	nmc->allowed_fields[0].value = NM_SETTING_PPP_SETTING_NAME;
-	nmc->allowed_fields[1].value = nm_setting_ppp_get_noauth (s_ppp) ? _("yes") : _("no");
-	nmc->allowed_fields[2].value = nm_setting_ppp_get_refuse_eap (s_ppp) ? _("yes") : _("no");
-	nmc->allowed_fields[3].value = nm_setting_ppp_get_refuse_pap (s_ppp) ? _("yes") : _("no");
-	nmc->allowed_fields[4].value = nm_setting_ppp_get_refuse_chap (s_ppp) ? _("yes") : _("no");
-	nmc->allowed_fields[5].value = nm_setting_ppp_get_refuse_mschap (s_ppp) ? _("yes") : _("no");
-	nmc->allowed_fields[6].value = nm_setting_ppp_get_refuse_mschapv2 (s_ppp) ? _("yes") : _("no");
-	nmc->allowed_fields[7].value = nm_setting_ppp_get_nobsdcomp (s_ppp) ? _("yes") : _("no");
-	nmc->allowed_fields[8].value = nm_setting_ppp_get_nodeflate (s_ppp) ? _("yes") : _("no");
-	nmc->allowed_fields[9].value = nm_setting_ppp_get_no_vj_comp (s_ppp) ? _("yes") : _("no");
-	nmc->allowed_fields[10].value = nm_setting_ppp_get_require_mppe (s_ppp) ? _("yes") : _("no");
-	nmc->allowed_fields[11].value = nm_setting_ppp_get_require_mppe_128 (s_ppp) ? _("yes") : _("no");
-	nmc->allowed_fields[12].value = nm_setting_ppp_get_mppe_stateful (s_ppp) ? _("yes") : _("no");
-	nmc->allowed_fields[13].value = nm_setting_ppp_get_crtscts (s_ppp) ? _("yes") : _("no");
-	nmc->allowed_fields[14].value = baud_str;
-	nmc->allowed_fields[15].value = mru_str;
-	nmc->allowed_fields[16].value = mtu_str;
-	nmc->allowed_fields[17].value = lcp_echo_failure_str;
-	nmc->allowed_fields[18].value = lcp_echo_interval_str;
-
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
-
-	g_free (baud_str);
-	g_free (mru_str);
-	g_free (mtu_str);
-	g_free (lcp_echo_failure_str);
-	g_free (lcp_echo_interval_str);
+	ret = nm_setting_ip4_config_remove_dns_by_value (setting, ip4_addr);
+	if (!ret)
+		g_set_error (error, 1, 0, _("the property doesn't contain DNS server '%s'"), dns);
+	return ret;
+}
+DEFINE_REMOVER_INDEX_OR_VALUE (nmc_property_ipv4_remove_dns,
+                               NM_SETTING_IP4_CONFIG,
+                               nm_setting_ip4_config_get_num_dns,
+                               nm_setting_ip4_config_remove_dns,
+                               _validate_and_remove_ipv4_dns)
+
+static const char *
+nmc_property_ipv4_describe_dns (NMSetting *setting, const char *prop)
+{
+	return _("Enter a list of IPv4 addresses of DNS servers.\n\n"
+	         "Example: 8.8.8.8, 8.8.4.4\n");
+}
+
+/* 'dns-search' */
+static gboolean
+nmc_property_ipv4_set_dns_search (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	char **strv = NULL;
+	guint i = 0;
+
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	strv = nmc_strsplit_set (val, " \t,", 0);
+	if (!verify_string_list (strv, prop, nmc_util_is_domain, error)) {
+		g_strfreev (strv);
+		return FALSE;
+	}
+
+	while (strv && strv[i])
+		nm_setting_ip4_config_add_dns_search (NM_SETTING_IP4_CONFIG (setting), strv[i++]);
+	g_strfreev (strv);
 
 	return TRUE;
 }
 
-gboolean
-setting_pppoe_details (NMSettingPPPOE *s_pppoe, NmCli *nmc)
+static gboolean
+_validate_and_remove_ipv4_dns_search (NMSettingIP4Config *setting,
+                                      const char *dns_search,
+                                      GError **error)
 {
-	char *pswd_flags;
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+	gboolean ret;
+
+	ret = nm_setting_ip4_config_remove_dns_search_by_value (setting, dns_search);
+	if (!ret)
+		g_set_error (error, 1, 0,
+		             _("the property doesn't contain DNS search domain '%s'"),
+		             dns_search);
+	return ret;
+}
+DEFINE_REMOVER_INDEX_OR_VALUE (nmc_property_ipv4_remove_dns_search,
+                               NM_SETTING_IP4_CONFIG,
+                               nm_setting_ip4_config_get_num_dns_searches,
+                               nm_setting_ip4_config_remove_dns_search,
+                               _validate_and_remove_ipv4_dns_search)
+
+/* 'addresses' */
+static NMIP4Address *
+_parse_ipv4_address (const char *address, GError **error)
+{
+	char *value = g_strdup (address);
+	char **addrv;
+	NMIP4Address *ip4addr;
+
+	addrv = nmc_strsplit_set (g_strstrip (value), " \t", 0);
+	if (addrv[0] == NULL || g_strv_length (addrv) > 2) {
+		g_set_error (error, 1, 0, _("'%s' is not valid (use ip[/prefix] [gateway])"),
+		             address);
+		g_free (value);
+		g_strfreev (addrv);
+		return NULL;
+	}
+	ip4addr = nmc_parse_and_build_ip4_address (addrv[0], addrv[1], error);
+	g_free (value);
+	g_strfreev (addrv);
+	return ip4addr;
+}
 
-	g_return_val_if_fail (NM_IS_SETTING_PPPOE (s_pppoe), FALSE);
+static gboolean
+nmc_property_ipv4_set_addresses (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	char **strv = NULL, **iter;
+	NMIP4Address *ip4addr;
+
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	strv = nmc_strsplit_set (val, ",", 0);
+	for (iter = strv; iter && *iter; iter++) {
+		ip4addr = _parse_ipv4_address (*iter, error);
+		if (!ip4addr) {
+			g_strfreev (strv);
+			return FALSE;
+		}
+		nm_setting_ip4_config_add_address (NM_SETTING_IP4_CONFIG (setting), ip4addr);
+		nm_ip4_address_unref (ip4addr);
+	}
+	g_strfreev (strv);
+	return TRUE;
+}
+
+static gboolean
+_validate_and_remove_ipv4_address (NMSettingIP4Config *setting,
+                                   const char *address,
+                                   GError **error)
+{
+	NMIP4Address *ip4addr;
+	gboolean ret;
 
-	nmc->allowed_fields = nmc_fields_setting_pppoe;
-	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_PPPOE_ALL, nmc->allowed_fields, NULL);
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-	print_fields (nmc->print_fields, nmc->allowed_fields);  /* Print field names */
+	ip4addr = _parse_ipv4_address (address, error);
+	if (!ip4addr)
+		return FALSE;
 
-	pswd_flags = secret_flags_to_string (nm_setting_pppoe_get_password_flags (s_pppoe));
+	ret = nm_setting_ip4_config_remove_address_by_value (setting, ip4addr);
+	if (!ret)
+		g_set_error (error, 1, 0,
+		             _("the property doesn't contain IP address '%s'"), address);
+	nm_ip4_address_unref (ip4addr);
+	return ret;
+}
+DEFINE_REMOVER_INDEX_OR_VALUE (nmc_property_ipv4_remove_addresses,
+                               NM_SETTING_IP4_CONFIG,
+                               nm_setting_ip4_config_get_num_addresses,
+                               nm_setting_ip4_config_remove_address,
+                               _validate_and_remove_ipv4_address)
+
+static const char *
+nmc_property_ipv4_describe_addresses (NMSetting *setting, const char *prop)
+{
+	return _("Enter a list of IPv4 addresses formatted as:\n"
+	         "  ip[/prefix] [gateway], ip[/prefix] [gateway],...\n"
+	         "Missing prefix is regarded as prefix of 32.\n\n"
+	         "Example: 192.168.1.5/24 192.168.1.1, 10.0.0.11/24\n");
+}
 
-	nmc->allowed_fields[0].value = NM_SETTING_PPPOE_SETTING_NAME;
-	nmc->allowed_fields[1].value = nm_setting_pppoe_get_service (s_pppoe);
-	nmc->allowed_fields[2].value = nm_setting_pppoe_get_username (s_pppoe);
-	nmc->allowed_fields[3].value = nm_setting_pppoe_get_password (s_pppoe);
-	nmc->allowed_fields[4].value = pswd_flags;
+/*
+ * from: { ip = 1.2.3.4/24, gw = 1.2.3.254 }; { ip = 2.2.2.2/16, gw = 5.5.5.5 }
+ * to:   1.2.3.4/24 1.2.3.254, 2.2.2.2/16 5.5.5.5
+ * from: { ip = 11::22/64, gw = 22::33 }; { ip = ab::cd/64, gw = ab::1 }
+ * to:   11::22/64 22:33, ab::cd/64 ab::1
+*/
+static char *
+nmc_property_out2in_addresses (const char *out_format)
+{
+        GRegex *regex;
+	GString *str;
+        char **strv;
+	int i;
 
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+	str = g_string_sized_new (128);
+	regex = g_regex_new ("\\{ ip = ([^/]+)/([^,]+), gw = ([^ ]+) \\}", 0, 0, NULL);
+
+	strv = g_regex_split (regex, out_format, 0);
+	for (i = 1; strv && strv[i] && strv[i+1] && strv[i+2]; i=i+4) {
+		g_string_append (str, strv[i]); /* IP */
+		g_string_append_c (str, '/');
+		g_string_append (str, strv[i+1]); /* prefix */
+		g_string_append_c (str, ' ');
+		g_string_append (str, strv[i+2]); /* gateway */
+		g_string_append (str, ", ");
+	}
+	if (str->len > 0)
+		g_string_truncate (str, str->len - 2);
 
-	g_free (pswd_flags);
+	g_strfreev (strv);
+	g_regex_unref (regex);
 
+	return g_string_free (str, FALSE);
+}
+
+/* 'routes' */
+static NMIP4Route *
+_parse_ipv4_route (const char *route, GError **error)
+{
+	char *value = g_strdup (route);
+	char **routev;
+	guint len;
+	NMIP4Route *ip4route = NULL;
+
+	routev = nmc_strsplit_set (g_strstrip (value), " \t", 0);
+	len = g_strv_length (routev);
+	if (len < 1 || len > 3) {
+		g_set_error (error, 1, 0, _("'%s' is not valid (the format is: ip[/prefix] [next-hop] [metric])"),
+		             route);
+		goto finish;
+	}
+	ip4route = nmc_parse_and_build_ip4_route (routev[0], routev[1], len >= 2 ? routev[2] : NULL, error);
+
+finish:
+	g_free (value);
+	g_strfreev (routev);
+	return ip4route;
+}
+
+static gboolean
+nmc_property_ipv4_set_routes (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	char **strv = NULL, **iter;
+	NMIP4Route *ip4route;
+
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	strv = nmc_strsplit_set (val, ",", 0);
+	for (iter = strv; iter && *iter; iter++) {
+		ip4route = _parse_ipv4_route (*iter, error);
+		if (!ip4route) {
+			g_strfreev (strv);
+			return FALSE;
+		}
+		nm_setting_ip4_config_add_route (NM_SETTING_IP4_CONFIG (setting), ip4route);
+		nm_ip4_route_unref (ip4route);
+	}
+	g_strfreev (strv);
 	return TRUE;
 }
 
-gboolean
-setting_gsm_details (NMSettingGsm *s_gsm, NmCli *nmc)
+static gboolean
+_validate_and_remove_ipv4_route (NMSettingIP4Config *setting,
+                                 const char *route,
+                                 GError **error)
 {
-	char *network_type_str, *allowed_bands_str, *pswd_flags, *pin_flags;
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+	NMIP4Route *ip4route;
+	gboolean ret;
 
-	g_return_val_if_fail (NM_IS_SETTING_GSM (s_gsm), FALSE);
+	ip4route = _parse_ipv4_route (route, error);
+	if (!ip4route)
+		return FALSE;
+
+	ret = nm_setting_ip4_config_remove_route_by_value (setting, ip4route);
+	if (!ret)
+		g_set_error (error, 1, 0, _("the property doesn't contain route '%s'"), route);
+	nm_ip4_route_unref (ip4route);
+	return ret;
+}
+DEFINE_REMOVER_INDEX_OR_VALUE (nmc_property_ipv4_remove_routes,
+                               NM_SETTING_IP4_CONFIG,
+                               nm_setting_ip4_config_get_num_routes,
+                               nm_setting_ip4_config_remove_route,
+                               _validate_and_remove_ipv4_route)
+
+static const char *
+nmc_property_ipv4_describe_routes (NMSetting *setting, const char *prop)
+{
+	return _("Enter a list of IPv4 routes formatted as:\n"
+	         "  ip[/prefix] [next-hop] [metric],...\n\n"
+	         "Missing prefix is regarded as a prefix of 32.\n"
+	         "Missing next-hop is regarded as 0.0.0.0.\n"
+	         "Missing metric or 0 means a default metric (NM/kernel will set a default value).\n\n"
+	         "Examples: 192.168.2.0/24 192.168.2.1 3, 10.1.0.0/16 10.0.0.254\n"
+	         "          10.1.2.0/24\n");
+}
+
+static char *
+nmc_property_out2in_routes (const char *out_format)
+{
+        GRegex *regex;
+	GString *str;
+        char **strv;
+	int i;
 
-	nmc->allowed_fields = nmc_fields_setting_gsm;
-	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_GSM_ALL, nmc->allowed_fields, NULL);
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-	print_fields (nmc->print_fields, nmc->allowed_fields);  /* Print field names */
+	str = g_string_sized_new (128);
+	regex = g_regex_new ("\\{ dst = ([^/]+)/([^,]+), nh = ([^,]+), mt = ([^ ]+) \\}", 0, 0, NULL);
+
+	strv = g_regex_split (regex, out_format, 0);
+	for (i = 1; strv && strv[i] && strv[i+1] && strv[i+2] && strv[i+3]; i=i+5) {
+		g_string_append (str, strv[i]); /* IP */
+		g_string_append_c (str, '/');
+		g_string_append (str, strv[i+1]); /* prefix */
+		g_string_append_c (str, ' ');
+		g_string_append (str, strv[i+2]); /* next hop */
+		g_string_append_c (str, ' ');
+		g_string_append (str, strv[i+3]); /* metric */
+		g_string_append (str, ", ");
+	}
+	if (str->len > 0)
+		g_string_truncate (str, str->len - 2);
 
-	network_type_str = g_strdup_printf ("%d", nm_setting_gsm_get_network_type (s_gsm));
-	allowed_bands_str = allowed_bands_to_string (nm_setting_gsm_get_allowed_bands (s_gsm));
+	g_strfreev (strv);
+	g_regex_unref (regex);
 
-	pswd_flags = secret_flags_to_string (nm_setting_gsm_get_password_flags (s_gsm));
-	pin_flags = secret_flags_to_string (nm_setting_gsm_get_pin_flags (s_gsm));
+	return g_string_free (str, FALSE);
+}
 
-	nmc->allowed_fields[0].value = NM_SETTING_GSM_SETTING_NAME;
-	nmc->allowed_fields[1].value = nm_setting_gsm_get_number (s_gsm);
-	nmc->allowed_fields[2].value = nm_setting_gsm_get_username (s_gsm);
-	nmc->allowed_fields[3].value = nm_setting_gsm_get_password (s_gsm);
-	nmc->allowed_fields[4].value = pswd_flags;
-	nmc->allowed_fields[5].value = nm_setting_gsm_get_apn (s_gsm);
-	nmc->allowed_fields[6].value = nm_setting_gsm_get_network_id (s_gsm);
-	nmc->allowed_fields[7].value = network_type_str;
-	nmc->allowed_fields[8].value = allowed_bands_str;
-	nmc->allowed_fields[9].value = nm_setting_gsm_get_pin (s_gsm);
-	nmc->allowed_fields[10].value = pin_flags;
-	nmc->allowed_fields[11].value = nm_setting_gsm_get_home_only (s_gsm) ? _("yes") : _("no");
+/* --- NM_SETTING_IP6_CONFIG_SETTING_NAME property setter functions --- */
+/* 'method' */
+static const char *ipv6_valid_methods[] = {
+	NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
+	NM_SETTING_IP6_CONFIG_METHOD_AUTO,
+	NM_SETTING_IP6_CONFIG_METHOD_DHCP,
+	NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL,
+	NM_SETTING_IP6_CONFIG_METHOD_MANUAL,
+	NM_SETTING_IP6_CONFIG_METHOD_SHARED,
+	NULL
+};
+
+static gboolean
+nmc_property_ipv6_set_method (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	/* Silently accept "static" and convert to "manual" */
+	if (val && strlen (val) > 1 && matches (val, "static") == 0)
+		val = NM_SETTING_IP6_CONFIG_METHOD_MANUAL;
 
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+	return check_and_set_string (setting, prop, val, ipv6_valid_methods, error);
+}
 
-	g_free (network_type_str);
-	g_free (allowed_bands_str);
-	g_free (pswd_flags);
-	g_free (pin_flags);
+DEFINE_ALLOWED_VAL_FUNC (nmc_property_ipv6_allowed_method, ipv6_valid_methods)
 
+/* 'dns' */
+static gboolean
+nmc_property_ipv6_set_dns (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	char **strv = NULL, **iter;
+	struct in6_addr ip6_addr;
+
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	strv = nmc_strsplit_set (val, " \t,", 0);
+	for (iter = strv; iter && *iter; iter++) {
+		if (inet_pton (AF_INET6, g_strstrip (*iter), &ip6_addr) < 1) {
+			g_set_error (error, 1, 0, _("invalid IPv6 address '%s'"), *iter);
+			g_strfreev (strv);
+			return FALSE;
+		}
+		nm_setting_ip6_config_add_dns (NM_SETTING_IP6_CONFIG (setting), &ip6_addr);
+	}
+	g_strfreev (strv);
 	return TRUE;
 }
 
-gboolean
-setting_cdma_details (NMSettingCdma *s_cdma, NmCli *nmc)
+static gboolean
+_validate_and_remove_ipv6_dns (NMSettingIP6Config *setting,
+                               const char *dns,
+                               GError **error)
 {
-	char *pswd_flags;
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+	struct in6_addr ip6_addr;
+	gboolean ret;
 
-	g_return_val_if_fail (NM_IS_SETTING_CDMA (s_cdma), FALSE);
+	if (inet_pton (AF_INET6, dns, &ip6_addr) < 1) {
+		g_set_error (error, 1, 0, _("invalid IPv6 address '%s'"), dns);
+		return FALSE;
+	}
 
-	nmc->allowed_fields = nmc_fields_setting_cdma;
-	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_CDMA_ALL, nmc->allowed_fields, NULL);
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-	print_fields (nmc->print_fields, nmc->allowed_fields);  /* Print field names */
+	ret = nm_setting_ip6_config_remove_dns_by_value (setting, &ip6_addr);
+	if (!ret)
+		g_set_error (error, 1, 0, _("the property doesn't contain DNS server '%s'"), dns);
+	return ret;
+}
+DEFINE_REMOVER_INDEX_OR_VALUE (nmc_property_ipv6_remove_dns,
+                               NM_SETTING_IP6_CONFIG,
+                               nm_setting_ip6_config_get_num_dns,
+                               nm_setting_ip6_config_remove_dns,
+                               _validate_and_remove_ipv6_dns)
+
+static const char *
+nmc_property_ipv6_describe_dns (NMSetting *setting, const char *prop)
+{
+	return _("Enter a list of IPv6 addresses of DNS servers.  If the IPv6 "
+	         "configuration method is 'auto' these DNS servers are appended "
+	         "to those (if any) returned by automatic configuration.  DNS "
+	         "servers cannot be used with the 'shared' or 'link-local' IPv6 "
+	         "configuration methods, as there is no upstream network. In "
+	         "all other IPv6 configuration methods, these DNS "
+	         "servers are used as the only DNS servers for this connection.\n\n"
+	         "Example: 2607:f0d0:1002:51::4, 2607:f0d0:1002:51::1\n");
+}
 
-	pswd_flags = secret_flags_to_string (nm_setting_cdma_get_password_flags (s_cdma));
+/* 'dns-search' */
+static gboolean
+nmc_property_ipv6_set_dns_search (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	char **strv = NULL;
+	guint i = 0;
 
-	nmc->allowed_fields[0].value = NM_SETTING_CDMA_SETTING_NAME;
-	nmc->allowed_fields[1].value = nm_setting_cdma_get_number (s_cdma);
-	nmc->allowed_fields[2].value = nm_setting_cdma_get_username (s_cdma);
-	nmc->allowed_fields[3].value = nm_setting_cdma_get_password (s_cdma);
-	nmc->allowed_fields[4].value = pswd_flags;
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+	strv = nmc_strsplit_set (val, " \t,", 0);
+	if (!verify_string_list (strv, prop, nmc_util_is_domain, error)) {
+		g_strfreev (strv);
+		return FALSE;
+	}
 
-	g_free (pswd_flags);
+	while (strv && strv[i])
+		nm_setting_ip6_config_add_dns_search (NM_SETTING_IP6_CONFIG (setting), strv[i++]);
+	g_strfreev (strv);
 
 	return TRUE;
 }
 
-gboolean
-setting_bluetooth_details (NMSettingBluetooth *s_bluetooth, NmCli *nmc)
+static gboolean
+_validate_and_remove_ipv6_dns_search (NMSettingIP6Config *setting,
+                                      const char *dns_search,
+                                      GError **error)
 {
-	const GByteArray *bdaddr;
-	char *bdaddr_str = NULL;
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+	gboolean ret;
+
+	ret = nm_setting_ip6_config_remove_dns_search_by_value (setting, dns_search);
+	if (!ret)
+		g_set_error (error, 1, 0,
+		             _("the property doesn't contain DNS search domain '%s'"),
+		             dns_search);
+	return ret;
+}
+DEFINE_REMOVER_INDEX_OR_VALUE (nmc_property_ipv6_remove_dns_search,
+                               NM_SETTING_IP6_CONFIG,
+                               nm_setting_ip6_config_get_num_dns_searches,
+                               nm_setting_ip6_config_remove_dns_search,
+                               _validate_and_remove_ipv6_dns_search)
+
+/* 'addresses' */
+static NMIP6Address *
+_parse_ipv6_address (const char *address, GError **error)
+{
+	char *value = g_strstrip (g_strdup (address));
+	char **addrv;
+	NMIP6Address *ip6addr;
+
+	addrv = nmc_strsplit_set (g_strstrip (value), " \t", 0);
+	if (addrv[0] == NULL || g_strv_length (addrv) > 2) {
+		g_set_error (error, 1, 0, _("'%s' is not valid (use ip[/prefix] [gateway])"),
+		             address);
+		g_free (value);
+		g_strfreev (addrv);
+		return NULL;
+	}
+	ip6addr = nmc_parse_and_build_ip6_address (addrv[0], addrv[1], error);
+	g_free (value);
+	g_strfreev (addrv);
+	return ip6addr;
+}
 
-	g_return_val_if_fail (NM_IS_SETTING_BLUETOOTH (s_bluetooth), FALSE);
+static gboolean
+nmc_property_ipv6_set_addresses (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	char **strv = NULL, **iter;
+	NMIP6Address *ip6addr;
+
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	strv = nmc_strsplit_set (val, ",", 0);
+	for (iter = strv; iter && *iter; iter++) {
+		ip6addr = _parse_ipv6_address (*iter, error);
+		if (!ip6addr) {
+			g_strfreev (strv);
+			return FALSE;
+		}
+		nm_setting_ip6_config_add_address (NM_SETTING_IP6_CONFIG (setting), ip6addr);
+		nm_ip6_address_unref (ip6addr);
+	}
+	g_strfreev (strv);
+	return TRUE;
+}
 
-	nmc->allowed_fields = nmc_fields_setting_bluetooth;
-	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_BLUETOOTH_ALL, nmc->allowed_fields, NULL);
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-	print_fields (nmc->print_fields, nmc->allowed_fields);  /* Print field names */
+static gboolean
+_validate_and_remove_ipv6_address (NMSettingIP6Config *setting,
+                                   const char *address,
+                                   GError **error)
+{
+	NMIP6Address *ip6addr;
+	gboolean ret;
 
-	bdaddr = nm_setting_bluetooth_get_bdaddr (s_bluetooth);
-	if (bdaddr)
-		bdaddr_str = nm_utils_hwaddr_ntoa (bdaddr->data, ARPHRD_ETHER);
+	ip6addr = _parse_ipv6_address (address, error);
+	if (!ip6addr)
+		return FALSE;
 
-	nmc->allowed_fields[0].value = NM_SETTING_BLUETOOTH_SETTING_NAME;
-	nmc->allowed_fields[1].value = bdaddr_str;
-	nmc->allowed_fields[2].value = nm_setting_bluetooth_get_connection_type (s_bluetooth);
+	ret = nm_setting_ip6_config_remove_address_by_value (setting, ip6addr);
+	if (!ret)
+		g_set_error (error, 1, 0, _("the property doesn't contain IP address '%s'"), address);
+	nm_ip6_address_unref (ip6addr);
+	return ret;
+}
+DEFINE_REMOVER_INDEX_OR_VALUE (nmc_property_ipv6_remove_addresses,
+                               NM_SETTING_IP6_CONFIG,
+                               nm_setting_ip6_config_get_num_addresses,
+                               nm_setting_ip6_config_remove_address,
+                               _validate_and_remove_ipv6_address)
+
+static const char *
+nmc_property_ipv6_describe_addresses (NMSetting *setting, const char *prop)
+{
+	return _("Enter a list of IPv6 addresses formatted as:\n"
+	         "  ip[/prefix] [gateway], ip[/prefix] [gateway],...\n"
+	         "Missing prefix is regarded as prefix of 128.\n\n"
+	         "Example: 2607:f0d0:1002:51::4/64 2607:f0d0:1002:51::1, 1050:0:0:0:5:600:300c:326b\n");
+}
 
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+/* 'routes' */
+static NMIP6Route *
+_parse_ipv6_route (const char *route, GError **error)
+{
+	char *value = g_strdup (route);
+	char **routev;
+	guint len;
+	NMIP6Route *ip6route = NULL;
+
+	routev = nmc_strsplit_set (g_strstrip (value), " \t", 0);
+	len = g_strv_length (routev);
+	if (len < 1 || len > 3) {
+		g_set_error (error, 1, 0, _("'%s' is not valid (the format is: ip[/prefix] [next-hop] [metric])"),
+		             route);
+		goto finish;
+	}
+	ip6route = nmc_parse_and_build_ip6_route (routev[0], routev[1], len >= 2 ? routev[2] : NULL, error);
 
-	g_free (bdaddr_str);
+finish:
+	g_free (value);
+	g_strfreev (routev);
+	return ip6route;
+}
 
+static gboolean
+nmc_property_ipv6_set_routes (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	char **strv = NULL, **iter;
+	NMIP6Route *ip6route;
+
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	strv = nmc_strsplit_set (val, ",", 0);
+	for (iter = strv; iter && *iter; iter++) {
+		ip6route = _parse_ipv6_route (*iter, error);
+		if (!ip6route) {
+			g_strfreev (strv);
+			return FALSE;
+		}
+		nm_setting_ip6_config_add_route (NM_SETTING_IP6_CONFIG (setting), ip6route);
+		nm_ip6_route_unref (ip6route);
+	}
+	g_strfreev (strv);
 	return TRUE;
 }
 
-gboolean
-setting_olpc_mesh_details (NMSettingOlpcMesh *s_olpc_mesh, NmCli *nmc)
+static gboolean
+_validate_and_remove_ipv6_route (NMSettingIP6Config *setting,
+                                 const char *route,
+                                 GError **error)
 {
-	const GByteArray *ssid, *dhcp_anycast;
-	char *channel_str, *ssid_str = NULL, *dhcp_anycast_str = NULL;
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+	NMIP6Route *ip6route;
+	gboolean ret;
 
-	g_return_val_if_fail (NM_IS_SETTING_OLPC_MESH (s_olpc_mesh), FALSE);
+	ip6route = _parse_ipv6_route (route, error);
+	if (!ip6route)
+		return FALSE;
+
+	ret = nm_setting_ip6_config_remove_route_by_value (setting, ip6route);
+	if (!ret)
+		g_set_error (error, 1, 0, _("the property doesn't contain route '%s'"), route);
+	nm_ip6_route_unref (ip6route);
+	return ret;
+}
+DEFINE_REMOVER_INDEX_OR_VALUE (nmc_property_ipv6_remove_routes,
+                               NM_SETTING_IP6_CONFIG,
+                               nm_setting_ip6_config_get_num_routes,
+                               nm_setting_ip6_config_remove_route,
+                               _validate_and_remove_ipv6_route)
+
+static const char *
+nmc_property_ipv6_describe_routes (NMSetting *setting, const char *prop)
+{
+	return _("Enter a list of IPv6 routes formatted as:\n"
+	         "  ip[/prefix] [next-hop] [metric],...\n\n"
+	         "Missing prefix is regarded as a prefix of 128.\n"
+	         "Missing next-hop is regarded as \"::\".\n"
+	         "Missing metric or 0 means a default metric (NM/kernel will set a default value).\n\n"
+	         "Examples: 2001:db8:beef:2::/64 2001:db8:beef::2, 2001:db8:beef:3::/64 2001:db8:beef::3 2\n"
+	         "          abbe::/64 55\n");
+}
 
-	nmc->allowed_fields = nmc_fields_setting_olpc_mesh;
-	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_OLPC_MESH_ALL, nmc->allowed_fields, NULL);
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-	print_fields (nmc->print_fields, nmc->allowed_fields);  /* Print field names */
+static gboolean
+nmc_property_ipv6_set_ip6_privacy (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	unsigned long val_int;
 
-	ssid = nm_setting_olpc_mesh_get_ssid (s_olpc_mesh);
-	if (ssid)
-		ssid_str = ssid_to_printable ((const char *) ssid->data, ssid->len);
-	channel_str = g_strdup_printf ("%d", nm_setting_olpc_mesh_get_channel (s_olpc_mesh));
-	dhcp_anycast = nm_setting_olpc_mesh_get_dhcp_anycast_address (s_olpc_mesh);
-	if (dhcp_anycast)
-		dhcp_anycast_str = nm_utils_hwaddr_ntoa (dhcp_anycast->data, ARPHRD_ETHER);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	if (!nmc_string_to_uint (val, FALSE, 0, 0, &val_int)) {
+		g_set_error (error, 1, 0, _("'%s' is not a number"), val);
+		return FALSE;
+	}
+
+	if (   val_int != NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED
+	    && val_int != NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR
+	    && val_int != NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR) {
+		g_set_error (error, 1, 0, _("'%s' is not valid; use 0, 1, or 2"), val);
+		return FALSE;
+	}
+
+	g_object_set (setting, prop, val_int, NULL);
+	return TRUE;
+}
+
+/* --- NM_SETTING_OLPC_MESH_SETTING_NAME property setter functions --- */
+static gboolean
+nmc_property_olpc_set_channel (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	unsigned long chan_int;
+
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	if (!nmc_string_to_uint (val, TRUE, 1, 13, &chan_int)) {
+		g_set_error (error, 1, 0, _("'%s' is not a valid channel; use <1-13>"), val);
+		return FALSE;
+	}
+	g_object_set (setting, prop, chan_int, NULL);
+	return TRUE;
+}
+
+
+/* --- NM_SETTING_SERIAL_SETTING_NAME property setter functions --- */
+static gboolean
+nmc_property_serial_set_parity (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	char parity;
+
+	if (val[0] == 'E' || val[0] == 'e')
+		parity = 'E';
+	else if (val[0] == 'O' || val[0] == 'o')
+		parity = 'o';
+	else if (val[0] == 'N' || val[0] == 'n')
+		parity = 'n';
+	else {
+		g_set_error (error, 1, 0, _("'%s' is not valid; use [e, o, n]"), val);
+		return FALSE;
+	}
+
+	g_object_set (setting, prop, parity, NULL);
+	return TRUE;
+}
+
+/* --- NM_SETTING_TEAM_SETTING_NAME property functions --- */
+/* --- NM_SETTING_TEAM_PORT_SETTING_NAME property functions --- */
+static gboolean
+nmc_property_team_set_config (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	char *json = NULL;
+
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	if (!nmc_team_check_config (val, &json, error)) {
+		return FALSE;
+	}
+	g_object_set (setting, prop, json, NULL);
+	g_free (json);
+	return TRUE;
+}
+
+static const char *
+nmc_property_team_describe_config (NMSetting *setting, const char *prop)
+{
+	return _("nmcli can accepts both direct JSON configuration data and a file name containing "
+	         "the configuration. In the latter case the file is read and the contents is put "
+	         "into this property.\n\n"
+	         "Examples: set team.config "
+	         "{ \"device\": \"team0\", \"runner\": {\"name\": \"roundrobin\"}, \"ports\": {\"eth1\": {}, \"eth2\": {}} }\n"
+	         "          set team.config /etc/my-team.conf\n");
+}
+
+/* --- NM_SETTING_VLAN_SETTING_NAME property setter functions --- */
+static gboolean
+nmc_property_vlan_set_prio_map (NMSetting *setting,
+                                const char *prop,
+                                const char *val,
+                                NMVlanPriorityMap map_type,
+                                GError **error)
+{
+	char **prio_map, **p;
+
+	prio_map = nmc_vlan_parse_priority_maps (val, map_type, error);
+	if (!prio_map)
+		return FALSE;
+
+	for (p = prio_map; p && *p; p++)
+		nm_setting_vlan_add_priority_str (NM_SETTING_VLAN (setting), map_type, *p);
+
+	g_strfreev (prio_map);
+	return TRUE;
+}
+
+static gboolean
+nmc_property_vlan_remove_prio_map (NMSetting *setting,
+                                   const char *prop,
+                                   guint32 idx,
+                                   NMVlanPriorityMap map_type,
+                                   GError **error)
+{
+	guint32 num;
+
+	num = nm_setting_vlan_get_num_priorities (NM_SETTING_VLAN (setting), map_type);
+	if (num == 0) {
+		g_set_error_literal (error, 1, 0, _("no priority to remove"));
+		return FALSE;
+	}
+	if (idx >= num) {
+		g_set_error (error, 1, 0, _("index '%d' is not in the range of <0-%d>"),
+		             idx, num - 1);
+		return FALSE;
+	}
+
+	nm_setting_vlan_remove_priority (NM_SETTING_VLAN (setting), map_type, idx);
+	return TRUE;
+}
+
+static gboolean
+nmc_property_vlan_set_ingress_priority_map (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	return nmc_property_vlan_set_prio_map (setting, prop, val, NM_VLAN_INGRESS_MAP, error);
+}
+
+static gboolean
+nmc_property_vlan_set_egress_priority_map (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	return nmc_property_vlan_set_prio_map (setting, prop, val, NM_VLAN_EGRESS_MAP, error);
+}
+
+static gboolean
+nmc_property_vlan_remove_priority_map (NMSetting *setting,
+                                       const char *prop,
+                                       const char *value,
+                                       guint32 idx,
+                                       NMVlanPriorityMap map,
+                                       GError **error)
+{
+	/* If value != NULL, remove by value */
+	if (value) {
+		gboolean ret;
+		char **prio_map;
+		char *val = g_strdup (value);
+
+		prio_map = nmc_vlan_parse_priority_maps (val, map, error);
+		if (!prio_map)
+			return FALSE;
+		if (prio_map[1])
+			printf (_("Warning: only one mapping at a time is supported; taking the first one (%s)\n"),
+			        prio_map[0]);
+		ret = nm_setting_vlan_remove_priority_str_by_value (NM_SETTING_VLAN (setting),
+		                                                    map,
+		                                                    prio_map[0]);
+
+		if (!ret)
+			g_set_error (error, 1, 0, _("the property doesn't contain mapping '%s'"), prio_map[0]);
+		g_free (val);
+		g_strfreev (prio_map);
+		return ret;
+	}
+
+	/* Else remove by index */
+	return nmc_property_vlan_remove_prio_map (setting, prop, idx, map, error);
+}
+
+static gboolean
+nmc_property_vlan_remove_ingress_priority_map (NMSetting *setting,
+                                               const char *prop,
+                                               const char *value,
+                                               guint32 idx,
+                                               GError **error)
+{
+	return nmc_property_vlan_remove_priority_map (setting,
+                                                      prop,
+                                                      value,
+                                                      idx,
+                                                      NM_VLAN_INGRESS_MAP,
+                                                      error);
+}
+
+static gboolean
+nmc_property_vlan_remove_egress_priority_map (NMSetting *setting,
+                                              const char *prop,
+                                              const char *value,
+                                              guint32 idx,
+                                              GError **error)
+{
+	return nmc_property_vlan_remove_priority_map (setting,
+                                                      prop,
+                                                      value,
+                                                      idx,
+                                                      NM_VLAN_EGRESS_MAP,
+                                                      error);
+}
+
+/* --- NM_SETTING_VPN_SETTING_NAME property setter functions --- */
+/* 'data' */
+DEFINE_SETTER_OPTIONS (nmc_property_vpn_set_data,
+                       NM_SETTING_VPN,
+                       NMSettingVPN,
+                       nm_setting_vpn_add_data_item,
+                       NULL,
+                       NULL)
+DEFINE_REMOVER_OPTION (nmc_property_vpn_remove_option_data,
+                       NM_SETTING_VPN,
+                       nm_setting_vpn_remove_data_item)
+
+/* 'secrets' */
+DEFINE_SETTER_OPTIONS (nmc_property_vpn_set_secrets,
+                       NM_SETTING_VPN,
+                       NMSettingVPN,
+                       nm_setting_vpn_add_secret,
+                       NULL,
+                       NULL)
+DEFINE_REMOVER_OPTION (nmc_property_vpn_remove_option_secret,
+                       NM_SETTING_VPN,
+                       nm_setting_vpn_remove_secret)
+
+/* --- NM_SETTING_WIMAX_SETTING_NAME property setter functions --- */
+/* No specific functions */
+
+/* --- NM_SETTING_WIRED_SETTING_NAME property setter functions --- */
+#if 0
+/*
+ * Do not allow setting 'port' and 'duplex' for now. They are not implemented in
+ * NM core, nor in ifcfg-rh plugin. Enable this when it gets done.
+ */
+/* 'port' */
+static const char *wired_valid_ports[] = { "tp", "aui", "bnc", "mii", NULL };
+
+static gboolean
+nmc_property_wired_set_port (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	return check_and_set_string (setting, prop, val, wired_valid_ports, error);
+}
+
+DEFINE_ALLOWED_VAL_FUNC (nmc_property_wired_allowed_port, wired_valid_ports)
+
+/* 'duplex' */
+static const char *wired_valid_duplexes[] = { "half", "full", NULL };
+
+static gboolean
+nmc_property_wired_set_duplex (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	return check_and_set_string (setting, prop, val, wired_valid_duplexes, error);
+}
+
+DEFINE_ALLOWED_VAL_FUNC (nmc_property_wired_allowed_duplex, wired_valid_duplexes)
+#endif
+
+/* 'mac-address-blacklist' */
+DEFINE_SETTER_MAC_BLACKLIST (nmc_property_wired_set_mac_address_blacklist,
+                             NM_SETTING_WIRED,
+                             nm_setting_wired_add_mac_blacklist_item)
+
+static gboolean
+_validate_and_remove_wired_mac_blacklist_item (NMSettingWired *setting,
+                                              const char *mac,
+                                              GError **error)
+{
+	gboolean ret;
+	guint8 buf[32];
+
+	if (!nm_utils_hwaddr_aton (mac, ARPHRD_ETHER, buf)) {
+		g_set_error (error, 1, 0, _("'%s' is not a valid MAC address"), mac);
+                return FALSE;
+	}
+
+	ret = nm_setting_wired_remove_mac_blacklist_item_by_value (setting, mac);
+	if (!ret)
+		g_set_error (error, 1, 0, _("the property doesn't contain MAC address '%s'"), mac);
+	return ret;
+}
+DEFINE_REMOVER_INDEX_OR_VALUE (nmc_property_wired_remove_mac_address_blacklist,
+                               NM_SETTING_WIRED,
+                               nm_setting_wired_get_num_mac_blacklist_items,
+                               nm_setting_wired_remove_mac_blacklist_item,
+                               _validate_and_remove_wired_mac_blacklist_item)
+
+/* 's390-subchannels' */
+static gboolean
+nmc_property_wired_set_s390_subchannels (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	char **strv = NULL, **iter;
+	GPtrArray *s390_subchannels;
+
+	//FIXME: both libnm-util and ifcfg-rh also allow two strings (3rd is optional)
+	strv = nmc_strsplit_set (val, " ,\t", 0);
+	if (g_strv_length (strv) != 3) {
+		g_set_error (error, 1, 0, _("'%s' is not valid; 3 strings should be provided"),
+		             val);
+		g_strfreev (strv);
+		return FALSE;
+	}
+
+	s390_subchannels = g_ptr_array_sized_new (3);
+	for (iter = strv; iter && *iter; iter++)
+		g_ptr_array_add (s390_subchannels, *iter);
+
+	g_object_set (setting, prop, s390_subchannels, NULL);
+	g_strfreev (strv);
+	g_ptr_array_free (s390_subchannels, TRUE);
+	return TRUE;
+}
+
+static const char *
+nmc_property_wired_describe_s390_subchannels (NMSetting *setting, const char *prop)
+{
+	return _("Enter a list of three channels (comma or space separated).\n\n"
+	         "Example: 0.0.0e20 0.0.0e21 0.0.0e22\n");
+}
+
+/* 's390-nettype' */
+static const char *wired_valid_s390_nettypes[] = { "qeth", "lcs", "ctc", NULL };
+
+static gboolean
+nmc_property_wired_set_s390_nettype (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	return check_and_set_string (setting, prop, val, wired_valid_s390_nettypes, error);
+}
+
+DEFINE_ALLOWED_VAL_FUNC (nmc_property_wired_allowed_s390_nettype, wired_valid_s390_nettypes)
+
+/* 's390-options' */
+DEFINE_SETTER_OPTIONS (nmc_property_wired_set_s390_options,
+                       NM_SETTING_WIRED,
+                       NMSettingWired,
+                       nm_setting_wired_add_s390_option,
+                       nm_setting_wired_get_valid_s390_options,
+                       NULL)
+DEFINE_REMOVER_OPTION (nmc_property_wired_remove_option_s390_options,
+                       NM_SETTING_WIRED,
+                       nm_setting_wired_remove_s390_option)
+
+static const char *
+nmc_property_wired_allowed_s390_options (NMSetting *setting, const char *prop)
+{
+	const char **valid_options;
+	static char *allowed_vals = NULL;
+
+	if (G_UNLIKELY (allowed_vals == NULL)) {
+		valid_options = nm_setting_wired_get_valid_s390_options (NM_SETTING_WIRED (setting));
+		allowed_vals = g_strjoinv (", ", (char **) valid_options);
+	}
+	return allowed_vals;
+}
 
-	nmc->allowed_fields[0].value = NM_SETTING_OLPC_MESH_SETTING_NAME;
-	nmc->allowed_fields[1].value = ssid_str;
-	nmc->allowed_fields[2].value = channel_str;
-	nmc->allowed_fields[3].value = dhcp_anycast_str;
+static const char *
+nmc_property_wired_describe_s390_options (NMSetting *setting, const char *prop)
+{
+	static char *desc = NULL;
+	const char **valid_options;
+	char *options_str;
+
+	if (G_UNLIKELY (desc == NULL)) {
+		valid_options = nm_setting_wired_get_valid_s390_options (NM_SETTING_WIRED (setting));
+		options_str = g_strjoinv (", ", (char **) valid_options);
+
+		desc = g_strdup_printf (_("Enter a list of S/390 options formatted as:\n"
+		                          "  option = <value>, option = <value>,...\n"
+		                          "Valid options are: %s\n"),
+		                        options_str);
+		g_free (options_str);
+	}
+	return desc;
+}
+
+/* --- NM_SETTING_WIRELESS_SETTING_NAME property setter functions --- */
+/* 'mode' */
+static const char *wifi_valid_modes[] = {
+	NM_SETTING_WIRELESS_MODE_INFRA,
+	NM_SETTING_WIRELESS_MODE_ADHOC,
+	NM_SETTING_WIRELESS_MODE_AP,
+	NULL
+};
+
+static gboolean
+nmc_property_wifi_set_mode (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	return check_and_set_string (setting, prop, val, wifi_valid_modes, error);
+}
+
+DEFINE_ALLOWED_VAL_FUNC (nmc_property_wifi_allowed_mode, wifi_valid_modes)
+
+/* 'band' */
+static const char *wifi_valid_bands[] = { "a", "bg", NULL };
+
+static gboolean
+nmc_property_wifi_set_band (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	return check_and_set_string (setting, prop, val, wifi_valid_bands, error);
+}
+
+DEFINE_ALLOWED_VAL_FUNC (nmc_property_wifi_allowed_band, wifi_valid_bands)
+
+/* 'channel' */
+static gboolean
+nmc_property_wifi_set_channel (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	unsigned long chan_int;
+
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	if (!nmc_string_to_uint (val, FALSE, 0, 0, &chan_int)) {
+		g_set_error (error, 1, 0, _("'%s' is not a valid channel"), val);
+		return FALSE;
+	}
+
+	if (   !nm_utils_wifi_is_channel_valid (chan_int, "a")
+	    && !nm_utils_wifi_is_channel_valid (chan_int, "bg")) {
+		g_set_error (error, 1, 0, _("'%ld' is not a valid channel"), chan_int);
+		return FALSE;
+	}
+
+	g_object_set (setting, prop, chan_int, NULL);
+	return TRUE;
+}
+
+/* 'mac-address-blacklist' */
+DEFINE_SETTER_MAC_BLACKLIST (nmc_property_wireless_set_mac_address_blacklist,
+                             NM_SETTING_WIRELESS,
+                             nm_setting_wireless_add_mac_blacklist_item)
+
+static gboolean
+_validate_and_remove_wifi_mac_blacklist_item (NMSettingWireless *setting,
+                                              const char *mac,
+                                              GError **error)
+{
+	gboolean ret;
+	guint8 buf[32];
+
+	if (!nm_utils_hwaddr_aton (mac, ARPHRD_ETHER, buf)) {
+		g_set_error (error, 1, 0, _("'%s' is not a valid MAC address"), mac);
+                return FALSE;
+	}
+
+	ret = nm_setting_wireless_remove_mac_blacklist_item_by_value (setting, mac);
+	if (!ret)
+		g_set_error (error, 1, 0, _("the property doesn't contain MAC address '%s'"), mac);
+	return ret;
+}
+DEFINE_REMOVER_INDEX_OR_VALUE (nmc_property_wireless_remove_mac_address_blacklist,
+                               NM_SETTING_WIRELESS,
+                               nm_setting_wireless_get_num_mac_blacklist_items,
+                               nm_setting_wireless_remove_mac_blacklist_item,
+                               _validate_and_remove_wifi_mac_blacklist_item)
+
+/* --- NM_SETTING_WIRELESS_SECURITY_SETTING_NAME property setter functions --- */
+/* 'key-mgmt' */
+static const char *wifi_sec_valid_key_mgmts[] = { "none", "ieee8021x", "wpa-none", "wpa-psk", "wpa-eap", NULL };
+
+static gboolean
+nmc_property_wifi_sec_set_key_mgmt (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	return check_and_set_string (setting, prop, val, wifi_sec_valid_key_mgmts, error);
+}
+
+DEFINE_ALLOWED_VAL_FUNC (nmc_property_wifi_sec_allowed_key_mgmt, wifi_sec_valid_key_mgmts)
+
+/* 'auth-alg' */
+static const char *wifi_sec_valid_auth_algs[] = { "open", "shared", "leap", NULL };
+
+static gboolean
+nmc_property_wifi_sec_set_auth_alg (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	return check_and_set_string (setting, prop, val, wifi_sec_valid_auth_algs, error);
+}
+
+DEFINE_SETTER_STR_LIST_MULTI (check_and_add_wifi_sec_proto,
+                              NM_SETTING_WIRELESS_SECURITY,
+                              nm_setting_wireless_security_add_proto)
+DEFINE_ALLOWED_VAL_FUNC (nmc_property_wifi_sec_allowed_auth_alg, wifi_sec_valid_auth_algs)
+
+/* 'proto' */
+static const char *wifi_sec_valid_protos[] = { "wpa", "rsn", NULL };
+
+static gboolean
+nmc_property_wifi_sec_set_proto (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	return check_and_add_wifi_sec_proto (setting, prop, val, wifi_sec_valid_protos, error);
+}
+
+static gboolean
+_validate_and_remove_wifi_sec_proto (NMSettingWirelessSecurity *setting,
+                                     const char *proto,
+                                     GError **error)
+{
+	gboolean ret;
+	const char *valid;
+
+	valid = nmc_string_is_valid (proto, wifi_sec_valid_protos, error);
+	if (!valid)
+		return FALSE;
+
+	ret = nm_setting_wireless_security_remove_proto_by_value (setting, proto);
+	if (!ret)
+		g_set_error (error, 1, 0,
+		             _("the property doesn't contain protocol '%s'"), proto);
+	return ret;
+}
+DEFINE_REMOVER_INDEX_OR_VALUE (nmc_property_wifi_sec_remove_proto,
+                               NM_SETTING_WIRELESS_SECURITY,
+                               nm_setting_wireless_security_get_num_protos,
+                               nm_setting_wireless_security_remove_proto,
+                               _validate_and_remove_wifi_sec_proto)
+
+DEFINE_SETTER_STR_LIST_MULTI (check_and_add_wifi_sec_pairwise,
+                              NM_SETTING_WIRELESS_SECURITY,
+                              nm_setting_wireless_security_add_pairwise)
+DEFINE_ALLOWED_VAL_FUNC (nmc_property_wifi_sec_allowed_proto, wifi_sec_valid_protos)
+
+/* 'pairwise' */
+static const char *wifi_sec_valid_pairwises[] = { "tkip", "ccmp", NULL };
+
+static gboolean
+nmc_property_wifi_sec_set_pairwise (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	return check_and_add_wifi_sec_pairwise (setting, prop, val, wifi_sec_valid_pairwises, error);
+}
+
+static gboolean
+_validate_and_remove_wifi_sec_pairwise (NMSettingWirelessSecurity *setting,
+                                        const char *pairwise,
+                                        GError **error)
+{
+	gboolean ret;
+	const char *valid;
+
+	valid = nmc_string_is_valid (pairwise, wifi_sec_valid_pairwises, error);
+	if (!valid)
+		return FALSE;
+
+	ret = nm_setting_wireless_security_remove_pairwise_by_value (setting, pairwise);
+	if (!ret)
+		g_set_error (error, 1, 0,
+		             _("the property doesn't contain protocol '%s'"), pairwise);
+	return ret;
+}
+DEFINE_REMOVER_INDEX_OR_VALUE (nmc_property_wifi_sec_remove_pairwise,
+                               NM_SETTING_WIRELESS_SECURITY,
+                               nm_setting_wireless_security_get_num_pairwise,
+                               nm_setting_wireless_security_remove_pairwise,
+                               _validate_and_remove_wifi_sec_pairwise)
+
+DEFINE_SETTER_STR_LIST_MULTI (check_and_add_wifi_sec_group,
+                              NM_SETTING_WIRELESS_SECURITY,
+                              nm_setting_wireless_security_add_group)
+DEFINE_ALLOWED_VAL_FUNC (nmc_property_wifi_sec_allowed_pairwise, wifi_sec_valid_pairwises)
+
+/* 'group' */
+static const char *wifi_sec_valid_groups[] = { "wep40", "wep104", "tkip", "ccmp", NULL };
+
+static gboolean
+nmc_property_wifi_sec_set_group (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	return check_and_add_wifi_sec_group (setting, prop, val, wifi_sec_valid_groups, error);
+}
+
+static gboolean
+_validate_and_remove_wifi_sec_group (NMSettingWirelessSecurity *setting,
+                                     const char *group,
+                                     GError **error)
+{
+	gboolean ret;
+	const char *valid;
+
+	valid = nmc_string_is_valid (group, wifi_sec_valid_groups, error);
+	if (!valid)
+		return FALSE;
+
+	ret = nm_setting_wireless_security_remove_group_by_value (setting, group);
+	if (!ret)
+		g_set_error (error, 1, 0,
+		             _("the property doesn't contain protocol '%s'"), group);
+	return ret;
+}
+DEFINE_REMOVER_INDEX_OR_VALUE (nmc_property_wifi_sec_remove_group,
+                               NM_SETTING_WIRELESS_SECURITY,
+                               nm_setting_wireless_security_get_num_groups,
+                               nm_setting_wireless_security_remove_group,
+                               _validate_and_remove_wifi_sec_group)
+DEFINE_ALLOWED_VAL_FUNC (nmc_property_wifi_sec_allowed_group, wifi_sec_valid_groups)
+
+/* 'wep-key' */
+static gboolean
+nmc_property_wifi_set_wep_key (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	NMWepKeyType guessed_type = NM_WEP_KEY_TYPE_UNKNOWN;
+	NMWepKeyType type;
+	guint32 prev_idx, idx;
+
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	/* Get currently set type */
+	type = nm_setting_wireless_security_get_wep_key_type (NM_SETTING_WIRELESS_SECURITY (setting));
+
+	/* Guess key type */
+	if (nm_utils_wep_key_valid (val, NM_WEP_KEY_TYPE_KEY))
+		guessed_type = NM_WEP_KEY_TYPE_KEY;
+	else if (nm_utils_wep_key_valid (val, NM_WEP_KEY_TYPE_PASSPHRASE))
+		guessed_type = NM_WEP_KEY_TYPE_PASSPHRASE;
+
+	if (guessed_type == NM_WEP_KEY_TYPE_UNKNOWN) {
+		g_set_error (error, 1, 0, _("'%s' is not valid"), val);
+		return FALSE;
+	}
+
+	if (type != NM_WEP_KEY_TYPE_UNKNOWN && type != guessed_type) {
+		if (nm_utils_wep_key_valid (val, type))
+			guessed_type = type;
+		else {
+			g_set_error (error, 1, 0,
+			             _("'%s' not compatible with %s '%s', please change the key or set the right %s first."),
+			             val, NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, wep_key_type_to_string (type),
+			             NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE);
+			return FALSE;
+		}
+	}
+	prev_idx = nm_setting_wireless_security_get_wep_tx_keyidx (NM_SETTING_WIRELESS_SECURITY (setting));
+	idx = prop[strlen (prop) - 1] - '0';
+	printf (_("WEP key is guessed to be of '%s'\n"), wep_key_type_to_string (guessed_type));
+	if (idx != prev_idx)
+		printf (_("WEP key index set to '%d'\n"), idx);
+
+	g_object_set (setting, prop, val, NULL);
+	g_object_set (setting, NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, guessed_type, NULL);
+	if (idx != prev_idx)
+		g_object_set (setting, NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX, idx, NULL);
+	return TRUE;
+}
 
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+/* 'wep-key-type' */
+static gboolean
+nmc_property_wifi_set_wep_key_type (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	unsigned long  type_int;
+	const char *valid_wep_types[] = { "unknown", "key", "passphrase", NULL };
+	const char *type_str = NULL;
+	const char *key0, *key1,* key2, *key3;
+	NMWepKeyType type = NM_WEP_KEY_TYPE_UNKNOWN;
+
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	if (!nmc_string_to_uint (val, TRUE, 0, 2, &type_int)) {
+		if (!(type_str = nmc_string_is_valid (val, valid_wep_types, NULL))) {
+			g_set_error (error, 1, 0, _("'%s' not among [0 (unknown), 1 (key), 2 (passphrase)]"), val);
+			return FALSE;
+		}
+		if (type_str == valid_wep_types[1])
+			type = NM_WEP_KEY_TYPE_KEY;
+		else if (type_str == valid_wep_types[2])
+			type = NM_WEP_KEY_TYPE_PASSPHRASE;
+	} else
+		type = (NMWepKeyType) type_int;
+
+	/* Check type compatibility with set keys */
+	key0 = nm_setting_wireless_security_get_wep_key (NM_SETTING_WIRELESS_SECURITY (setting), 0);
+	key1 = nm_setting_wireless_security_get_wep_key (NM_SETTING_WIRELESS_SECURITY (setting), 1);
+	key2 = nm_setting_wireless_security_get_wep_key (NM_SETTING_WIRELESS_SECURITY (setting), 2);
+	key3 = nm_setting_wireless_security_get_wep_key (NM_SETTING_WIRELESS_SECURITY (setting), 3);
+	if (key0 && !nm_utils_wep_key_valid (key0, type))
+		printf (_("Warning: '%s' is not compatible with '%s' type, please change or delete the key.\n"),
+			NM_SETTING_WIRELESS_SECURITY_WEP_KEY0, wep_key_type_to_string (type));
+	if (key1 && !nm_utils_wep_key_valid (key1, type))
+		printf (_("Warning: '%s' is not compatible with '%s' type, please change or delete the key.\n"),
+			NM_SETTING_WIRELESS_SECURITY_WEP_KEY1, wep_key_type_to_string (type));
+	if (key2 && !nm_utils_wep_key_valid (key2, type))
+		printf (_("Warning: '%s' is not compatible with '%s' type, please change or delete the key.\n"),
+			NM_SETTING_WIRELESS_SECURITY_WEP_KEY2, wep_key_type_to_string (type));
+	if (key3 && !nm_utils_wep_key_valid (key3, type))
+		printf (_("Warning: '%s' is not compatible with '%s' type, please change or delete the key.\n"),
+			NM_SETTING_WIRELESS_SECURITY_WEP_KEY3, wep_key_type_to_string (type));
+
+	g_object_set (setting, prop, type, NULL);
+	return TRUE;
+}
+
+static const char *
+nmc_property_wifi_describe_wep_key_type (NMSetting *setting, const char *prop)
+{
+	static char *desc = NULL;
+
+	if (G_UNLIKELY (desc == NULL)) {
+		desc = g_strdup_printf (_("Enter the type of WEP keys. The accepted values are: "
+		                          "0 or unknown, 1 or key, and 2 or passphrase.\n"));
+	}
+	return desc;
+}
+
+/* 'psk' */
+static gboolean
+nmc_property_wifi_set_psk (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	if (!nm_utils_wpa_psk_valid (val)) {
+		g_set_error (error, 1, 0, _("'%s' is not a valid PSK"), val);
+		return FALSE;
+	}
+	g_object_set (setting, prop, val, NULL);
+	return TRUE;
+}
+
+#define DCB_ALL_FLAGS (NM_SETTING_DCB_FLAG_ENABLE | NM_SETTING_DCB_FLAG_ADVERTISE | NM_SETTING_DCB_FLAG_WILLING)
+
+/* DCB stuff */
+static gboolean
+nmc_property_dcb_set_flags (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	char **strv = NULL, **iter;
+	NMSettingDcbFlags flags = NM_SETTING_DCB_FLAG_NONE;
+	long int t;
+
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	/* Check for overall hex numeric value */
+	if (nmc_string_to_int_base (val, 0, TRUE, 0, DCB_ALL_FLAGS, &t))
+		flags = (guint) t;
+	else {
+		/* Check for individual flag numbers */
+		strv = nmc_strsplit_set (val, " \t,", 0);
+		for (iter = strv; iter && *iter; iter++) {
+			if (!nmc_string_to_int_base (*iter, 0, TRUE, 0, DCB_ALL_FLAGS, &t))
+				t = -1;
+
+			if (   g_ascii_strcasecmp (*iter, "enable") == 0
+			    || g_ascii_strcasecmp (*iter, "enabled") == 0
+			    || t == NM_SETTING_DCB_FLAG_ENABLE)
+				flags |= NM_SETTING_DCB_FLAG_ENABLE;
+			else if (   g_ascii_strcasecmp (*iter, "advertise") == 0
+				 || t == NM_SETTING_DCB_FLAG_ADVERTISE)
+				flags |= NM_SETTING_DCB_FLAG_ADVERTISE;
+			else if (   g_ascii_strcasecmp (*iter, "willing") == 0
+				 || t == NM_SETTING_DCB_FLAG_WILLING)
+				flags |= NM_SETTING_DCB_FLAG_WILLING;
+			else if (   g_ascii_strcasecmp (*iter, "disable") == 0
+				 || g_ascii_strcasecmp (*iter, "disabled") == 0
+				 || t == 0) {
+				/* pass */
+			} else {
+				g_set_error (error, 1, 0, _("'%s' is not a valid DCB flag"), *iter);
+				return FALSE;
+			}
+		}
+		g_strfreev (strv);
+	}
+
+	/* Validate the number according to the property spec */
+	if (!validate_uint (setting, prop, (guint) flags, error))
+		return FALSE;
+
+	g_object_set (setting, prop, (guint) flags, NULL);
+	return TRUE;
+}
+
+static gboolean
+nmc_property_dcb_set_priority (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	long int priority = 0;
+
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	if (!nmc_string_to_int (val, FALSE, -1, 7, &priority)) {
+		g_set_error (error, 1, 0, _("'%s' is not a DCB app priority"), val);
+		return FALSE;
+	}
+
+	/* Validate the number according to the property spec */
+	if (!validate_int (setting, prop, (gint) priority, error))
+		return FALSE;
+
+	g_object_set (setting, prop, (gint) priority, NULL);
+	return TRUE;
+}
+
+static gboolean
+dcb_parse_uint_array (const char *val,
+                      guint max,
+                      guint other,
+                      guint *out_array,
+                      GError **error)
+{
+	char **items, **iter;
+	guint i = 0;
+
+	g_return_val_if_fail (out_array != NULL, FALSE);
+
+	items = g_strsplit_set (val, ",", -1);
+	if (g_strv_length (items) != 8) {
+		g_set_error_literal (error, 1, 0, _("must contain 8 comma-separated numbers"));
+		goto error;
+	}
 
-	g_free (ssid_str);
-	g_free (channel_str);
-	g_free (dhcp_anycast_str);
+	for (iter = items; iter && *iter; iter++) {
+		long int num = 0;
+		gboolean success;
+
+		*iter = g_strstrip (*iter);
+		success = nmc_string_to_int_base (*iter, 10, TRUE, 0, other ? other : max, &num);
+
+		/* If number is greater than 'max' it must equal 'other' */
+		if (success && other && (num > max) && (num != other))
+			success = FALSE;
+
+		if (!success) {
+			if (other) {
+				g_set_error (error, 1, 0, _("'%s' not a number between 0 and %u (inclusive) or %u"),
+					     *iter, max, other);
+			} else {
+				g_set_error (error, 1, 0, _("'%s' not a number between 0 and %u (inclusive)"),
+					     *iter, max);
+			}
+			goto error;
+		}
+		out_array[i++] = (guint) num;
+	}
 
 	return TRUE;
+
+error:
+	g_strfreev (items);
+	return FALSE;
 }
 
 static void
-vpn_data_item (const char *key, const char *value, gpointer user_data)
+dcb_check_feature_enabled (NMSettingDcb *s_dcb, const char *flags_prop)
 {
-	GString *ret_str = (GString *) user_data;
+	NMSettingDcbFlags flags = NM_SETTING_DCB_FLAG_NONE;
 
-	if (ret_str->len != 0)
-		g_string_append (ret_str, ", ");
+	g_object_get (s_dcb, flags_prop, &flags, NULL);
+	if (!(flags & NM_SETTING_DCB_FLAG_ENABLE))
+		printf (_("Warning: changes will have no effect until '%s' includes 1 (enabled)\n\n"), flags_prop);
+}
 
-	g_string_append_printf (ret_str, "%s = %s", key, value);
+static gboolean
+nmc_property_dcb_set_pfc (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	guint i = 0;
+	guint nums[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	if (!dcb_parse_uint_array (val, 1, 0, nums, error))
+		return FALSE;
+
+	for (i = 0; i < 8; i++)
+		nm_setting_dcb_set_priority_flow_control (NM_SETTING_DCB (setting), i, !!nums[i]);
+
+	dcb_check_feature_enabled (NM_SETTING_DCB (setting), NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS);
+	return TRUE;
 }
 
-gboolean
-setting_vpn_details (NMSettingVPN *s_vpn, NmCli *nmc)
+static gboolean
+nmc_property_dcb_set_pg_group_id (NMSetting *setting, const char *prop, const char *val, GError **error)
 {
-	GString *data_item_str, *secret_str;
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+	guint i = 0;
+	guint nums[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
 
-	g_return_val_if_fail (NM_IS_SETTING_VPN (s_vpn), FALSE);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-	nmc->allowed_fields = nmc_fields_setting_vpn;
-	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_VPN_ALL, nmc->allowed_fields, NULL);
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-	print_fields (nmc->print_fields, nmc->allowed_fields);  /* Print field names */
+	if (!dcb_parse_uint_array (val, 7, 15, nums, error))
+		return FALSE;
 
-	data_item_str = g_string_new (NULL);
-	secret_str = g_string_new (NULL);
-	nm_setting_vpn_foreach_data_item (s_vpn, &vpn_data_item, data_item_str);
-	nm_setting_vpn_foreach_secret (s_vpn, &vpn_data_item, secret_str);
+	for (i = 0; i < 8; i++)
+		nm_setting_dcb_set_priority_group_id (NM_SETTING_DCB (setting), i, nums[i]);
+
+	dcb_check_feature_enabled (NM_SETTING_DCB (setting), NM_SETTING_DCB_PRIORITY_GROUP_FLAGS);
+	return TRUE;
+}
 
-	nmc->allowed_fields[0].value = NM_SETTING_VPN_SETTING_NAME;
-	nmc->allowed_fields[1].value = nm_setting_vpn_get_service_type (s_vpn);
-	nmc->allowed_fields[2].value = nm_setting_vpn_get_user_name (s_vpn);
-	nmc->allowed_fields[3].value = data_item_str->str;
-	nmc->allowed_fields[4].value = secret_str->str;
+static gboolean
+nmc_property_dcb_set_pg_group_bandwidth (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	guint i = 0, sum = 0;
+	guint nums[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
 
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-	g_string_free (data_item_str, TRUE);
-	g_string_free (secret_str, TRUE);
+	if (!dcb_parse_uint_array (val, 100, 0, nums, error))
+		return FALSE;
 
+	for (i = 0; i < 8; i++)
+		sum += nums[i];
+	if (sum != 100) {
+		g_set_error_literal (error, 1, 0, _("bandwidth percentages must total 100%%"));
+		return FALSE;
+	}
+
+	for (i = 0; i < 8; i++)
+		nm_setting_dcb_set_priority_group_bandwidth (NM_SETTING_DCB (setting), i, nums[i]);
+
+	dcb_check_feature_enabled (NM_SETTING_DCB (setting), NM_SETTING_DCB_PRIORITY_GROUP_FLAGS);
 	return TRUE;
 }
 
-gboolean
-setting_wimax_details (NMSettingWimax *s_wimax, NmCli *nmc)
+static gboolean
+nmc_property_dcb_set_pg_bandwidth (NMSetting *setting, const char *prop, const char *val, GError **error)
 {
-	const GByteArray *mac;
-	char *device_mac_str = NULL;
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+	guint i = 0;
+	guint nums[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
 
-	g_return_val_if_fail (NM_IS_SETTING_WIMAX (s_wimax), FALSE);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	if (!dcb_parse_uint_array (val, 100, 0, nums, error))
+		return FALSE;
+
+	for (i = 0; i < 8; i++)
+		nm_setting_dcb_set_priority_bandwidth (NM_SETTING_DCB (setting), i, nums[i]);
+
+	dcb_check_feature_enabled (NM_SETTING_DCB (setting), NM_SETTING_DCB_PRIORITY_GROUP_FLAGS);
+	return TRUE;
+}
+
+static gboolean
+nmc_property_dcb_set_pg_strict (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	guint i = 0;
+	guint nums[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	if (!dcb_parse_uint_array (val, 1, 0, nums, error))
+		return FALSE;
 
-	nmc->allowed_fields = nmc_fields_setting_wimax;
-	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_WIMAX_ALL, nmc->allowed_fields, NULL);
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-	print_fields (nmc->print_fields, nmc->allowed_fields);  /* Print field names */
+	for (i = 0; i < 8; i++)
+		nm_setting_dcb_set_priority_strict_bandwidth (NM_SETTING_DCB (setting), i, !!nums[i]);
 
-	mac = nm_setting_wimax_get_mac_address (s_wimax);
-	if (mac)
-		device_mac_str = nm_utils_hwaddr_ntoa (mac->data, ARPHRD_ETHER);
+	dcb_check_feature_enabled (NM_SETTING_DCB (setting), NM_SETTING_DCB_PRIORITY_GROUP_FLAGS);
+	return TRUE;
+}
+
+static gboolean
+nmc_property_dcb_set_pg_traffic_class (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	guint i = 0;
+	guint nums[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
 
-	nmc->allowed_fields[0].value = NM_SETTING_WIMAX_SETTING_NAME;
-	nmc->allowed_fields[1].value = device_mac_str;
-	nmc->allowed_fields[2].value = nm_setting_wimax_get_network_name (s_wimax);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+	if (!dcb_parse_uint_array (val, 7, 0, nums, error))
+		return FALSE;
 
-	g_free (device_mac_str);
+	for (i = 0; i < 8; i++)
+		nm_setting_dcb_set_priority_traffic_class (NM_SETTING_DCB (setting), i, nums[i]);
 
+	dcb_check_feature_enabled (NM_SETTING_DCB (setting), NM_SETTING_DCB_PRIORITY_GROUP_FLAGS);
 	return TRUE;
 }
 
+/* 'app-fcoe-mode' */
+static const char *_dcb_valid_fcoe_modes[] = { NM_SETTING_DCB_FCOE_MODE_FABRIC,
+                                               NM_SETTING_DCB_FCOE_MODE_VN2VN,
+                                               NULL };
+
+static gboolean
+nmc_property_dcb_set_app_fcoe_mode (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+	return check_and_set_string (setting, prop, val, _dcb_valid_fcoe_modes, error);
+}
+
+DEFINE_ALLOWED_VAL_FUNC (nmc_property_dcb_allowed_app_fcoe_modes, _dcb_valid_fcoe_modes)
+
+/*----------------------------------------------------------------------------*/
+
+static void
+nmc_add_prop_funcs (char *key,
+                    NmcPropertyGetFunc get_func,
+                    NmcPropertySetFunc set_func,
+                    NmcPropertyRemoveFunc remove_func,
+                    NmcPropertyDescribeFunc describe_func,
+                    NmcPropertyValuesFunc values_func,
+                    NmcPropertyOut2InFunc out2in_func)
+{
+	NmcPropertyFuncs *item = g_malloc0 (sizeof (NmcPropertyFuncs));
+	item->get_func = get_func;
+	item->set_func = set_func;
+	item->remove_func = remove_func;
+	item->describe_func = describe_func;
+	item->values_func = values_func;
+	item->out2in_func = out2in_func;
+
+	g_hash_table_insert (nmc_properties, key, item);
+}
+
+/* concatenate setting name and property name */
+#define GLUE(A,B) (g_strconcat ((NM_SETTING_##A##_SETTING_NAME),(NM_SETTING_##A##_##B), NULL))
+void
+nmc_properties_init (void)
+{
+	if (G_LIKELY (nmc_properties))
+		return;
+
+	/* create properties hash table */
+	nmc_properties = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+	/* Add editable properties for NM_SETTING_802_1X_SETTING_NAME */
+	nmc_add_prop_funcs (GLUE (802_1X, EAP),
+	                    nmc_property_802_1X_get_eap,
+	                    nmc_property_802_1X_set_eap,
+	                    nmc_property_802_1X_remove_eap,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (802_1X, IDENTITY),
+	                    nmc_property_802_1X_get_identity,
+	                    nmc_property_set_string,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (802_1X, ANONYMOUS_IDENTITY),
+	                    nmc_property_802_1X_get_anonymous_identity,
+	                    nmc_property_set_string,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (802_1X, PAC_FILE),
+	                    nmc_property_802_1X_get_pac_file,
+	                    nmc_property_set_string,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (802_1X, CA_CERT),
+	                    nmc_property_802_1X_get_ca_cert,
+	                    nmc_property_802_1X_set_ca_cert,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (802_1X, CA_PATH),
+	                    nmc_property_802_1X_get_ca_path,
+                            nmc_property_set_string,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (802_1X, SUBJECT_MATCH),
+	                    nmc_property_802_1X_get_subject_match,
+	                    nmc_property_set_string,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (802_1X, ALTSUBJECT_MATCHES),
+	                    nmc_property_802_1X_get_altsubject_matches,
+	                    nmc_property_802_1X_set_altsubject_matches,
+	                    nmc_property_802_1X_remove_altsubject_matches,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (802_1X, CLIENT_CERT),
+	                    nmc_property_802_1X_get_client_cert,
+	                    nmc_property_802_1X_set_client_cert,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (802_1X, PHASE1_PEAPVER),
+	                    nmc_property_802_1X_get_phase1_peapver,
+	                    nmc_property_802_1X_set_phase1_peapver,
+	                    NULL,
+	                    NULL,
+	                    nmc_property_802_1X_allowed_phase1_peapver,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (802_1X, PHASE1_PEAPLABEL),
+	                    nmc_property_802_1X_get_phase1_peaplabel,
+	                    nmc_property_802_1X_set_phase1_peaplabel,
+	                    NULL,
+	                    NULL,
+	                    nmc_property_802_1X_allowed_phase1_peaplabel,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (802_1X, PHASE1_FAST_PROVISIONING),
+	                    nmc_property_802_1X_get_phase1_fast_provisioning,
+	                    nmc_property_802_1X_set_phase1_fast_provisioning,
+	                    NULL,
+	                    NULL,
+	                    nmc_property_802_1X_allowed_phase1_fast_provisioning,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (802_1X, PHASE2_AUTH),
+	                    nmc_property_802_1X_get_phase2_auth,
+	                    nmc_property_802_1X_set_phase2_auth,
+	                    NULL,
+	                    NULL,
+	                    nmc_property_802_1X_allowed_phase2_auth,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (802_1X, PHASE2_AUTHEAP),
+	                    nmc_property_802_1X_get_phase2_autheap,
+	                    nmc_property_802_1X_set_phase2_autheap,
+	                    NULL,
+	                    NULL,
+	                    nmc_property_802_1X_allowed_phase2_autheap,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (802_1X, PHASE2_CA_CERT),
+	                    nmc_property_802_1X_get_phase2_ca_cert,
+	                    nmc_property_802_1X_set_phase2_ca_cert,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (802_1X, PHASE2_CA_PATH),
+	                    nmc_property_802_1X_get_phase2_ca_path,
+	                    nmc_property_set_string,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (802_1X, PHASE2_SUBJECT_MATCH),
+	                    nmc_property_802_1X_get_phase2_subject_match,
+	                    nmc_property_set_string,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (802_1X, PHASE2_ALTSUBJECT_MATCHES),
+	                    nmc_property_802_1X_get_phase2_altsubject_matches,
+	                    nmc_property_802_1X_set_phase2_altsubject_matches,
+	                    nmc_property_802_1X_remove_phase2_altsubject_matches,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (802_1X, PHASE2_CLIENT_CERT),
+	                    nmc_property_802_1X_get_phase2_client_cert,
+	                    nmc_property_802_1X_set_phase2_client_cert,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (802_1X, PASSWORD),
+	                    nmc_property_802_1X_get_password,
+	                    nmc_property_set_string,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (802_1X, PASSWORD_FLAGS),
+	                    nmc_property_802_1X_get_password_flags,
+	                    nmc_property_set_flags,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    nmc_property_out2in_cut_paren);
+	nmc_add_prop_funcs (GLUE (802_1X, PASSWORD_RAW),
+	                    nmc_property_802_1X_get_password_raw,
+	                    nmc_property_802_1X_set_password_raw,
+	                    NULL,
+	                    nmc_property_802_1X_describe_password_raw,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (802_1X, PASSWORD_RAW_FLAGS),
+	                    nmc_property_802_1X_get_password_raw_flags,
+	                    nmc_property_set_flags,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    nmc_property_out2in_cut_paren);
+	nmc_add_prop_funcs (GLUE (802_1X, PRIVATE_KEY),
+	                    nmc_property_802_1X_get_private_key,
+	                    nmc_property_802_1X_set_private_key,
+	                    NULL,
+	                    nmc_property_802_1X_describe_private_key,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (802_1X, PRIVATE_KEY_PASSWORD),
+	                    nmc_property_802_1X_get_private_key_password,
+	                    nmc_property_set_string,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (802_1X, PRIVATE_KEY_PASSWORD_FLAGS),
+	                    nmc_property_802_1X_get_private_key_password_flags,
+	                    nmc_property_set_flags,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    nmc_property_out2in_cut_paren);
+	nmc_add_prop_funcs (GLUE (802_1X, PHASE2_PRIVATE_KEY),
+	                    nmc_property_802_1X_get_phase2_private_key,
+	                    nmc_property_802_1X_set_phase2_private_key,
+	                    NULL,
+	                    nmc_property_802_1X_describe_private_key,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (802_1X, PHASE2_PRIVATE_KEY_PASSWORD),
+	                    nmc_property_802_1X_get_phase2_private_key_password,
+	                    nmc_property_set_string,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (802_1X, PHASE2_PRIVATE_KEY_PASSWORD_FLAGS),
+	                    nmc_property_802_1X_get_phase2_private_key_password_flags,
+	                    nmc_property_set_flags,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    nmc_property_out2in_cut_paren);
+	nmc_add_prop_funcs (GLUE (802_1X, PIN),
+	                    nmc_property_802_1X_get_pin,
+	                    nmc_property_set_string,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (802_1X, PIN_FLAGS),
+	                    nmc_property_802_1X_get_pin_flags,
+	                    nmc_property_set_flags,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    nmc_property_out2in_cut_paren);
+	nmc_add_prop_funcs (GLUE (802_1X, SYSTEM_CA_CERTS),
+	                    nmc_property_802_1X_get_system_ca_certs,
+	                    nmc_property_set_bool,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+
+	/* Add editable properties for NM_SETTING_ADSL_SETTING_NAME */
+	nmc_add_prop_funcs (GLUE (ADSL, USERNAME),
+	                    nmc_property_adsl_get_username,
+	                    nmc_property_set_string,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (ADSL, PASSWORD),
+	                    nmc_property_adsl_get_password,
+	                    nmc_property_set_string,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (ADSL, PASSWORD_FLAGS),
+	                    nmc_property_adsl_get_password_flags,
+	                    nmc_property_set_flags,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    nmc_property_out2in_cut_paren);
+	nmc_add_prop_funcs (GLUE (ADSL, PROTOCOL),
+	                    nmc_property_adsl_get_protocol,
+	                    nmc_property_adsl_set_protocol,
+	                    NULL,
+	                    NULL,
+	                    nmc_property_adsl_allowed_protocol,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (ADSL, ENCAPSULATION),
+	                    nmc_property_adsl_get_encapsulation,
+	                    nmc_property_adsl_set_encapsulation,
+	                    NULL,
+	                    NULL,
+	                    nmc_property_adsl_allowed_encapsulation,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (ADSL, VPI),
+	                    nmc_property_adsl_get_vpi,
+	                    nmc_property_set_uint,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (ADSL, VCI),
+	                    nmc_property_adsl_get_vci,
+	                    nmc_property_set_uint,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+
+	/* Add editable properties for NM_SETTING_BLUETOOTH_SETTING_NAME */
+	nmc_add_prop_funcs (GLUE (BLUETOOTH, BDADDR),
+	                    nmc_property_bluetooth_get_bdaddr,
+	                    nmc_property_set_mac,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (BLUETOOTH, TYPE),
+	                    nmc_property_bluetooth_get_type,
+	                    nmc_property_bluetooth_set_type,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+
+	/* Add editable properties for NM_SETTING_BOND_SETTING_NAME */
+	nmc_add_prop_funcs (GLUE (BOND, INTERFACE_NAME),
+	                    nmc_property_bond_get_interface_name,
+	                    nmc_property_set_ifname,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (BOND, OPTIONS),
+	                    nmc_property_bond_get_options,
+	                    nmc_property_bond_set_options,
+	                    nmc_property_bond_remove_option_options,
+	                    nmc_property_bond_describe_options,
+	                    nmc_property_bond_allowed_options,
+	                    NULL);
+
+	/* Add editable properties for NM_SETTING_BRIDGE_SETTING_NAME */
+	nmc_add_prop_funcs (GLUE (BRIDGE, INTERFACE_NAME),
+	                    nmc_property_bridge_get_interface_name,
+	                    nmc_property_set_ifname,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (BRIDGE, MAC_ADDRESS),
+	                    nmc_property_bridge_get_mac_address,
+	                    nmc_property_set_mac,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (BRIDGE, STP),
+	                    nmc_property_bridge_get_stp,
+	                    nmc_property_set_bool,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (BRIDGE, PRIORITY),
+	                    nmc_property_bridge_get_priority,
+	                    nmc_property_set_uint,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (BRIDGE, FORWARD_DELAY),
+	                    nmc_property_bridge_get_forward_delay,
+	                    nmc_property_set_uint,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (BRIDGE, HELLO_TIME),
+	                    nmc_property_bridge_get_hello_time,
+	                    nmc_property_set_uint,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (BRIDGE, MAX_AGE),
+	                    nmc_property_bridge_get_max_age,
+	                    nmc_property_set_uint,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (BRIDGE, AGEING_TIME),
+	                    nmc_property_bridge_get_ageing_time,
+	                    nmc_property_set_uint,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+
+	/* Add editable properties for NM_SETTING_BRIDGE_PORT_SETTING_NAME */
+	nmc_add_prop_funcs (GLUE (BRIDGE_PORT, PRIORITY),
+	                    nmc_property_bridge_port_get_priority,
+	                    nmc_property_set_uint,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (BRIDGE_PORT, PATH_COST),
+	                    nmc_property_bridge_port_get_path_cost,
+	                    nmc_property_set_uint,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (BRIDGE_PORT, HAIRPIN_MODE),
+	                    nmc_property_bridge_port_get_hairpin_mode,
+	                    nmc_property_set_bool,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+
+	/* Add editable properties for NM_SETTING_CDMA_SETTING_NAME */
+	nmc_add_prop_funcs (GLUE (CDMA, NUMBER),
+	                    nmc_property_cdma_get_number,
+	                    nmc_property_set_string,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (CDMA, USERNAME),
+	                    nmc_property_cdma_get_username,
+	                    nmc_property_set_string,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (CDMA, PASSWORD),
+	                    nmc_property_cdma_get_password,
+	                    nmc_property_set_string,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (CDMA, PASSWORD_FLAGS),
+	                    nmc_property_cdma_get_password_flags,
+	                    nmc_property_set_flags,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    nmc_property_out2in_cut_paren);
+
+	/* Add editable properties for NM_SETTING_CONNECTION_SETTING_NAME */
+	nmc_add_prop_funcs (GLUE (CONNECTION, ID),
+	                    nmc_property_connection_get_id,
+	                    nmc_property_set_string,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (CONNECTION, UUID),
+	                    nmc_property_connection_get_uuid,
+	                    NULL, /* forbid setting/removing UUID */
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (CONNECTION, INTERFACE_NAME),
+	                    nmc_property_connection_get_interface_name,
+	                    nmc_property_set_ifname,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (CONNECTION, TYPE),
+	                    nmc_property_connection_get_type,
+	                    NULL, /* read-only */
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (CONNECTION, AUTOCONNECT),
+	                    nmc_property_connection_get_autoconnect,
+	                    nmc_property_set_bool,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (CONNECTION, TIMESTAMP),
+	                    nmc_property_connection_get_timestamp,
+	                    NULL, /* read-only */
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (CONNECTION, READ_ONLY),
+	                    nmc_property_connection_get_read_only,
+	                    NULL, /* 'read-only' is read-only :-) */
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (CONNECTION, PERMISSIONS),
+	                    nmc_property_connection_get_permissions,
+	                    nmc_property_connection_set_permissions,
+	                    nmc_property_connection_remove_permissions,
+	                    nmc_property_connection_describe_permissions,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (CONNECTION, ZONE),
+	                    nmc_property_connection_get_zone,
+	                    nmc_property_set_string,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (CONNECTION, MASTER),
+	                    nmc_property_connection_get_master,
+	                    nmc_property_con_set_master,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (CONNECTION, SLAVE_TYPE),
+	                    nmc_property_connection_get_slave_type,
+	                    nmc_property_con_set_slave_type,
+	                    NULL,
+	                    NULL,
+	                    nmc_property_con_allowed_slave_type,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (CONNECTION, SECONDARIES),
+	                    nmc_property_connection_get_secondaries,
+	                    nmc_property_connection_set_secondaries,
+	                    nmc_property_connection_remove_secondaries,
+	                    nmc_property_connection_describe_secondaries,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (CONNECTION, GATEWAY_PING_TIMEOUT),
+	                    nmc_property_connection_get_gateway_ping_timeout,
+	                    nmc_property_set_uint,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+
+	/* Add editable properties for NM_SETTING_DCB_SETTING_NAME */
+	nmc_add_prop_funcs (GLUE (DCB, APP_FCOE_FLAGS),
+	                    nmc_property_dcb_get_app_fcoe_flags,
+	                    nmc_property_dcb_set_flags,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (DCB, APP_FCOE_MODE),
+	                    nmc_property_dcb_get_app_fcoe_mode,
+	                    nmc_property_dcb_set_app_fcoe_mode,
+	                    NULL,
+	                    NULL,
+	                    nmc_property_dcb_allowed_app_fcoe_modes,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (DCB, APP_FCOE_PRIORITY),
+	                    nmc_property_dcb_get_app_fcoe_priority,
+	                    nmc_property_dcb_set_priority,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (DCB, APP_ISCSI_FLAGS),
+	                    nmc_property_dcb_get_app_iscsi_flags,
+	                    nmc_property_dcb_set_flags,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (DCB, APP_ISCSI_PRIORITY),
+	                    nmc_property_dcb_get_app_iscsi_priority,
+	                    nmc_property_dcb_set_priority,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (DCB, APP_FIP_FLAGS),
+	                    nmc_property_dcb_get_app_fip_flags,
+	                    nmc_property_dcb_set_flags,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (DCB, APP_FIP_PRIORITY),
+	                    nmc_property_dcb_get_app_fip_priority,
+	                    nmc_property_dcb_set_priority,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (DCB, PRIORITY_FLOW_CONTROL_FLAGS),
+	                    nmc_property_dcb_get_pfc_flags,
+	                    nmc_property_dcb_set_flags,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (DCB, PRIORITY_FLOW_CONTROL),
+	                    nmc_property_dcb_get_pfc,
+	                    nmc_property_dcb_set_pfc,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (DCB, PRIORITY_GROUP_FLAGS),
+	                    nmc_property_dcb_get_pg_flags,
+	                    nmc_property_dcb_set_flags,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (DCB, PRIORITY_GROUP_ID),
+	                    nmc_property_dcb_get_pg_group_id,
+	                    nmc_property_dcb_set_pg_group_id,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (DCB, PRIORITY_GROUP_BANDWIDTH),
+	                    nmc_property_dcb_get_pg_group_bandwidth,
+	                    nmc_property_dcb_set_pg_group_bandwidth,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (DCB, PRIORITY_BANDWIDTH),
+	                    nmc_property_dcb_get_pg_bandwidth,
+	                    nmc_property_dcb_set_pg_bandwidth,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (DCB, PRIORITY_STRICT_BANDWIDTH),
+	                    nmc_property_dcb_get_pg_strict,
+	                    nmc_property_dcb_set_pg_strict,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (DCB, PRIORITY_TRAFFIC_CLASS),
+	                    nmc_property_dcb_get_pg_traffic_class,
+	                    nmc_property_dcb_set_pg_traffic_class,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+
+	/* Add editable properties for NM_SETTING_GSM_SETTING_NAME */
+	nmc_add_prop_funcs (GLUE (GSM, NUMBER),
+	                    nmc_property_gsm_get_number,
+	                    nmc_property_set_string,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (GSM, USERNAME),
+	                    nmc_property_gsm_get_username,
+	                    nmc_property_set_string,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (GSM, PASSWORD),
+	                    nmc_property_gsm_get_password,
+	                    nmc_property_set_string,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (GSM, PASSWORD_FLAGS),
+	                    nmc_property_gsm_get_password_flags,
+	                    nmc_property_set_flags,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    nmc_property_out2in_cut_paren);
+	nmc_add_prop_funcs (GLUE (GSM, APN),
+	                    nmc_property_gsm_get_apn,
+	                    nmc_property_set_string,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (GSM, NETWORK_ID),
+	                    nmc_property_gsm_get_network_id,
+	                    nmc_property_set_string,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (GSM, NETWORK_TYPE),
+	                    nmc_property_gsm_get_network_type,
+	                    nmc_property_set_int,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (GSM, ALLOWED_BANDS),
+	                    nmc_property_gsm_get_allowed_bands,
+	                    nmc_property_set_uint,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    nmc_property_out2in_cut_paren);
+	nmc_add_prop_funcs (GLUE (GSM, PIN),
+	                    nmc_property_gsm_get_pin,
+	                    nmc_property_set_string,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (GSM, PIN_FLAGS),
+	                    nmc_property_gsm_get_pin_flags,
+	                    nmc_property_set_flags,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    nmc_property_out2in_cut_paren);
+	nmc_add_prop_funcs (GLUE (GSM, HOME_ONLY),
+	                    nmc_property_gsm_get_home_only,
+	                    nmc_property_set_bool,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+
+	/* Add editable properties for NM_SETTING_INFINIBAND_SETTING_NAME */
+	nmc_add_prop_funcs (GLUE (INFINIBAND, MAC_ADDRESS),
+	                    nmc_property_ib_get_mac_address,
+	                    nmc_property_ib_set_mac,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (INFINIBAND, MTU),
+	                    nmc_property_ib_get_mtu,
+	                    nmc_property_set_mtu,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (INFINIBAND, TRANSPORT_MODE),
+	                    nmc_property_ib_get_transport_mode,
+	                    nmc_property_ib_set_transport_mode,
+	                    NULL,
+	                    NULL,
+	                    nmc_property_ib_allowed_transport_mode,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (INFINIBAND, P_KEY),
+	                    nmc_property_ib_get_p_key,
+	                    nmc_property_ib_set_p_key,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (INFINIBAND, PARENT),
+	                    nmc_property_ib_get_parent,
+	                    nmc_property_set_ifname,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+
+	/* Add editable properties for NM_SETTING_IP4_CONFIG_SETTING_NAME */
+	nmc_add_prop_funcs (GLUE (IP4_CONFIG, METHOD),
+	                    nmc_property_ipv4_get_method,
+	                    nmc_property_ipv4_set_method,
+	                    NULL,
+	                    NULL,
+	                    nmc_property_ipv4_allowed_method,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (IP4_CONFIG, DNS),
+	                    nmc_property_ipv4_get_dns,
+	                    nmc_property_ipv4_set_dns,
+	                    nmc_property_ipv4_remove_dns,
+	                    nmc_property_ipv4_describe_dns,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (IP4_CONFIG, DNS_SEARCH),
+	                    nmc_property_ipv4_get_dns_search,
+	                    nmc_property_ipv4_set_dns_search,
+	                    nmc_property_ipv4_remove_dns_search,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (IP4_CONFIG, ADDRESSES),
+	                    nmc_property_ipv4_get_addresses,
+	                    nmc_property_ipv4_set_addresses,
+	                    nmc_property_ipv4_remove_addresses,
+	                    nmc_property_ipv4_describe_addresses,
+	                    NULL,
+	                    nmc_property_out2in_addresses);
+	nmc_add_prop_funcs (GLUE (IP4_CONFIG, ROUTES),
+	                    nmc_property_ipv4_get_routes,
+	                    nmc_property_ipv4_set_routes,
+	                    nmc_property_ipv4_remove_routes,
+	                    nmc_property_ipv4_describe_routes,
+	                    NULL,
+	                    nmc_property_out2in_routes);
+	nmc_add_prop_funcs (GLUE (IP4_CONFIG, IGNORE_AUTO_ROUTES),
+	                    nmc_property_ipv4_get_ignore_auto_routes,
+	                    nmc_property_set_bool,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (IP4_CONFIG, IGNORE_AUTO_DNS),
+	                    nmc_property_ipv4_get_ignore_auto_dns,
+	                    nmc_property_set_bool,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (IP4_CONFIG, DHCP_CLIENT_ID),
+	                    nmc_property_ipv4_get_dhcp_client_id,
+	                    nmc_property_set_string,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (IP4_CONFIG, DHCP_SEND_HOSTNAME),
+	                    nmc_property_ipv4_get_dhcp_send_hostname,
+	                    nmc_property_set_bool,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (IP4_CONFIG, DHCP_HOSTNAME),
+	                    nmc_property_ipv4_get_dhcp_hostname,
+	                    nmc_property_set_string,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (IP4_CONFIG, NEVER_DEFAULT),
+	                    nmc_property_ipv4_get_never_default,
+	                    nmc_property_set_bool,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (IP4_CONFIG, MAY_FAIL),
+	                    nmc_property_ipv4_get_may_fail,
+	                    nmc_property_set_bool,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+
+	/* Add editable properties for NM_SETTING_IP6_CONFIG_SETTING_NAME */
+	nmc_add_prop_funcs (GLUE (IP6_CONFIG, METHOD),
+	                    nmc_property_ipv6_get_method,
+	                    nmc_property_ipv6_set_method,
+	                    NULL,
+	                    NULL,
+	                    nmc_property_ipv6_allowed_method,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (IP6_CONFIG, DNS),
+	                    nmc_property_ipv6_get_dns,
+	                    nmc_property_ipv6_set_dns,
+	                    nmc_property_ipv6_remove_dns,
+	                    nmc_property_ipv6_describe_dns,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (IP6_CONFIG, DNS_SEARCH),
+	                    nmc_property_ipv6_get_dns_search,
+	                    nmc_property_ipv6_set_dns_search,
+	                    nmc_property_ipv6_remove_dns_search,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (IP6_CONFIG, ADDRESSES),
+	                    nmc_property_ipv6_get_addresses,
+	                    nmc_property_ipv6_set_addresses,
+	                    nmc_property_ipv6_remove_addresses,
+	                    nmc_property_ipv6_describe_addresses,
+	                    NULL,
+	                    nmc_property_out2in_addresses);
+	nmc_add_prop_funcs (GLUE (IP6_CONFIG, ROUTES),
+	                    nmc_property_ipv6_get_routes,
+	                    nmc_property_ipv6_set_routes,
+	                    nmc_property_ipv6_remove_routes,
+	                    nmc_property_ipv6_describe_routes,
+	                    NULL,
+	                    nmc_property_out2in_routes);
+	nmc_add_prop_funcs (GLUE (IP6_CONFIG, IGNORE_AUTO_ROUTES),
+	                    nmc_property_ipv6_get_ignore_auto_routes,
+	                    nmc_property_set_bool,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (IP6_CONFIG, IGNORE_AUTO_DNS),
+	                    nmc_property_ipv6_get_ignore_auto_dns,
+	                    nmc_property_set_bool,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (IP6_CONFIG, NEVER_DEFAULT),
+	                    nmc_property_ipv6_get_never_default,
+	                    nmc_property_set_bool,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (IP6_CONFIG, MAY_FAIL),
+	                    nmc_property_ipv6_get_may_fail,
+	                    nmc_property_set_bool,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (IP6_CONFIG, IP6_PRIVACY),
+	                    nmc_property_ipv6_get_ip6_privacy,
+	                    nmc_property_ipv6_set_ip6_privacy,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    nmc_property_out2in_cut_paren);
+	nmc_add_prop_funcs (GLUE (IP6_CONFIG, DHCP_HOSTNAME),
+	                    nmc_property_ipv6_get_dhcp_hostname,
+	                    nmc_property_set_string,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+
+	/* Add editable properties for NM_SETTING_OLPC_MESH_SETTING_NAME */
+	nmc_add_prop_funcs (GLUE (OLPC_MESH, SSID),
+	                    nmc_property_olpc_get_ssid,
+	                    nmc_property_set_ssid,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (OLPC_MESH, CHANNEL),
+	                    nmc_property_olpc_get_channel,
+	                    nmc_property_olpc_set_channel,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (OLPC_MESH, DHCP_ANYCAST_ADDRESS),
+	                    nmc_property_olpc_get_anycast_address,
+	                    nmc_property_set_mac,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+
+	/* Add editable properties for NM_SETTING_PPP_SETTING_NAME */
+	nmc_add_prop_funcs (GLUE (PPP, NOAUTH),
+	                    nmc_property_ppp_get_noauth,
+	                    nmc_property_set_bool,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (PPP, REFUSE_EAP),
+	                    nmc_property_ppp_get_refuse_eap,
+	                    nmc_property_set_bool,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (PPP, REFUSE_PAP),
+	                    nmc_property_ppp_get_refuse_pap,
+	                    nmc_property_set_bool,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (PPP, REFUSE_CHAP),
+	                    nmc_property_ppp_get_refuse_chap,
+	                    nmc_property_set_bool,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (PPP, REFUSE_MSCHAP),
+	                    nmc_property_ppp_get_refuse_mschap,
+	                    nmc_property_set_bool,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (PPP, REFUSE_MSCHAPV2),
+	                    nmc_property_ppp_get_refuse_mschapv2,
+	                    nmc_property_set_bool,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (PPP, NOBSDCOMP),
+	                    nmc_property_ppp_get_nobsdcomp,
+	                    nmc_property_set_bool,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (PPP, NODEFLATE),
+	                    nmc_property_ppp_get_nodeflate,
+	                    nmc_property_set_bool,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (PPP, NO_VJ_COMP),
+	                    nmc_property_ppp_get_no_vj_comp,
+	                    nmc_property_set_bool,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (PPP, REQUIRE_MPPE),
+	                    nmc_property_ppp_get_require_mppe,
+	                    nmc_property_set_bool,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (PPP, REQUIRE_MPPE_128),
+	                    nmc_property_ppp_get_require_mppe_128,
+	                    nmc_property_set_bool,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (PPP, MPPE_STATEFUL),
+	                    nmc_property_ppp_get_mppe_stateful,
+	                    nmc_property_set_bool,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (PPP, CRTSCTS),
+	                    nmc_property_ppp_get_crtscts,
+	                    nmc_property_set_bool,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (PPP, BAUD),
+	                    nmc_property_ppp_get_baud,
+	                    nmc_property_set_uint,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (PPP, MRU),
+	                    nmc_property_ppp_get_mru,
+	                    nmc_property_set_uint,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (PPP, MTU),
+	                    nmc_property_ppp_get_mtu,
+	                    nmc_property_set_mtu,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (PPP, LCP_ECHO_FAILURE),
+	                    nmc_property_ppp_get_lcp_echo_failure,
+	                    nmc_property_set_uint,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (PPP, LCP_ECHO_INTERVAL),
+	                    nmc_property_ppp_get_lcp_echo_interval,
+	                    nmc_property_set_uint,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+
+	/* Add editable properties for NM_SETTING_PPPOE_SETTING_NAME */
+	nmc_add_prop_funcs (GLUE (PPPOE, SERVICE),
+	                    nmc_property_pppoe_get_service,
+	                    nmc_property_set_string,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (PPPOE, USERNAME),
+	                    nmc_property_pppoe_get_username,
+	                    nmc_property_set_string,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (PPPOE, PASSWORD),
+	                    nmc_property_pppoe_get_password,
+	                    nmc_property_set_string,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (PPPOE, PASSWORD_FLAGS),
+	                    nmc_property_pppoe_get_password_flags,
+	                    nmc_property_set_flags,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    nmc_property_out2in_cut_paren);
+
+	/* Add editable properties for NM_SETTING_SERIAL_SETTING_NAME */
+	nmc_add_prop_funcs (GLUE (SERIAL, BAUD),
+	                    nmc_property_serial_get_baud,
+	                    nmc_property_set_uint,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (SERIAL, BITS),
+	                    nmc_property_serial_get_bits,
+	                    nmc_property_set_uint,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (SERIAL, PARITY),
+	                    nmc_property_serial_get_parity,
+	                    nmc_property_serial_set_parity,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (SERIAL, STOPBITS),
+	                    nmc_property_serial_get_stopbits,
+	                    nmc_property_set_uint,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (SERIAL, SEND_DELAY),
+	                    nmc_property_serial_get_send_delay,
+	                    nmc_property_set_uint,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+
+	/* Add editable properties for NM_SETTING_TEAM_SETTING_NAME */
+	nmc_add_prop_funcs (GLUE (TEAM, INTERFACE_NAME),
+	                    nmc_property_team_get_interface_name,
+	                    nmc_property_set_ifname,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (TEAM, CONFIG),
+	                    nmc_property_team_get_config,
+	                    nmc_property_team_set_config,
+	                    NULL,
+	                    nmc_property_team_describe_config,
+	                    NULL,
+	                    NULL);
+
+	/* Add editable properties for NM_SETTING_TEAM_PORT_SETTING_NAME */
+	nmc_add_prop_funcs (GLUE (TEAM_PORT, CONFIG),
+	                    nmc_property_team_port_get_config,
+	                    nmc_property_team_set_config,
+	                    NULL,
+	                    nmc_property_team_describe_config,
+	                    NULL,
+	                    NULL);
+
+	/* Add editable properties for NM_SETTING_VLAN_SETTING_NAME */
+	nmc_add_prop_funcs (GLUE (VLAN, INTERFACE_NAME),
+	                    nmc_property_vlan_get_interface_name,
+	                    nmc_property_set_ifname,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (VLAN, PARENT),
+	                    nmc_property_vlan_get_parent,
+	                    nmc_property_set_string,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (VLAN, ID),
+	                    nmc_property_vlan_get_id,
+	                    nmc_property_set_uint,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (VLAN, FLAGS),
+	                    nmc_property_vlan_get_flags,
+	                    nmc_property_set_uint,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (VLAN, INGRESS_PRIORITY_MAP),
+	                    nmc_property_vlan_get_ingress_priority_map,
+	                    nmc_property_vlan_set_ingress_priority_map,
+	                    nmc_property_vlan_remove_ingress_priority_map,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (VLAN, EGRESS_PRIORITY_MAP),
+	                    nmc_property_vlan_get_egress_priority_map,
+	                    nmc_property_vlan_set_egress_priority_map,
+	                    nmc_property_vlan_remove_egress_priority_map,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+
+	/* Add editable properties for NM_SETTING_VPN_SETTING_NAME */
+	nmc_add_prop_funcs (GLUE (VPN, SERVICE_TYPE),
+	                    nmc_property_vpn_get_service_type,
+	                    nmc_property_set_string,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (VPN, USER_NAME),
+	                    nmc_property_vpn_get_user_name,
+	                    nmc_property_set_string,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (VPN, DATA),
+	                    nmc_property_vpn_get_data,
+	                    nmc_property_vpn_set_data,
+	                    nmc_property_vpn_remove_option_data,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (VPN, SECRETS),
+	                    nmc_property_vpn_get_secrets,
+	                    nmc_property_vpn_set_secrets,
+	                    nmc_property_vpn_remove_option_secret,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+
+	/* Add editable properties for NM_SETTING_WIMAX_SETTING_NAME */
+	nmc_add_prop_funcs (GLUE (WIMAX, NETWORK_NAME),
+	                    nmc_property_wimax_get_network_name,
+	                    nmc_property_set_string,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (WIMAX, MAC_ADDRESS),
+	                    nmc_property_wimax_get_mac_address,
+	                    nmc_property_set_mac,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+
+	/* Add editable properties for NM_SETTING_WIRED_SETTING_NAME */
+	nmc_add_prop_funcs (GLUE (WIRED, PORT),
+	                    nmc_property_wired_get_port,
+	                    NULL, /*nmc_property_wired_set_port,*/
+	                    NULL,
+	                    NULL,
+	                    NULL, /*nmc_property_wired_allowed_port,*/
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (WIRED, SPEED),
+	                    nmc_property_wired_get_speed,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (WIRED, DUPLEX),
+	                    nmc_property_wired_get_duplex,
+	                    NULL, /*nmc_property_wired_set_duplex,*/
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL); /*nmc_property_wired_allowed_duplex);*/
+	nmc_add_prop_funcs (GLUE (WIRED, AUTO_NEGOTIATE),
+	                    nmc_property_wired_get_auto_negotiate,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (WIRED, MAC_ADDRESS),
+	                    nmc_property_wired_get_mac_address,
+	                    nmc_property_set_mac,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (WIRED, CLONED_MAC_ADDRESS),
+	                    nmc_property_wired_get_cloned_mac_address,
+	                    nmc_property_set_mac,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (WIRED, MAC_ADDRESS_BLACKLIST),
+	                    nmc_property_wired_get_mac_address_blacklist,
+	                    nmc_property_wired_set_mac_address_blacklist,
+	                    nmc_property_wired_remove_mac_address_blacklist,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (WIRED, MTU),
+	                    nmc_property_wired_get_mtu,
+	                    nmc_property_set_mtu,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (WIRED, S390_SUBCHANNELS),
+	                    nmc_property_wired_get_s390_subchannels,
+	                    nmc_property_wired_set_s390_subchannels,
+	                    NULL,
+	                    nmc_property_wired_describe_s390_subchannels,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (WIRED, S390_NETTYPE),
+	                    nmc_property_wired_get_s390_nettype,
+	                    nmc_property_wired_set_s390_nettype,
+	                    NULL,
+	                    NULL,
+	                    nmc_property_wired_allowed_s390_nettype,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (WIRED, S390_OPTIONS),
+	                    nmc_property_wired_get_s390_options,
+	                    nmc_property_wired_set_s390_options,
+	                    nmc_property_wired_remove_option_s390_options,
+	                    nmc_property_wired_describe_s390_options,
+	                    nmc_property_wired_allowed_s390_options,
+	                    NULL);
+
+	/* Add editable properties for NM_SETTING_WIRELESS_SETTING_NAME */
+	nmc_add_prop_funcs (GLUE (WIRELESS, SSID),
+	                    nmc_property_wireless_get_ssid,
+	                    nmc_property_set_ssid,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (WIRELESS, MODE),
+	                    nmc_property_wireless_get_mode,
+	                    nmc_property_wifi_set_mode,
+	                    NULL,
+	                    NULL,
+	                    nmc_property_wifi_allowed_mode,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (WIRELESS, BAND),
+	                    nmc_property_wireless_get_band,
+	                    nmc_property_wifi_set_band,
+	                    NULL,
+	                    NULL,
+	                    nmc_property_wifi_allowed_band,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (WIRELESS, CHANNEL),
+	                    nmc_property_wireless_get_channel,
+	                    nmc_property_wifi_set_channel,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (WIRELESS, BSSID),
+	                    nmc_property_wireless_get_bssid,
+	                    nmc_property_set_mac,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	/*
+	 * Do not allow setting 'rate' and 'tx-power'. They are not implemented in
+	 * NM core, nor in ifcfg-rh plugin (thus not preserved over re-reading).
+	 */
+	nmc_add_prop_funcs (GLUE (WIRELESS, RATE),
+	                    nmc_property_wireless_get_rate,
+	                    NULL, /* editing rate disabled */
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (WIRELESS, TX_POWER),
+	                    nmc_property_wireless_get_tx_power,
+	                    NULL, /* editing tx-power disabled */
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (WIRELESS, MAC_ADDRESS),
+	                    nmc_property_wireless_get_mac_address,
+	                    nmc_property_set_mac,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (WIRELESS, CLONED_MAC_ADDRESS),
+	                    nmc_property_wireless_get_cloned_mac_address,
+	                    nmc_property_set_mac,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (WIRELESS, MAC_ADDRESS_BLACKLIST),
+	                    nmc_property_wireless_get_mac_address_blacklist,
+	                    nmc_property_wireless_set_mac_address_blacklist,
+	                    nmc_property_wireless_remove_mac_address_blacklist,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (WIRELESS, SEEN_BSSIDS),
+	                    nmc_property_wireless_get_seen_bssids,
+	                    NULL, /* read-only */
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (WIRELESS, MTU),
+	                    nmc_property_wireless_get_mtu,
+	                    nmc_property_set_mtu,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (WIRELESS, HIDDEN),
+	                    nmc_property_wireless_get_hidden,
+	                    nmc_property_set_bool,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+
+	/* Add editable properties for NM_SETTING_WIRELESS_SECURITY_SETTING_NAME */
+	nmc_add_prop_funcs (GLUE (WIRELESS_SECURITY, KEY_MGMT),
+	                    nmc_property_wifi_sec_get_key_mgmt,
+	                    nmc_property_wifi_sec_set_key_mgmt,
+	                    NULL,
+	                    NULL,
+	                    nmc_property_wifi_sec_allowed_key_mgmt,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (WIRELESS_SECURITY, WEP_TX_KEYIDX),
+	                    nmc_property_wifi_sec_get_wep_tx_keyidx,
+	                    nmc_property_set_uint,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (WIRELESS_SECURITY, AUTH_ALG),
+	                    nmc_property_wifi_sec_get_auth_alg,
+	                    nmc_property_wifi_sec_set_auth_alg,
+	                    NULL,
+	                    NULL,
+	                    nmc_property_wifi_sec_allowed_auth_alg,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (WIRELESS_SECURITY, PROTO),
+	                    nmc_property_wifi_sec_get_proto,
+	                    nmc_property_wifi_sec_set_proto,
+	                    nmc_property_wifi_sec_remove_proto,
+	                    NULL,
+	                    nmc_property_wifi_sec_allowed_proto,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (WIRELESS_SECURITY, PAIRWISE),
+	                    nmc_property_wifi_sec_get_pairwise,
+	                    nmc_property_wifi_sec_set_pairwise,
+	                    nmc_property_wifi_sec_remove_pairwise,
+	                    NULL,
+	                    nmc_property_wifi_sec_allowed_pairwise,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (WIRELESS_SECURITY, GROUP),
+	                    nmc_property_wifi_sec_get_group,
+	                    nmc_property_wifi_sec_set_group,
+	                    nmc_property_wifi_sec_remove_group,
+	                    NULL,
+	                    nmc_property_wifi_sec_allowed_group,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (WIRELESS_SECURITY, LEAP_USERNAME),
+	                    nmc_property_wifi_sec_get_leap_username,
+	                    nmc_property_set_string,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (WIRELESS_SECURITY, WEP_KEY0),
+	                    nmc_property_wifi_sec_get_wep_key0,
+	                    nmc_property_wifi_set_wep_key,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (WIRELESS_SECURITY, WEP_KEY1),
+	                    nmc_property_wifi_sec_get_wep_key1,
+	                    nmc_property_wifi_set_wep_key,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (WIRELESS_SECURITY, WEP_KEY2),
+	                    nmc_property_wifi_sec_get_wep_key2,
+	                    nmc_property_wifi_set_wep_key,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (WIRELESS_SECURITY, WEP_KEY3),
+	                    nmc_property_wifi_sec_get_wep_key3,
+	                    nmc_property_wifi_set_wep_key,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (WIRELESS_SECURITY, WEP_KEY_FLAGS),
+	                    nmc_property_wifi_sec_get_wep_key_flags,
+	                    nmc_property_set_flags,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    nmc_property_out2in_cut_paren);
+	nmc_add_prop_funcs (GLUE (WIRELESS_SECURITY, WEP_KEY_TYPE),
+	                    nmc_property_wifi_sec_get_wep_key_type,
+	                    nmc_property_wifi_set_wep_key_type,
+	                    NULL,
+	                    nmc_property_wifi_describe_wep_key_type,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (WIRELESS_SECURITY, PSK),
+	                    nmc_property_wifi_sec_get_psk,
+	                    nmc_property_wifi_set_psk,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (WIRELESS_SECURITY, PSK_FLAGS),
+	                    nmc_property_wifi_sec_get_psk_flags,
+	                    nmc_property_set_flags,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    nmc_property_out2in_cut_paren);
+	nmc_add_prop_funcs (GLUE (WIRELESS_SECURITY, LEAP_PASSWORD),
+	                    nmc_property_wifi_sec_get_leap_password,
+	                    nmc_property_set_string,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    NULL);
+	nmc_add_prop_funcs (GLUE (WIRELESS_SECURITY, LEAP_PASSWORD_FLAGS),
+	                    nmc_property_wifi_sec_get_leap_password_flags,
+	                    nmc_property_set_flags,
+	                    NULL,
+	                    NULL,
+	                    NULL,
+	                    nmc_property_out2in_cut_paren);
+}
+
+void
+nmc_properties_cleanup ()
+{
+	if (nmc_properties)
+		g_hash_table_destroy (nmc_properties);
+}
+
+static const NmcPropertyFuncs *
+nmc_properties_find (const char *s_name, const char *p_name)
+{
+	NmcPropertyFuncs *item = NULL;
+	char *key;
+
+	/* FIXME: maybe it's better to init it globally */
+	nmc_properties_init ();
+
+	key = g_strdup_printf ("%s%s", s_name, p_name);
+	item = (NmcPropertyFuncs *) g_hash_table_lookup (nmc_properties, key);
+	g_free (key);
+
+	return item;
+}
+
+static char *
+get_property_val (NMSetting *setting, const char *prop, gboolean convert, GError **error)
+{
+	const NmcPropertyFuncs *item;
+
+	g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	item = nmc_properties_find (nm_setting_get_name (setting), prop);
+	if (item && item->get_func) {
+		char *prop_val = item->get_func (setting);
+		if (convert && item->out2in_func) {
+			char *converted = item->out2in_func (prop_val);
+			g_free (prop_val);
+			return converted;
+		} else
+			return prop_val;
+	}
+
+	g_set_error_literal (error, 1, 0, _("don't know how to get the property value"));
+	return NULL;
+}
+
+/*
+ * Generic function for getting property value.
+ *
+ * Gets property value as a string by calling specialized functions.
+ *
+ * Returns: current property value. The caller must free the returned string.
+ */
+char *
+nmc_setting_get_property (NMSetting *setting, const char *prop, GError **error)
+{
+	return get_property_val (setting, prop, FALSE, error);
+}
+
+/*
+ * The same as nmc_setting_get_property(), but in addition converts
+ * usual output format into a simpler one, used as input in the editor.
+ */
+char *
+nmc_setting_get_property_out2in (NMSetting *setting, const char *prop, GError **error)
+{
+	return get_property_val (setting, prop, TRUE, error);
+}
+
+/*
+ * Generic function for setting property value.
+ *
+ * Sets property=val in setting by calling specialized functions.
+ * If val is NULL then default property value is set.
+ *
+ * Returns: TRUE on success; FALSE on failure and sets error
+ */
 gboolean
-setting_infiniband_details (NMSettingInfiniband *s_infiniband, NmCli *nmc)
+nmc_setting_set_property (NMSetting *setting, const char *prop, const char *val, GError **error)
 {
-	const GByteArray *mac;
-	char *mtu_str, *mac_str = NULL;
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+	const NmcPropertyFuncs *item;
 
-	g_return_val_if_fail (NM_IS_SETTING_INFINIBAND (s_infiniband), FALSE);
+	g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	item = nmc_properties_find (nm_setting_get_name (setting), prop);
+	if (item && item->set_func) {
+		if (!val) {
+			/* No value argument sets default value */
+			nmc_property_set_default_value (setting, prop);
+			return TRUE;
+		}
+		return item->set_func (setting, prop, val, error);
+	}
 
-	nmc->allowed_fields = nmc_fields_setting_infiniband;
-	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_INFINIBAND_ALL, nmc->allowed_fields, NULL);
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-	print_fields (nmc->print_fields, nmc->allowed_fields);  /* Print field names */
+	g_set_error_literal (error, 1, 0, _("the property can't be changed"));
+	return FALSE;
+}
 
-	mac = nm_setting_infiniband_get_mac_address (s_infiniband);
-	if (mac)
-		mac_str = nm_utils_hwaddr_ntoa (mac->data, ARPHRD_INFINIBAND);
-	mtu_str = g_strdup_printf ("%d", nm_setting_infiniband_get_mtu (s_infiniband));
+void
+nmc_property_set_default_value (NMSetting *setting, const char *prop)
+{
+	GValue value = G_VALUE_INIT;
+	GParamSpec *param_spec;
+
+	param_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (G_OBJECT (setting)), prop);
+	if (param_spec) {
+		g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (param_spec));
+		g_param_value_set_default (param_spec, &value);
+		g_object_set_property (G_OBJECT (setting), prop, &value);
+	}
+}
+
+/*
+ * Generic function for reseting (single value) properties.
+ *
+ * The function resets the property value to the default one. It respects
+ * nmcli restrictions for changing properties. So if 'set_func' is NULL,
+ * reseting the value is denied.
+ *
+ * Returns: TRUE on success; FALSE on failure and sets error
+ */
+gboolean
+nmc_setting_reset_property (NMSetting *setting, const char *prop, GError **error)
+{
+	const NmcPropertyFuncs *item;
 
-	nmc->allowed_fields[0].value = NM_SETTING_INFINIBAND_SETTING_NAME;
-	nmc->allowed_fields[1].value = mac_str;
-	nmc->allowed_fields[2].value = strcmp (mtu_str, "0") ? mtu_str : _("auto");
-	nmc->allowed_fields[3].value = nm_setting_infiniband_get_transport_mode (s_infiniband);
+	g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	item = nmc_properties_find (nm_setting_get_name (setting), prop);
+	if (item && item->set_func) {
+		nmc_property_set_default_value (setting, prop);
+		return TRUE;
+	}
+	g_set_error_literal (error, 1, 0, _("the property can't be changed"));
+	return FALSE;
+}
+
+/*
+ * Generic function for removing items for collection-type properties.
+ *
+ * If 'option' is not NULL, it tries to remove it, otherwise 'idx' is used.
+ * For single-value properties (not having specialized remove function) this
+ * function does nothing and just returns TRUE.
+ *
+ * Returns: TRUE on success; FALSE on failure and sets error
+ */
+gboolean
+nmc_setting_remove_property_option (NMSetting *setting,
+                                    const char *prop,
+                                    const char *option,
+                                    guint32 idx,
+                                    GError **error)
+{
+	const NmcPropertyFuncs *item;
 
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+	g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-	g_free (mac_str);
-	g_free (mtu_str);
+	item = nmc_properties_find (nm_setting_get_name (setting), prop);
+	if (item && item->remove_func)
+		return item->remove_func (setting, prop, option, idx, error);
 
 	return TRUE;
 }
 
-gboolean
-setting_bond_details (NMSettingBond *s_bond, NmCli *nmc)
+/*
+ * Get valid property names for a setting.
+ *
+ * Returns: string array with the properties or NULL on failure.
+ *          The returned value should be freed with g_strfreev()
+ */
+char **
+nmc_setting_get_valid_properties (NMSetting *setting)
 {
-	GString *bond_options_s;
+	char **valid_props = NULL;
+	GParamSpec **props, **iter;
+	guint num;
 	int i;
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
 
-	g_return_val_if_fail (NM_IS_SETTING_BOND (s_bond), FALSE);
+	/* Iterate through properties */
+	i = 0;
+	props = g_object_class_list_properties (G_OBJECT_GET_CLASS (G_OBJECT (setting)), &num);
+	valid_props = g_malloc0 (sizeof (char*) * (num + 1));
+	for (iter = props; iter && *iter; iter++) {
+		const char *key_name = g_param_spec_get_name (*iter);
 
-	nmc->allowed_fields = nmc_fields_setting_bond;
-	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_BOND_ALL, nmc->allowed_fields, NULL);
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-	print_fields (nmc->print_fields, nmc->allowed_fields);  /* Print field names */
+		/* Add all properties except for "name" that is non-editable */
+		if (g_strcmp0 (key_name, "name") != 0)
+			valid_props[i++] = g_strdup (key_name);
+	}
+	valid_props[i] = NULL;
 
-	bond_options_s = g_string_new (NULL);
-	for (i = 0; i < nm_setting_bond_get_num_options (s_bond); i++) {
-		const char *key, *value;
+	return valid_props;
+}
 
-		nm_setting_bond_get_option (s_bond, i, &key, &value);
-		g_string_append_printf (bond_options_s, "%s=%s,", key, value);
+/*
+ * Return allowed values for 'prop' as a string.
+ */
+const char *
+nmc_setting_get_property_allowed_values (NMSetting *setting, const char *prop)
+{
+
+	const NmcPropertyFuncs *item;
+
+	g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
+
+	item = nmc_properties_find (nm_setting_get_name (setting), prop);
+	if (item && item->values_func)
+		return item->values_func (setting, prop);
+
+	return NULL;
+}
+
+/*
+ * Create a description string for a property.
+ *
+ * It returns a description got from properties blurb, concatenated with
+ * nmcli specific description (if it exists).
+ *
+ * Returns: property description or NULL on failure. The caller must free the string.
+ */
+char *
+nmc_setting_get_property_desc (NMSetting *setting, const char *prop)
+{
+	GParamSpec *spec;
+	const NmcPropertyFuncs *item;
+	const char *setting_desc = "";
+	const char *setting_desc_title = "";
+	const char *nmcli_desc = NULL;
+	const char *nmcli_desc_title = "";
+	const char *nmcli_nl = "";
+
+	g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
+
+	spec = g_object_class_find_property (G_OBJECT_GET_CLASS (G_OBJECT (setting)), prop);
+	if (spec) {
+		setting_desc = g_param_spec_get_blurb (spec);
+		setting_desc_title = _("[NM property description]");
 	}
-	g_string_truncate (bond_options_s, bond_options_s->len-1);  /* chop off trailing ',' */
 
-	nmc->allowed_fields[0].value = NM_SETTING_BOND_SETTING_NAME;
-	nmc->allowed_fields[1].value = nm_setting_bond_get_interface_name (s_bond);
-	nmc->allowed_fields[2].value = bond_options_s->str;
+	item = nmc_properties_find (nm_setting_get_name (setting), prop);
+	if (item && item->describe_func) {
+		nmcli_desc = item->describe_func (setting, prop);
+		nmcli_desc_title = _("[nmcli specific description]");
+		nmcli_nl = "\n";
+	}
+
+	return g_strdup_printf ("%s\n%s\n%s%s%s%s",
+	                        setting_desc_title, setting_desc,
+	                        nmcli_nl, nmcli_desc_title, nmcli_nl,
+	                        nmcli_desc ? nmcli_desc : "");
+}
+
+/*
+ * Gets setting:prop property value and returns it in 'value'.
+ * Caller is responsible for freeing the GValue resources using g_value_unset()
+ */
+gboolean
+nmc_property_get_gvalue (NMSetting *setting, const char *prop, GValue *value)
+{
+	GParamSpec *param_spec;
+
+	param_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (G_OBJECT (setting)), prop);
+	if (param_spec) {
+		memset (value, 0, sizeof (GValue));
+		g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (param_spec));
+		g_object_get_property (G_OBJECT (setting), prop, value);
+		return TRUE;
+	}
+	return FALSE;
+}
+
+/*
+ * Sets setting:prop property value from 'value'.
+ */
+gboolean
+nmc_property_set_gvalue (NMSetting *setting, const char *prop, GValue *value)
+{
+	GParamSpec *param_spec;
+
+	param_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (G_OBJECT (setting)), prop);
+	if (param_spec && G_VALUE_TYPE (value) == G_PARAM_SPEC_VALUE_TYPE (param_spec)) {
+		g_object_set_property (G_OBJECT (setting), prop, value);
+		return TRUE;
+	}
+	return FALSE;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static gboolean
+setting_connection_details (NMSetting *setting, NmCli *nmc, const char *one_prop)
+{
+	NMSettingConnection *s_con = NM_SETTING_CONNECTION (setting);
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
 
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+	g_return_val_if_fail (NM_IS_SETTING_CONNECTION (s_con), FALSE);
 
-	g_string_free (bond_options_s, TRUE);
+	tmpl = nmc_fields_setting_connection;
+	tmpl_len = sizeof (nmc_fields_setting_connection);
+	nmc->print_fields.indices = parse_output_fields (one_prop ? one_prop : NMC_FIELDS_SETTING_CONNECTION_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);
+
+	arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+	set_val_str (arr, 0, g_strdup (nm_setting_get_name (setting)));
+	set_val_str (arr, 1, nmc_property_connection_get_id (setting));
+	set_val_str (arr, 2, nmc_property_connection_get_uuid (setting));
+	set_val_str (arr, 3, nmc_property_connection_get_interface_name (setting));
+	set_val_str (arr, 4, nmc_property_connection_get_type (setting));
+	set_val_str (arr, 5, nmc_property_connection_get_autoconnect (setting));
+	set_val_str (arr, 6, nmc_property_connection_get_timestamp (setting));
+	set_val_str (arr, 7, nmc_property_connection_get_read_only (setting));
+	set_val_str (arr, 8, nmc_property_connection_get_permissions (setting));
+	set_val_str (arr, 9, nmc_property_connection_get_zone (setting));
+	set_val_str (arr, 10, nmc_property_connection_get_master (setting));
+	set_val_str (arr, 11, nmc_property_connection_get_slave_type (setting));
+	set_val_str (arr, 12, nmc_property_connection_get_secondaries (setting));
+	set_val_str (arr, 13, nmc_property_connection_get_gateway_ping_timeout (setting));
+	g_ptr_array_add (nmc->output_data, arr);
+
+	print_data (nmc);  /* Print all data */
 
 	return TRUE;
 }
 
-gboolean
-setting_vlan_details (NMSettingVlan *s_vlan, NmCli *nmc)
+static gboolean
+setting_wired_details (NMSetting *setting, NmCli *nmc, const char *one_prop)
 {
-	char *vlan_id_str, *vlan_flags_str, *vlan_ingress_prio_str, *vlan_egress_prio_str;
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+	NMSettingWired *s_wired = NM_SETTING_WIRED (setting);
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
 
-	g_return_val_if_fail (NM_IS_SETTING_VLAN (s_vlan), FALSE);
+	g_return_val_if_fail (NM_IS_SETTING_WIRED (s_wired), FALSE);
 
-	nmc->allowed_fields = nmc_fields_setting_vlan;
-	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_VLAN_ALL, nmc->allowed_fields, NULL);
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-	print_fields (nmc->print_fields, nmc->allowed_fields);  /* Print field names */
+	tmpl = nmc_fields_setting_wired;
+	tmpl_len = sizeof (nmc_fields_setting_wired);
+	nmc->print_fields.indices = parse_output_fields (one_prop ? one_prop : NMC_FIELDS_SETTING_WIRED_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);
+
+	arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+	set_val_str (arr, 0, g_strdup (nm_setting_get_name (setting)));
+	set_val_str (arr, 1, nmc_property_wired_get_port (setting));
+	set_val_str (arr, 2, nmc_property_wired_get_speed (setting));
+	set_val_str (arr, 3, nmc_property_wired_get_duplex (setting));
+	set_val_str (arr, 4, nmc_property_wired_get_auto_negotiate (setting));
+	set_val_str (arr, 5, nmc_property_wired_get_mac_address (setting));
+	set_val_str (arr, 6, nmc_property_wired_get_cloned_mac_address (setting));
+	set_val_str (arr, 7, nmc_property_wired_get_mac_address_blacklist (setting));
+	set_val_str (arr, 8, nmc_property_wired_get_mtu (setting));
+	set_val_str (arr, 9, nmc_property_wired_get_s390_subchannels (setting));
+	set_val_str (arr, 10, nmc_property_wired_get_s390_nettype (setting));
+	set_val_str (arr, 11, nmc_property_wired_get_s390_options (setting));
+	g_ptr_array_add (nmc->output_data, arr);
+
+	print_data (nmc);  /* Print all data */
 
-	vlan_id_str = g_strdup_printf ("%d", nm_setting_vlan_get_id (s_vlan));
-	vlan_flags_str = vlan_flags_to_string (nm_setting_vlan_get_flags (s_vlan));
-	vlan_ingress_prio_str = vlan_priorities_to_string (s_vlan, NM_VLAN_INGRESS_MAP);
-	vlan_egress_prio_str = vlan_priorities_to_string (s_vlan, NM_VLAN_EGRESS_MAP);
+	return TRUE;
+}
 
-	nmc->allowed_fields[0].value = NM_SETTING_VLAN_SETTING_NAME;
-	nmc->allowed_fields[1].value = nm_setting_vlan_get_interface_name (s_vlan);
-	nmc->allowed_fields[2].value = nm_setting_vlan_get_parent (s_vlan);
-	nmc->allowed_fields[3].value = vlan_id_str;
-	nmc->allowed_fields[4].value = vlan_flags_str;
-	nmc->allowed_fields[5].value = vlan_ingress_prio_str;
-	nmc->allowed_fields[6].value = vlan_egress_prio_str;
+static gboolean
+setting_802_1X_details (NMSetting *setting, NmCli *nmc, const char *one_prop)
+{
+	NMSetting8021x *s_8021x = NM_SETTING_802_1X (setting);
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
+
+	g_return_val_if_fail (NM_IS_SETTING_802_1X (s_8021x), FALSE);
+
+	tmpl = nmc_fields_setting_8021X;
+	tmpl_len = sizeof (nmc_fields_setting_8021X);
+	nmc->print_fields.indices = parse_output_fields (one_prop ? one_prop : NMC_FIELDS_SETTING_802_1X_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);
+
+	arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+	set_val_str (arr, 0, g_strdup (nm_setting_get_name (setting)));
+	set_val_str (arr, 1, nmc_property_802_1X_get_eap (setting));
+	set_val_str (arr, 2, nmc_property_802_1X_get_identity (setting));
+	set_val_str (arr, 3, nmc_property_802_1X_get_anonymous_identity (setting));
+	set_val_str (arr, 4, nmc_property_802_1X_get_pac_file (setting));
+	set_val_str (arr, 5, nmc_property_802_1X_get_ca_cert (setting));
+	set_val_str (arr, 6, nmc_property_802_1X_get_ca_path (setting));
+	set_val_str (arr, 7, nmc_property_802_1X_get_subject_match (setting));
+	set_val_str (arr, 8, nmc_property_802_1X_get_altsubject_matches (setting));
+	set_val_str (arr, 9, nmc_property_802_1X_get_client_cert (setting));
+	set_val_str (arr, 10, nmc_property_802_1X_get_phase1_peapver (setting));
+	set_val_str (arr, 11, nmc_property_802_1X_get_phase1_peaplabel (setting));
+	set_val_str (arr, 12, nmc_property_802_1X_get_phase1_fast_provisioning (setting));
+	set_val_str (arr, 13, nmc_property_802_1X_get_phase2_auth (setting));
+	set_val_str (arr, 14, nmc_property_802_1X_get_phase2_autheap (setting));
+	set_val_str (arr, 15, nmc_property_802_1X_get_phase2_ca_cert (setting));
+	set_val_str (arr, 16, nmc_property_802_1X_get_phase2_ca_path (setting));
+	set_val_str (arr, 17, nmc_property_802_1X_get_phase2_subject_match (setting));
+	set_val_str (arr, 18, nmc_property_802_1X_get_phase2_altsubject_matches (setting));
+	set_val_str (arr, 19, nmc_property_802_1X_get_phase2_client_cert (setting));
+	set_val_str (arr, 20, nmc_property_802_1X_get_password (setting));
+	set_val_str (arr, 21, nmc_property_802_1X_get_password_flags (setting));
+	set_val_str (arr, 22, nmc_property_802_1X_get_password_raw (setting));
+	set_val_str (arr, 23, nmc_property_802_1X_get_password_raw_flags (setting));
+	set_val_str (arr, 24, nmc_property_802_1X_get_private_key (setting));
+	set_val_str (arr, 25, nmc_property_802_1X_get_private_key_password (setting));
+	set_val_str (arr, 26, nmc_property_802_1X_get_private_key_password_flags (setting));
+	set_val_str (arr, 27, nmc_property_802_1X_get_phase2_private_key (setting));
+	set_val_str (arr, 28, nmc_property_802_1X_get_phase2_private_key_password (setting));
+	set_val_str (arr, 29, nmc_property_802_1X_get_phase2_private_key_password_flags (setting));
+	set_val_str (arr, 30, nmc_property_802_1X_get_pin (setting));
+	set_val_str (arr, 31, nmc_property_802_1X_get_pin_flags (setting));
+	set_val_str (arr, 32, nmc_property_802_1X_get_system_ca_certs (setting));
+	g_ptr_array_add (nmc->output_data, arr);
+
+	print_data (nmc);  /* Print all data */
 
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+	return TRUE;
+}
 
-	g_free (vlan_id_str);
-	g_free (vlan_flags_str);
-	g_free (vlan_ingress_prio_str);
-	g_free (vlan_egress_prio_str);
+static gboolean
+setting_wireless_details (NMSetting *setting, NmCli *nmc, const char *one_prop)
+{
+	NMSettingWireless *s_wireless = NM_SETTING_WIRELESS (setting);
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
+
+	g_return_val_if_fail (NM_IS_SETTING_WIRELESS (s_wireless), FALSE);
+
+	tmpl = nmc_fields_setting_wireless;
+	tmpl_len = sizeof (nmc_fields_setting_wireless);
+	nmc->print_fields.indices = parse_output_fields (one_prop ? one_prop : NMC_FIELDS_SETTING_WIRELESS_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);
+
+	arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+	set_val_str (arr, 0, g_strdup (nm_setting_get_name (setting)));
+	set_val_str (arr, 1, nmc_property_wireless_get_ssid (setting));
+	set_val_str (arr, 2, nmc_property_wireless_get_mode (setting));
+	set_val_str (arr, 3, nmc_property_wireless_get_band (setting));
+	set_val_str (arr, 4, nmc_property_wireless_get_channel (setting));
+	set_val_str (arr, 5, nmc_property_wireless_get_bssid (setting));
+	set_val_str (arr, 6, nmc_property_wireless_get_rate (setting));
+	set_val_str (arr, 7, nmc_property_wireless_get_tx_power (setting));
+	set_val_str (arr, 8, nmc_property_wireless_get_mac_address (setting));
+	set_val_str (arr, 9, nmc_property_wireless_get_cloned_mac_address (setting));
+	set_val_str (arr, 10, nmc_property_wireless_get_mac_address_blacklist (setting));
+	set_val_str (arr, 11, nmc_property_wireless_get_mtu (setting));
+	set_val_str (arr, 12, nmc_property_wireless_get_seen_bssids (setting));
+	set_val_str (arr, 13, nmc_property_wireless_get_hidden (setting));
+	g_ptr_array_add (nmc->output_data, arr);
+
+	print_data (nmc);  /* Print all data */
 
 	return TRUE;
 }
 
-gboolean
-setting_adsl_details (NMSettingAdsl *s_adsl, NmCli *nmc)
+static gboolean
+setting_wireless_security_details (NMSetting *setting, NmCli *nmc, const char *one_prop)
 {
-	char *pswd_flags;
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+	NMSettingWirelessSecurity *s_wireless_sec = NM_SETTING_WIRELESS_SECURITY (setting);
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
 
-	g_return_val_if_fail (NM_IS_SETTING_ADSL (s_adsl), FALSE);
+	g_return_val_if_fail (NM_IS_SETTING_WIRELESS_SECURITY (s_wireless_sec), FALSE);
 
-	nmc->allowed_fields = nmc_fields_setting_adsl;
-	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_ADSL_ALL, nmc->allowed_fields, NULL);
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-	print_fields (nmc->print_fields, nmc->allowed_fields);  /* Print field names */
+	tmpl = nmc_fields_setting_wireless_security;
+	tmpl_len = sizeof (nmc_fields_setting_wireless_security);
+	nmc->print_fields.indices = parse_output_fields (one_prop ? one_prop : NMC_FIELDS_SETTING_WIRELESS_SECURITY_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);
+
+	arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+	set_val_str (arr, 0, g_strdup (nm_setting_get_name (setting)));
+	set_val_str (arr, 1, nmc_property_wifi_sec_get_key_mgmt (setting));
+	set_val_str (arr, 2, nmc_property_wifi_sec_get_wep_tx_keyidx (setting));
+	set_val_str (arr, 3, nmc_property_wifi_sec_get_auth_alg (setting));
+	set_val_str (arr, 4, nmc_property_wifi_sec_get_proto (setting));
+	set_val_str (arr, 5, nmc_property_wifi_sec_get_pairwise (setting));
+	set_val_str (arr, 6, nmc_property_wifi_sec_get_group (setting));
+	set_val_str (arr, 7, nmc_property_wifi_sec_get_leap_username (setting));
+	set_val_str (arr, 8, nmc_property_wifi_sec_get_wep_key0 (setting));
+	set_val_str (arr, 9, nmc_property_wifi_sec_get_wep_key1 (setting));
+	set_val_str (arr, 10, nmc_property_wifi_sec_get_wep_key2 (setting));
+	set_val_str (arr, 11, nmc_property_wifi_sec_get_wep_key3 (setting));
+	set_val_str (arr, 12, nmc_property_wifi_sec_get_wep_key_flags (setting));
+	set_val_str (arr, 13, nmc_property_wifi_sec_get_wep_key_type (setting));
+	set_val_str (arr, 14, nmc_property_wifi_sec_get_psk (setting));
+	set_val_str (arr, 15, nmc_property_wifi_sec_get_psk_flags (setting));
+	set_val_str (arr, 16, nmc_property_wifi_sec_get_leap_password (setting));
+	set_val_str (arr, 17, nmc_property_wifi_sec_get_leap_password_flags (setting));
+	g_ptr_array_add (nmc->output_data, arr);
+
+	print_data (nmc);  /* Print all data */
 
-	pswd_flags = secret_flags_to_string (nm_setting_adsl_get_password_flags (s_adsl));
+	return TRUE;
+}
 
-	nmc->allowed_fields[0].value = NM_SETTING_ADSL_SETTING_NAME;
-	nmc->allowed_fields[1].value = nm_setting_adsl_get_username (s_adsl);
-	nmc->allowed_fields[2].value = nm_setting_adsl_get_password (s_adsl);
-	nmc->allowed_fields[3].value = pswd_flags;
-	nmc->allowed_fields[4].value = nm_setting_adsl_get_protocol (s_adsl);
-	nmc->allowed_fields[5].value = nm_setting_adsl_get_encapsulation (s_adsl);
-	nmc->allowed_fields[6].value = g_strdup_printf ("%d", nm_setting_adsl_get_vpi (s_adsl));
-	nmc->allowed_fields[7].value = g_strdup_printf ("%d", nm_setting_adsl_get_vci (s_adsl));
+static gboolean
+setting_ip4_config_details (NMSetting *setting, NmCli *nmc, const char *one_prop)
+{
+	NMSettingIP4Config *s_ip4 = NM_SETTING_IP4_CONFIG (setting);
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
 
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+	g_return_val_if_fail (NM_IS_SETTING_IP4_CONFIG (s_ip4), FALSE);
 
-	g_free (pswd_flags);
-	g_free ((char*) nmc->allowed_fields[6].value);
-	g_free ((char*) nmc->allowed_fields[7].value);
+	tmpl = nmc_fields_setting_ip4_config;
+	tmpl_len = sizeof (nmc_fields_setting_ip4_config);
+	nmc->print_fields.indices = parse_output_fields (one_prop ? one_prop : NMC_FIELDS_SETTING_IP4_CONFIG_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);
+
+	arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+	set_val_str (arr, 0, g_strdup (nm_setting_get_name (setting)));
+	set_val_str (arr, 1, nmc_property_ipv4_get_method (setting));
+	set_val_str (arr, 2, nmc_property_ipv4_get_dns (setting));
+	set_val_str (arr, 3, nmc_property_ipv4_get_dns_search (setting));
+	set_val_str (arr, 4, nmc_property_ipv4_get_addresses (setting));
+	set_val_str (arr, 5, nmc_property_ipv4_get_routes (setting));
+	set_val_str (arr, 6, nmc_property_ipv4_get_ignore_auto_routes (setting));
+	set_val_str (arr, 7, nmc_property_ipv4_get_ignore_auto_dns (setting));
+	set_val_str (arr, 8, nmc_property_ipv4_get_dhcp_client_id (setting));
+	set_val_str (arr, 9, nmc_property_ipv4_get_dhcp_send_hostname (setting));
+	set_val_str (arr, 10, nmc_property_ipv4_get_dhcp_hostname (setting));
+	set_val_str (arr, 11, nmc_property_ipv4_get_never_default (setting));
+	set_val_str (arr, 12, nmc_property_ipv4_get_may_fail (setting));
+	g_ptr_array_add (nmc->output_data, arr);
+
+	print_data (nmc);  /* Print all data */
 
 	return TRUE;
 }
 
-gboolean
-setting_bridge_details (NMSettingBridge *s_bridge, NmCli *nmc)
+static gboolean
+setting_ip6_config_details (NMSetting *setting, NmCli *nmc, const char *one_prop)
 {
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+	NMSettingIP6Config *s_ip6 = NM_SETTING_IP6_CONFIG (setting);
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
 
-	g_return_val_if_fail (NM_IS_SETTING_BRIDGE (s_bridge), FALSE);
+	g_return_val_if_fail (NM_IS_SETTING_IP6_CONFIG (s_ip6), FALSE);
+
+	tmpl = nmc_fields_setting_ip6_config;
+	tmpl_len = sizeof (nmc_fields_setting_ip6_config);
+	nmc->print_fields.indices = parse_output_fields (one_prop ? one_prop : NMC_FIELDS_SETTING_IP6_CONFIG_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);
+
+	arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+	set_val_str (arr, 0, g_strdup (nm_setting_get_name (setting)));
+	set_val_str (arr, 1, nmc_property_ipv6_get_method (setting));
+	set_val_str (arr, 2, nmc_property_ipv6_get_dns (setting));
+	set_val_str (arr, 3, nmc_property_ipv6_get_dns_search (setting));
+	set_val_str (arr, 4, nmc_property_ipv6_get_addresses (setting));
+	set_val_str (arr, 5, nmc_property_ipv6_get_routes (setting));
+	set_val_str (arr, 6, nmc_property_ipv6_get_ignore_auto_routes (setting));
+	set_val_str (arr, 7, nmc_property_ipv6_get_ignore_auto_dns (setting));
+	set_val_str (arr, 8, nmc_property_ipv6_get_never_default (setting));
+	set_val_str (arr, 9, nmc_property_ipv6_get_may_fail (setting));
+	set_val_str (arr, 10, nmc_property_ipv6_get_ip6_privacy (setting));
+	set_val_str (arr, 11, nmc_property_ipv6_get_dhcp_hostname (setting));
+	g_ptr_array_add (nmc->output_data, arr);
+
+	print_data (nmc);  /* Print all data */
+
+	return TRUE;
+}
+
+static gboolean
+setting_serial_details (NMSetting *setting, NmCli *nmc, const char *one_prop)
+{
+	NMSettingSerial *s_serial = NM_SETTING_SERIAL (setting);
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
 
-	nmc->allowed_fields = nmc_fields_setting_bridge;
-	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_BRIDGE_ALL, nmc->allowed_fields, NULL);
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-	print_fields (nmc->print_fields, nmc->allowed_fields);  /* Print field names */
+	g_return_val_if_fail (NM_IS_SETTING_SERIAL (s_serial), FALSE);
 
-	nmc->allowed_fields[0].value = NM_SETTING_BRIDGE_SETTING_NAME;
-	nmc->allowed_fields[1].value = nm_setting_bridge_get_interface_name (s_bridge);
-	nmc->allowed_fields[2].value = nm_setting_bridge_get_stp (s_bridge) ? _("yes") : _("no");
-	nmc->allowed_fields[3].value = g_strdup_printf ("%u", nm_setting_bridge_get_priority (s_bridge));
-	nmc->allowed_fields[4].value = g_strdup_printf ("%u", nm_setting_bridge_get_forward_delay (s_bridge));
-	nmc->allowed_fields[5].value = g_strdup_printf ("%u", nm_setting_bridge_get_hello_time (s_bridge));
-	nmc->allowed_fields[6].value = g_strdup_printf ("%u", nm_setting_bridge_get_max_age (s_bridge));
-	nmc->allowed_fields[7].value = g_strdup_printf ("%u", nm_setting_bridge_get_ageing_time (s_bridge));
+	tmpl = nmc_fields_setting_serial;
+	tmpl_len = sizeof (nmc_fields_setting_serial);
+	nmc->print_fields.indices = parse_output_fields (one_prop ? one_prop : NMC_FIELDS_SETTING_SERIAL_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);
 
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+	arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+	set_val_str (arr, 0, g_strdup (nm_setting_get_name (setting)));
+	set_val_str (arr, 1, nmc_property_serial_get_baud (setting));
+	set_val_str (arr, 2, nmc_property_serial_get_bits (setting));
+	set_val_str (arr, 3, nmc_property_serial_get_parity (setting));
+	set_val_str (arr, 4, nmc_property_serial_get_stopbits (setting));
+	set_val_str (arr, 5, nmc_property_serial_get_send_delay (setting));
+	g_ptr_array_add (nmc->output_data, arr);
 
-	/* free values */
-	g_free ((char*) nmc->allowed_fields[3].value);
-	g_free ((char*) nmc->allowed_fields[4].value);
-	g_free ((char*) nmc->allowed_fields[5].value);
-	g_free ((char*) nmc->allowed_fields[6].value);
-	g_free ((char*) nmc->allowed_fields[7].value);
+	print_data (nmc);  /* Print all data */
 
 	return TRUE;
 }
 
-gboolean
-setting_bridge_port_details (NMSettingBridgePort *s_bridge_port, NmCli *nmc)
+static gboolean
+setting_ppp_details (NMSetting *setting, NmCli *nmc, const char *one_prop)
+{
+	NMSettingPPP *s_ppp = NM_SETTING_PPP (setting);
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
+
+	g_return_val_if_fail (NM_IS_SETTING_PPP (s_ppp), FALSE);
+
+	tmpl = nmc_fields_setting_ppp;
+	tmpl_len = sizeof (nmc_fields_setting_ppp);
+	nmc->print_fields.indices = parse_output_fields (one_prop ? one_prop : NMC_FIELDS_SETTING_PPP_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);
+
+	arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+	set_val_str (arr, 0, g_strdup (nm_setting_get_name (setting)));
+	set_val_str (arr, 1, nmc_property_ppp_get_noauth (setting));
+	set_val_str (arr, 2, nmc_property_ppp_get_refuse_eap (setting));
+	set_val_str (arr, 3, nmc_property_ppp_get_refuse_pap (setting));
+	set_val_str (arr, 4, nmc_property_ppp_get_refuse_chap (setting));
+	set_val_str (arr, 5, nmc_property_ppp_get_refuse_mschap (setting));
+	set_val_str (arr, 6, nmc_property_ppp_get_refuse_mschapv2 (setting));
+	set_val_str (arr, 7, nmc_property_ppp_get_nobsdcomp (setting));
+	set_val_str (arr, 8, nmc_property_ppp_get_nodeflate (setting));
+	set_val_str (arr, 9, nmc_property_ppp_get_no_vj_comp (setting));
+	set_val_str (arr, 10, nmc_property_ppp_get_require_mppe (setting));
+	set_val_str (arr, 11, nmc_property_ppp_get_require_mppe_128 (setting));
+	set_val_str (arr, 12, nmc_property_ppp_get_mppe_stateful (setting));
+	set_val_str (arr, 13, nmc_property_ppp_get_crtscts (setting));
+	set_val_str (arr, 14, nmc_property_ppp_get_baud (setting));
+	set_val_str (arr, 15, nmc_property_ppp_get_mru (setting));
+	set_val_str (arr, 16, nmc_property_ppp_get_mtu (setting));
+	set_val_str (arr, 17, nmc_property_ppp_get_lcp_echo_failure (setting));
+	set_val_str (arr, 18, nmc_property_ppp_get_lcp_echo_interval (setting));
+	g_ptr_array_add (nmc->output_data, arr);
+
+	print_data (nmc);  /* Print all data */
+
+	return TRUE;
+}
+
+static gboolean
+setting_pppoe_details (NMSetting *setting, NmCli *nmc, const char *one_prop)
+{
+	NMSettingPPPOE *s_pppoe = NM_SETTING_PPPOE (setting);
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
+
+	g_return_val_if_fail (NM_IS_SETTING_PPPOE (s_pppoe), FALSE);
+
+	tmpl = nmc_fields_setting_pppoe;
+	tmpl_len = sizeof (nmc_fields_setting_pppoe);
+	nmc->print_fields.indices = parse_output_fields (one_prop ? one_prop : NMC_FIELDS_SETTING_PPPOE_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);
+
+	arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+	set_val_str (arr, 0, g_strdup (nm_setting_get_name (setting)));
+	set_val_str (arr, 1, nmc_property_pppoe_get_service (setting));
+	set_val_str (arr, 2, nmc_property_pppoe_get_username (setting));
+	set_val_str (arr, 3, nmc_property_pppoe_get_password (setting));
+	set_val_str (arr, 4, nmc_property_pppoe_get_password_flags (setting));
+	g_ptr_array_add (nmc->output_data, arr);
+
+	print_data (nmc);  /* Print all data */
+
+	return TRUE;
+}
+
+static gboolean
+setting_gsm_details (NMSetting *setting, NmCli *nmc, const char *one_prop)
+{
+	NMSettingGsm *s_gsm = NM_SETTING_GSM (setting);
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
+
+	g_return_val_if_fail (NM_IS_SETTING_GSM (s_gsm), FALSE);
+
+	tmpl = nmc_fields_setting_gsm;
+	tmpl_len = sizeof (nmc_fields_setting_gsm);
+	nmc->print_fields.indices = parse_output_fields (one_prop ? one_prop : NMC_FIELDS_SETTING_GSM_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);
+
+	arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+	set_val_str (arr, 0, g_strdup (nm_setting_get_name (setting)));
+	set_val_str (arr, 1, nmc_property_gsm_get_number (setting));
+	set_val_str (arr, 2, nmc_property_gsm_get_username (setting));
+	set_val_str (arr, 3, nmc_property_gsm_get_password (setting));
+	set_val_str (arr, 4, nmc_property_gsm_get_password_flags (setting));
+	set_val_str (arr, 5, nmc_property_gsm_get_apn (setting));
+	set_val_str (arr, 6, nmc_property_gsm_get_network_id (setting));
+	set_val_str (arr, 7, nmc_property_gsm_get_network_type (setting));
+	set_val_str (arr, 8, nmc_property_gsm_get_allowed_bands (setting));
+	set_val_str (arr, 9, nmc_property_gsm_get_pin (setting));
+	set_val_str (arr, 10, nmc_property_gsm_get_pin_flags (setting));
+	set_val_str (arr, 11, nmc_property_gsm_get_home_only (setting));
+	g_ptr_array_add (nmc->output_data, arr);
+
+	print_data (nmc);  /* Print all data */
+
+	return TRUE;
+}
+
+static gboolean
+setting_cdma_details (NMSetting *setting, NmCli *nmc, const char *one_prop)
+{
+	NMSettingCdma *s_cdma = NM_SETTING_CDMA (setting);
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
+
+	g_return_val_if_fail (NM_IS_SETTING_CDMA (s_cdma), FALSE);
+
+	tmpl = nmc_fields_setting_cdma;
+	tmpl_len = sizeof (nmc_fields_setting_cdma);
+	nmc->print_fields.indices = parse_output_fields (one_prop ? one_prop : NMC_FIELDS_SETTING_CDMA_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);
+
+	arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+	set_val_str (arr, 0, g_strdup (nm_setting_get_name (setting)));
+	set_val_str (arr, 1, nmc_property_cdma_get_number (setting));
+	set_val_str (arr, 2, nmc_property_cdma_get_username (setting));
+	set_val_str (arr, 3, nmc_property_cdma_get_password (setting));
+	set_val_str (arr, 4, nmc_property_cdma_get_password_flags (setting));
+	g_ptr_array_add (nmc->output_data, arr);
+
+	print_data (nmc);  /* Print all data */
+
+	return TRUE;
+}
+
+static gboolean
+setting_bluetooth_details (NMSetting *setting, NmCli *nmc, const char *one_prop)
+{
+	NMSettingBluetooth *s_bluetooth = NM_SETTING_BLUETOOTH (setting);
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
+
+	g_return_val_if_fail (NM_IS_SETTING_BLUETOOTH (s_bluetooth), FALSE);
+
+	tmpl = nmc_fields_setting_bluetooth;
+	tmpl_len = sizeof (nmc_fields_setting_bluetooth);
+	nmc->print_fields.indices = parse_output_fields (one_prop ? one_prop : NMC_FIELDS_SETTING_BLUETOOTH_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);
+
+	arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+	set_val_str (arr, 0, g_strdup (nm_setting_get_name (setting)));
+	set_val_str (arr, 1, nmc_property_bluetooth_get_bdaddr (setting));
+	set_val_str (arr, 2, nmc_property_bluetooth_get_type (setting));
+	g_ptr_array_add (nmc->output_data, arr);
+
+	print_data (nmc);  /* Print all data */
+
+	return TRUE;
+}
+
+static gboolean
+setting_olpc_mesh_details (NMSetting *setting, NmCli *nmc, const char *one_prop)
+{
+	NMSettingOlpcMesh *s_olpc_mesh = NM_SETTING_OLPC_MESH (setting);
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
+
+	g_return_val_if_fail (NM_IS_SETTING_OLPC_MESH (s_olpc_mesh), FALSE);
+
+	tmpl = nmc_fields_setting_olpc_mesh;
+	tmpl_len = sizeof (nmc_fields_setting_olpc_mesh);
+	nmc->print_fields.indices = parse_output_fields (one_prop ? one_prop : NMC_FIELDS_SETTING_OLPC_MESH_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);
+
+	arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+	set_val_str (arr, 0, g_strdup (nm_setting_get_name (setting)));
+	set_val_str (arr, 1, nmc_property_olpc_get_ssid (setting));
+	set_val_str (arr, 2, nmc_property_olpc_get_channel (setting));
+	set_val_str (arr, 3, nmc_property_olpc_get_anycast_address (setting));
+	g_ptr_array_add (nmc->output_data, arr);
+
+	print_data (nmc);  /* Print all data */
+
+	return TRUE;
+}
+
+static gboolean
+setting_vpn_details (NMSetting *setting, NmCli *nmc, const char *one_prop)
+{
+	NMSettingVPN *s_vpn = NM_SETTING_VPN (setting);
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
+
+	g_return_val_if_fail (NM_IS_SETTING_VPN (s_vpn), FALSE);
+
+	tmpl = nmc_fields_setting_vpn;
+	tmpl_len = sizeof (nmc_fields_setting_vpn);
+	nmc->print_fields.indices = parse_output_fields (one_prop ? one_prop : NMC_FIELDS_SETTING_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);
+
+	arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+	set_val_str (arr, 0, g_strdup (nm_setting_get_name (setting)));
+	set_val_str (arr, 1, nmc_property_vpn_get_service_type (setting));
+	set_val_str (arr, 2, nmc_property_vpn_get_user_name (setting));
+	set_val_str (arr, 3, nmc_property_vpn_get_data (setting));
+	set_val_str (arr, 4, nmc_property_vpn_get_secrets (setting));
+	g_ptr_array_add (nmc->output_data, arr);
+
+	print_data (nmc);  /* Print all data */
+
+	return TRUE;
+}
+
+static gboolean
+setting_wimax_details (NMSetting *setting, NmCli *nmc, const char *one_prop)
+{
+	NMSettingWimax *s_wimax = NM_SETTING_WIMAX (setting);
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
+
+	g_return_val_if_fail (NM_IS_SETTING_WIMAX (s_wimax), FALSE);
+
+	tmpl = nmc_fields_setting_wimax;
+	tmpl_len = sizeof (nmc_fields_setting_wimax);
+	nmc->print_fields.indices = parse_output_fields (one_prop ? one_prop : NMC_FIELDS_SETTING_WIMAX_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);
+
+	arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+	set_val_str (arr, 0, g_strdup (nm_setting_get_name (setting)));
+	set_val_str (arr, 1, nmc_property_wimax_get_mac_address (setting));
+	set_val_str (arr, 2, nmc_property_wimax_get_network_name (setting));
+	g_ptr_array_add (nmc->output_data, arr);
+
+	print_data (nmc);  /* Print all data */
+
+	return TRUE;
+}
+
+static gboolean
+setting_infiniband_details (NMSetting *setting, NmCli *nmc, const char *one_prop)
+{
+	NMSettingInfiniband *s_infiniband = NM_SETTING_INFINIBAND (setting);
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
+
+	g_return_val_if_fail (NM_IS_SETTING_INFINIBAND (s_infiniband), FALSE);
+
+	tmpl = nmc_fields_setting_infiniband;
+	tmpl_len = sizeof (nmc_fields_setting_infiniband);
+	nmc->print_fields.indices = parse_output_fields (one_prop ? one_prop : NMC_FIELDS_SETTING_INFINIBAND_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);
+
+	arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+	set_val_str (arr, 0, g_strdup (nm_setting_get_name (setting)));
+	set_val_str (arr, 1, nmc_property_ib_get_mac_address (setting));
+	set_val_str (arr, 2, nmc_property_ib_get_mtu (setting));
+	set_val_str (arr, 3, nmc_property_ib_get_transport_mode (setting));
+	set_val_str (arr, 4, nmc_property_ib_get_p_key (setting));
+	set_val_str (arr, 5, nmc_property_ib_get_parent (setting));
+	g_ptr_array_add (nmc->output_data, arr);
+
+	print_data (nmc);  /* Print all data */
+
+	return TRUE;
+}
+
+static gboolean
+setting_bond_details (NMSetting *setting, NmCli *nmc, const char *one_prop)
+{
+	NMSettingBond *s_bond = NM_SETTING_BOND (setting);
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
+
+	g_return_val_if_fail (NM_IS_SETTING_BOND (s_bond), FALSE);
+
+	tmpl = nmc_fields_setting_bond;
+	tmpl_len = sizeof (nmc_fields_setting_bond);
+	nmc->print_fields.indices = parse_output_fields (one_prop ? one_prop : NMC_FIELDS_SETTING_BOND_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);
+
+	arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+	set_val_str (arr, 0, g_strdup (nm_setting_get_name (setting)));
+	set_val_str (arr, 1, nmc_property_bond_get_interface_name (setting));
+	set_val_str (arr, 2, nmc_property_bond_get_options (setting));
+	g_ptr_array_add (nmc->output_data, arr);
+
+	print_data (nmc);  /* Print all data */
+
+	return TRUE;
+}
+
+static gboolean
+setting_vlan_details (NMSetting *setting, NmCli *nmc, const char *one_prop)
+{
+	NMSettingVlan *s_vlan = NM_SETTING_VLAN (setting);
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
+
+	g_return_val_if_fail (NM_IS_SETTING_VLAN (s_vlan), FALSE);
+
+	tmpl = nmc_fields_setting_vlan;
+	tmpl_len = sizeof (nmc_fields_setting_vlan);
+	nmc->print_fields.indices = parse_output_fields (one_prop ? one_prop : NMC_FIELDS_SETTING_VLAN_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);
+
+	arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+	set_val_str (arr, 0, g_strdup (nm_setting_get_name (setting)));
+	set_val_str (arr, 1, nmc_property_vlan_get_interface_name (setting));
+	set_val_str (arr, 2, nmc_property_vlan_get_parent (setting));
+	set_val_str (arr, 3, nmc_property_vlan_get_id (setting));
+	set_val_str (arr, 4, nmc_property_vlan_get_flags (setting));
+	set_val_str (arr, 5, nmc_property_vlan_get_ingress_priority_map (setting));
+	set_val_str (arr, 6, nmc_property_vlan_get_egress_priority_map (setting));
+	g_ptr_array_add (nmc->output_data, arr);
+
+	print_data (nmc);  /* Print all data */
+
+	return TRUE;
+}
+
+static gboolean
+setting_adsl_details (NMSetting *setting, NmCli *nmc, const char *one_prop)
+{
+	NMSettingAdsl *s_adsl = NM_SETTING_ADSL (setting);
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
+
+	g_return_val_if_fail (NM_IS_SETTING_ADSL (s_adsl), FALSE);
+
+	tmpl = nmc_fields_setting_adsl;
+	tmpl_len = sizeof (nmc_fields_setting_adsl);
+	nmc->print_fields.indices = parse_output_fields (one_prop ? one_prop : NMC_FIELDS_SETTING_ADSL_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);
+
+	arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+	set_val_str (arr, 0, g_strdup (nm_setting_get_name (setting)));
+	set_val_str (arr, 1, nmc_property_adsl_get_username (setting));
+	set_val_str (arr, 2, nmc_property_adsl_get_password (setting));
+	set_val_str (arr, 3, nmc_property_adsl_get_password_flags (setting));
+	set_val_str (arr, 4, nmc_property_adsl_get_protocol (setting));
+	set_val_str (arr, 5, nmc_property_adsl_get_encapsulation (setting));
+	set_val_str (arr, 6, nmc_property_adsl_get_vpi (setting));
+	set_val_str (arr, 7, nmc_property_adsl_get_vci (setting));
+	g_ptr_array_add (nmc->output_data, arr);
+
+	print_data (nmc);  /* Print all data */
+
+	return TRUE;
+}
+
+static gboolean
+setting_bridge_details (NMSetting *setting, NmCli *nmc, const char *one_prop)
+{
+	NMSettingBridge *s_bridge = NM_SETTING_BRIDGE (setting);
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
+
+	g_return_val_if_fail (NM_IS_SETTING_BRIDGE (s_bridge), FALSE);
+
+	tmpl = nmc_fields_setting_bridge;
+	tmpl_len = sizeof (nmc_fields_setting_bridge);
+	nmc->print_fields.indices = parse_output_fields (one_prop ? one_prop : NMC_FIELDS_SETTING_BRIDGE_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);
+
+	arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+	set_val_str (arr, 0, g_strdup (nm_setting_get_name (setting)));
+	set_val_str (arr, 1, nmc_property_bridge_get_interface_name (setting));
+	set_val_str (arr, 2, nmc_property_bridge_get_mac_address (setting));
+	set_val_str (arr, 3, nmc_property_bridge_get_stp (setting));
+	set_val_str (arr, 4, nmc_property_bridge_get_priority (setting));
+	set_val_str (arr, 5, nmc_property_bridge_get_forward_delay (setting));
+	set_val_str (arr, 6, nmc_property_bridge_get_hello_time (setting));
+	set_val_str (arr, 7, nmc_property_bridge_get_max_age (setting));
+	set_val_str (arr, 8, nmc_property_bridge_get_ageing_time (setting));
+	g_ptr_array_add (nmc->output_data, arr);
+
+	print_data (nmc);  /* Print all data */
+
+	return TRUE;
+}
+
+static gboolean
+setting_bridge_port_details (NMSetting *setting, NmCli *nmc, const char *one_prop)
 {
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+	NMSettingBridgePort *s_bridge_port = NM_SETTING_BRIDGE_PORT (setting);
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
 
 	g_return_val_if_fail (NM_IS_SETTING_BRIDGE_PORT (s_bridge_port), FALSE);
 
-	nmc->allowed_fields = nmc_fields_setting_bridge_port;
-	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_BRIDGE_PORT_ALL, nmc->allowed_fields, NULL);
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-	print_fields (nmc->print_fields, nmc->allowed_fields);  /* Print field names */
+	tmpl = nmc_fields_setting_bridge_port;
+	tmpl_len = sizeof (nmc_fields_setting_bridge_port);
+	nmc->print_fields.indices = parse_output_fields (one_prop ? one_prop : NMC_FIELDS_SETTING_BRIDGE_PORT_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);
+
+	arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+	set_val_str (arr, 0, g_strdup (nm_setting_get_name (setting)));
+	set_val_str (arr, 1, nmc_property_bridge_port_get_priority (setting));
+	set_val_str (arr, 2, nmc_property_bridge_port_get_path_cost (setting));
+	set_val_str (arr, 3, nmc_property_bridge_port_get_hairpin_mode (setting));
+	g_ptr_array_add (nmc->output_data, arr);
+
+	print_data (nmc);  /* Print all data */
+
+	return TRUE;
+}
+
+static gboolean
+setting_team_details (NMSetting *setting, NmCli *nmc, const char *one_prop)
+{
+	NMSettingTeam *s_team = NM_SETTING_TEAM (setting);
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
 
-	nmc->allowed_fields[0].value = NM_SETTING_BRIDGE_PORT_SETTING_NAME;
-	nmc->allowed_fields[1].value = g_strdup_printf ("%u", nm_setting_bridge_port_get_priority (s_bridge_port));
-	nmc->allowed_fields[2].value = g_strdup_printf ("%u", nm_setting_bridge_port_get_path_cost (s_bridge_port));
-	nmc->allowed_fields[3].value = nm_setting_bridge_port_get_hairpin_mode (s_bridge_port) ? _("yes") : _("no");
+	g_return_val_if_fail (NM_IS_SETTING_TEAM (s_team), FALSE);
 
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+	tmpl = nmc_fields_setting_team;
+	tmpl_len = sizeof (nmc_fields_setting_team);
+	nmc->print_fields.indices = parse_output_fields (one_prop ? one_prop : NMC_FIELDS_SETTING_TEAM_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);
 
-	g_free ((char*) nmc->allowed_fields[1].value);
-	g_free ((char*) nmc->allowed_fields[2].value);
+	arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+	set_val_str (arr, 0, g_strdup (nm_setting_get_name (setting)));
+	set_val_str (arr, 1, nmc_property_team_get_interface_name (setting));
+	set_val_str (arr, 2, nmc_property_team_get_config (setting));
+	g_ptr_array_add (nmc->output_data, arr);
+
+	print_data (nmc);  /* Print all data */
 
 	return TRUE;
 }
 
+static gboolean
+setting_team_port_details (NMSetting *setting, NmCli *nmc, const char *one_prop)
+{
+	NMSettingTeamPort *s_team_port = NM_SETTING_TEAM_PORT (setting);
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
+
+	g_return_val_if_fail (NM_IS_SETTING_TEAM_PORT (s_team_port), FALSE);
+
+	tmpl = nmc_fields_setting_team_port;
+	tmpl_len = sizeof (nmc_fields_setting_team_port);
+	nmc->print_fields.indices = parse_output_fields (one_prop ? one_prop : NMC_FIELDS_SETTING_TEAM_PORT_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);
+
+	arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+	set_val_str (arr, 0, g_strdup (nm_setting_get_name (setting)));
+	set_val_str (arr, 1, nmc_property_team_port_get_config (setting));
+	g_ptr_array_add (nmc->output_data, arr);
+
+	print_data (nmc);  /* Print all data */
+
+	return TRUE;
+}
+
+static gboolean
+setting_dcb_details (NMSetting *setting, NmCli *nmc, const char *one_prop)
+{
+	NMSettingDcb *s_dcb = NM_SETTING_DCB (setting);
+	NmcOutputField *tmpl, *arr;
+	size_t tmpl_len;
+
+	g_return_val_if_fail (NM_IS_SETTING_DCB (s_dcb), FALSE);
+
+	tmpl = nmc_fields_setting_dcb;
+	tmpl_len = sizeof (nmc_fields_setting_dcb);
+	nmc->print_fields.indices = parse_output_fields (one_prop ? one_prop : NMC_FIELDS_SETTING_DCB_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);
+
+	arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+	set_val_str (arr, 0, g_strdup (nm_setting_get_name (setting)));
+	set_val_str (arr, 1, nmc_property_dcb_get_app_fcoe_flags (setting));
+	set_val_str (arr, 2, nmc_property_dcb_get_app_fcoe_priority (setting));
+	set_val_str (arr, 3, nmc_property_dcb_get_app_fcoe_mode (setting));
+	set_val_str (arr, 4, nmc_property_dcb_get_app_iscsi_flags (setting));
+	set_val_str (arr, 5, nmc_property_dcb_get_app_iscsi_priority (setting));
+	set_val_str (arr, 6, nmc_property_dcb_get_app_fip_flags (setting));
+	set_val_str (arr, 7, nmc_property_dcb_get_app_fip_priority (setting));
+	set_val_str (arr, 8, nmc_property_dcb_get_pfc_flags (setting));
+	set_val_str (arr, 9, nmc_property_dcb_get_pfc (setting));
+	set_val_str (arr, 10, nmc_property_dcb_get_pg_flags (setting));
+	set_val_str (arr, 11, nmc_property_dcb_get_pg_group_id (setting));
+	set_val_str (arr, 12, nmc_property_dcb_get_pg_group_bandwidth (setting));
+	set_val_str (arr, 13, nmc_property_dcb_get_pg_bandwidth (setting));
+	set_val_str (arr, 14, nmc_property_dcb_get_pg_strict (setting));
+	set_val_str (arr, 15, nmc_property_dcb_get_pg_traffic_class (setting));
+	g_ptr_array_add (nmc->output_data, arr);
+
+	print_data (nmc);  /* Print all data */
+
+	return TRUE;
+}
+
+typedef struct {
+	const char *sname;
+	gboolean (*func) (NMSetting *setting, NmCli *nmc, const char *one_prop);
+} SettingDetails;
+
+static const SettingDetails detail_printers[] = {
+	{ NM_SETTING_CONNECTION_SETTING_NAME,        setting_connection_details },
+	{ NM_SETTING_WIRED_SETTING_NAME,             setting_wired_details },
+	{ NM_SETTING_802_1X_SETTING_NAME,            setting_802_1X_details },
+	{ NM_SETTING_WIRELESS_SETTING_NAME,          setting_wireless_details },
+	{ NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, setting_wireless_security_details },
+	{ NM_SETTING_IP4_CONFIG_SETTING_NAME,        setting_ip4_config_details },
+	{ NM_SETTING_IP6_CONFIG_SETTING_NAME,        setting_ip6_config_details },
+	{ NM_SETTING_SERIAL_SETTING_NAME,            setting_serial_details },
+	{ NM_SETTING_PPP_SETTING_NAME,               setting_ppp_details },
+	{ NM_SETTING_PPPOE_SETTING_NAME,             setting_pppoe_details },
+	{ NM_SETTING_GSM_SETTING_NAME,               setting_gsm_details },
+	{ NM_SETTING_CDMA_SETTING_NAME,              setting_cdma_details },
+	{ NM_SETTING_BLUETOOTH_SETTING_NAME,         setting_bluetooth_details },
+	{ NM_SETTING_OLPC_MESH_SETTING_NAME,         setting_olpc_mesh_details },
+	{ NM_SETTING_VPN_SETTING_NAME,               setting_vpn_details },
+	{ NM_SETTING_WIMAX_SETTING_NAME,             setting_wimax_details },
+	{ NM_SETTING_INFINIBAND_SETTING_NAME,        setting_infiniband_details },
+	{ NM_SETTING_BOND_SETTING_NAME,              setting_bond_details },
+	{ NM_SETTING_VLAN_SETTING_NAME,              setting_vlan_details },
+	{ NM_SETTING_ADSL_SETTING_NAME,              setting_adsl_details },
+	{ NM_SETTING_BRIDGE_SETTING_NAME,            setting_bridge_details },
+	{ NM_SETTING_BRIDGE_PORT_SETTING_NAME,       setting_bridge_port_details },
+	{ NM_SETTING_TEAM_SETTING_NAME,              setting_team_details },
+	{ NM_SETTING_TEAM_PORT_SETTING_NAME,         setting_team_port_details },
+	{ NM_SETTING_DCB_SETTING_NAME,               setting_dcb_details },
+	{ NULL },
+};
+
+gboolean
+setting_details (NMSetting *setting, NmCli *nmc, const char *one_prop)
+{
+	const SettingDetails *iter = &detail_printers[0];
+
+	g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
+
+	while (iter->sname) {
+		if (nm_connection_lookup_setting_type (iter->sname) == G_OBJECT_TYPE (setting))
+			return iter->func (setting, nmc, one_prop);
+		iter++;
+	}
+
+	g_assert_not_reached ();
+	return FALSE;
+}
+
diff --git a/cli/src/settings.h b/cli/src/settings.h
index 15e5577f..709c8977 100644
--- a/cli/src/settings.h
+++ b/cli/src/settings.h
@@ -14,7 +14,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * (C) Copyright 2010 - 2012 Red Hat, Inc.
+ * (C) Copyright 2010 - 2013 Red Hat, Inc.
  */
 
 #ifndef NMC_SETTINGS_H
@@ -42,33 +42,48 @@
 #include <nm-setting-bridge.h>
 #include <nm-setting-bridge-port.h>
 #include <nm-setting-vlan.h>
+#include <nm-setting-dcb.h>
 
 #include "nmcli.h"
 #include "utils.h"
 
+/* --- Functions --- */
 
-gboolean setting_details (NMSetting *ssetting, NmCli *nmc);
-gboolean setting_connection_details (NMSettingConnection *s_con, NmCli *nmc);
-gboolean setting_wired_details (NMSettingWired *s_wired, NmCli *nmc);
-gboolean setting_802_1X_details (NMSetting8021x *s_8021X, NmCli *nmc);
-gboolean setting_wireless_details (NMSettingWireless *s_wireless, NmCli *nmc);
-gboolean setting_wireless_security_details (NMSettingWirelessSecurity *s_wsec, NmCli *nmc);
-gboolean setting_ip4_config_details (NMSettingIP4Config *s_ip4, NmCli *nmc);
-gboolean setting_ip6_config_details (NMSettingIP6Config *s_ip6, NmCli *nmc);
-gboolean setting_serial_details (NMSettingSerial *s_serial, NmCli *nmc);
-gboolean setting_ppp_details (NMSettingPPP *s_ppp, NmCli *nmc);
-gboolean setting_pppoe_details (NMSettingPPPOE *s_pppoe, NmCli *nmc);
-gboolean setting_gsm_details (NMSettingGsm *s_gsm, NmCli *nmc);
-gboolean setting_cdma_details (NMSettingCdma *s_cdma, NmCli *nmc);
-gboolean setting_bluetooth_details (NMSettingBluetooth *s_bluetooth, NmCli *nmc);
-gboolean setting_olpc_mesh_details (NMSettingOlpcMesh *s_olpc_mesh, NmCli *nmc);
-gboolean setting_vpn_details (NMSettingVPN *s_vpn, NmCli *nmc);
-gboolean setting_wimax_details (NMSettingWimax *s_wimax, NmCli *nmc);
-gboolean setting_infiniband_details (NMSettingInfiniband *s_infiniband, NmCli *nmc);
-gboolean setting_bond_details (NMSettingBond *s_bond, NmCli *nmc);
-gboolean setting_vlan_details (NMSettingVlan *s_vlan, NmCli *nmc);
-gboolean setting_adsl_details (NMSettingAdsl *s_adsl, NmCli *nmc);
-gboolean setting_bridge_details (NMSettingBridge *s_bridge, NmCli *nmc);
-gboolean setting_bridge_port_details (NMSettingBridgePort *s_bridge_port, NmCli *nmc);
+void nmc_properties_init (void);
+void nmc_properties_cleanup (void);
+
+NMSetting *nmc_setting_new_for_name (const char *name);
+void nmc_setting_custom_init (NMSetting *setting);
+void nmc_setting_ip4_connect_handlers (NMSettingIP4Config *setting);
+void nmc_setting_ip6_connect_handlers (NMSettingIP6Config *setting);
+void nmc_setting_wireless_connect_handlers (NMSettingWireless *setting);
+
+char      **nmc_setting_get_valid_properties (NMSetting *setting);
+char       *nmc_setting_get_property_desc (NMSetting *setting, const char *prop);
+const char *nmc_setting_get_property_allowed_values (NMSetting *setting, const char *prop);
+char       *nmc_setting_get_property (NMSetting *setting,
+                                      const char *prop,
+                                      GError **error);
+char       *nmc_setting_get_property_out2in (NMSetting *setting,
+                                             const char *prop,
+                                             GError **error);
+gboolean    nmc_setting_set_property (NMSetting *setting,
+                                      const char *prop,
+                                      const char *val,
+                                      GError **error);
+gboolean    nmc_setting_reset_property (NMSetting *setting,
+                                        const char *prop,
+                                        GError **error);
+gboolean    nmc_setting_remove_property_option (NMSetting *setting,
+                                                const char *prop,
+                                                const char *option,
+                                                guint32 idx,
+                                                GError **error);
+void nmc_property_set_default_value (NMSetting *setting, const char *prop);
+
+gboolean nmc_property_get_gvalue (NMSetting *setting, const char *prop, GValue *value);
+gboolean nmc_property_set_gvalue (NMSetting *setting, const char *prop, GValue *value);
+
+gboolean setting_details (NMSetting *ssetting, NmCli *nmc, const char *one_prop);
 
 #endif /* NMC_SETTINGS_H */
diff --git a/cli/src/utils.c b/cli/src/utils.c
index ab0a5dba..9b513f5a 100644
--- a/cli/src/utils.c
+++ b/cli/src/utils.c
@@ -14,7 +14,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * (C) Copyright 2010 - 2012 Red Hat, Inc.
+ * (C) Copyright 2010 - 2014 Red Hat, Inc.
  */
 
 /* Generated configuration file */
@@ -22,6 +22,8 @@
 
 #include <stdio.h>
 #include <string.h>
+#include <stdlib.h>
+#include <errno.h>
 
 #include <sys/socket.h>
 #include <netinet/in.h>
@@ -36,8 +38,8 @@
 int
 matches (const char *cmd, const char *pattern)
 {
-	int len = strlen (cmd);
-	if (len > strlen (pattern))
+	size_t len = strlen (cmd);
+	if (!len || len > strlen (pattern))
 		return -1;
 	return memcmp (pattern, cmd, len);
 }
@@ -57,14 +59,116 @@ next_arg (int *argc, char ***argv)
 	return 0;
 }
 
+gboolean
+nmc_arg_is_help (const char *arg)
+{
+	if (!arg)
+		return FALSE;
+	if (   matches (arg, "help") == 0
+	    || (g_str_has_prefix (arg, "-")  && matches (arg+1, "help") == 0)
+	    || (g_str_has_prefix (arg, "--") && matches (arg+2, "help") == 0)) {
+		return TRUE;
+	}
+	return FALSE;
+}
+
+gboolean
+nmc_arg_is_option (const char *str, const char *opt_name)
+{
+	const char *p;
+
+	if (!str || !*str)
+		return FALSE;
+
+	if (str[0] != '-')
+		return FALSE;
+
+	p = (str[1] == '-') ? str + 2 : str + 1;
+
+	return (*p ? (matches (p, opt_name) == 0) : FALSE);
+}
+
+
 /*
- *  Convert SSID to a printable form.
- *  If it is an UTF-8 string, enclose it in quotes and return it.
- *  Otherwise convert it to a hex string representation.
+ * Helper function to parse command-line arguments.
+ * arg_arr: description of arguments to look for
+ * last:    whether these are last expected arguments
+ * argc:    command-line argument array
+ * argv:    command-line argument array size
+ * error:   error set on a failure (when FALSE is returned)
+ * Returns: TRUE on success, FALSE on an error and sets 'error'
+ */
+gboolean
+nmc_parse_args (nmc_arg_t *arg_arr, gboolean last, int *argc, char ***argv, GError **error)
+{
+	nmc_arg_t *p;
+	gboolean found;
+	gboolean have_mandatory;
+
+	g_return_val_if_fail (arg_arr != NULL, FALSE);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	while (*argc > 0) {
+		found = FALSE;
+
+		for (p = arg_arr; p->name; p++) {
+			if (strcmp (**argv, p->name) == 0) {
+
+				if (p->found) {
+					/* Don't allow repeated arguments, because the argument of the same
+					 * name could be used later on the line for another purpose. Assume
+					 * that's the case and return.
+					 */
+					return TRUE;
+				}
+
+				if (p->has_value) {
+					if (next_arg (argc, argv) != 0) {
+						g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+						             _("Error: value for '%s' argument is required."), *(*argv-1));
+						return FALSE;
+					}
+					*(p->value) = **argv;
+				}
+				p->found = TRUE;
+				found = TRUE;
+				break;
+			}
+		}
+
+		if (!found) {
+			have_mandatory = TRUE;
+			for (p = arg_arr; p->name; p++) {
+				if (p->mandatory && !p->found) {
+					have_mandatory = FALSE;
+					break;
+				}
+			}
+
+			if (have_mandatory && !last)
+				return TRUE;
+
+			if (p->name)
+				g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+				             _("Error: Argument '%s' was expected, but '%s' provided."), p->name, **argv);
+			else
+				g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+				             _("Error: Unexpected argument '%s'"), **argv);
+			return FALSE;
+		}
+
+		next_arg (argc, argv);
+	}
+
+	return TRUE;
+}
+
+/*
+ *  Convert SSID to a hex string representation.
  *  Caller has to free the returned string using g_free()
  */
 char *
-ssid_to_printable (const char *str, gsize len)
+ssid_to_hex (const char *str, gsize len)
 {
 	GString *printable;
 	char *printable_str;
@@ -73,9 +177,6 @@ ssid_to_printable (const char *str, gsize len)
 	if (str == NULL || len == 0)
 		return NULL;
 
-	if (g_utf8_validate (str, len, NULL))
-		return g_strdup_printf ("'%.*s'", (int) len, str);
-
 	printable = g_string_new (NULL);
 	for (i = 0; i < len; i++) {
 		g_string_append_printf (printable, "%02X", (unsigned char) str[i]);
@@ -91,19 +192,19 @@ ssid_to_printable (const char *str, gsize len)
 char *
 nmc_ip4_address_as_string (guint32 ip, GError **error)
 {
-	struct in_addr tmp_addr;
+	guint32 tmp_addr;
 	char buf[INET_ADDRSTRLEN];
 
 	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
 
 	memset (&buf, '\0', sizeof (buf));
-	tmp_addr.s_addr = ip;
+	tmp_addr = ip;
 
 	if (inet_ntop (AF_INET, &tmp_addr, buf, INET_ADDRSTRLEN)) {
 		return g_strdup (buf);
 	} else {
 		g_set_error (error, NMCLI_ERROR, 0, _("Error converting IP4 address '0x%X' to text form"),
-		             ntohl (tmp_addr.s_addr));
+		             ntohl (tmp_addr));
 		return NULL;
 	}
 }
@@ -170,6 +271,298 @@ nmc_terminal_show_progress (const char *str)
 		idx = 0;
 }
 
+const char *
+nmc_term_color_sequence (NmcTermColor color)
+{
+	switch (color) {
+        case NMC_TERM_COLOR_BLACK:
+		return "\33[30m";
+		break;
+        case NMC_TERM_COLOR_RED:
+		return "\33[31m";
+		break;
+        case NMC_TERM_COLOR_GREEN:
+		return "\33[32m";
+		break;
+        case NMC_TERM_COLOR_YELLOW:
+		return "\33[33m";
+		break;
+        case NMC_TERM_COLOR_BLUE:
+		return "\33[34m";
+		break;
+        case NMC_TERM_COLOR_MAGENTA:
+		return "\33[35m";
+		break;
+        case NMC_TERM_COLOR_CYAN:
+		return "\33[36m";
+		break;
+        case NMC_TERM_COLOR_WHITE:
+		return "\33[37m";
+		break;
+	default:
+		return "";
+		break;
+	}
+}
+
+char *
+nmc_colorize (NmcTermColor color, const char *fmt, ...)
+{
+	va_list args;
+	char *str, *colored;
+	const char *ansi_color, *color_end;
+
+	va_start (args, fmt);
+	str = g_strdup_vprintf (fmt, args);
+	va_end (args);
+
+	ansi_color = nmc_term_color_sequence (color);
+	if (*ansi_color)
+		color_end = "\33[0m";
+	else
+		color_end = "";
+
+	colored = g_strdup_printf ("%s%s%s", ansi_color, str, color_end);
+	g_free (str);
+	return colored;
+}
+
+/*
+ * Convert string to signed integer.
+ * If required, the resulting number is checked to be in the <min,max> range.
+ */
+gboolean
+nmc_string_to_int_base (const char *str,
+                        int base,
+                        gboolean range_check,
+                        long int min,
+                        long int max,
+                        long int *value)
+{
+	char *end;
+	long int tmp;
+
+	errno = 0;
+	tmp = strtol (str, &end, base);
+	if (errno || *end != '\0' || (range_check && (tmp < min || tmp > max))) {
+		return FALSE;
+	}
+	*value = tmp;
+	return TRUE;
+}
+
+/*
+ * Convert string to unsigned integer.
+ * If required, the resulting number is checked to be in the <min,max> range.
+ */
+gboolean
+nmc_string_to_uint_base (const char *str,
+                         int base,
+                         gboolean range_check,
+                         unsigned long int min,
+                         unsigned long int max,
+                         unsigned long int *value)
+{
+	char *end;
+	unsigned long int tmp;
+
+	errno = 0;
+	tmp = strtoul (str, &end, base);
+	if (errno || *end != '\0' || (range_check && (tmp < min || tmp > max))) {
+		return FALSE;
+	}
+	*value = tmp;
+	return TRUE;
+}
+
+gboolean
+nmc_string_to_int (const char *str,
+                   gboolean range_check,
+                   long int min,
+                   long int max,
+                   long int *value)
+{
+	return nmc_string_to_int_base (str, 10, range_check, min, max, value);
+}
+
+gboolean
+nmc_string_to_uint (const char *str,
+                    gboolean range_check,
+                    unsigned long int min,
+                    unsigned long int max,
+                    unsigned long int *value)
+{
+	return nmc_string_to_uint_base (str, 10, range_check, min, max, value);
+}
+
+gboolean
+nmc_string_to_bool (const char *str, gboolean *val_bool, GError **error)
+{
+	const char *s_true[] = { "true", "yes", "on", NULL };
+	const char *s_false[] = { "false", "no", "off", NULL };
+
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	if (g_strcmp0 (str, "o") == 0) {
+		g_set_error (error, 1, 0,
+		             _("'%s' is ambiguous (on x off)"), str);
+		return FALSE;
+	}
+
+	if (nmc_string_is_valid (str, s_true, NULL))
+		*val_bool = TRUE;
+	else if (nmc_string_is_valid (str, s_false, NULL))
+		*val_bool = FALSE;
+	else {
+		g_set_error (error, 1, 0,
+		             _("'%s' is not valid; use [%s] or [%s]"),
+		             str, "true, yes, on", "false, no, off");
+		return FALSE;
+	}
+	return TRUE;
+}
+
+/*
+ * Ask user for input and return the string.
+ * The caller is responsible for freeing the returned string.
+ */
+char *
+nmc_get_user_input (const char *ask_str)
+{
+	char *line = NULL;
+	size_t line_ln = 0;
+	ssize_t num;
+
+	fprintf (stdout, "%s", ask_str);
+	num = getline (&line, &line_ln, stdin);
+
+	/* Remove newline from the string */
+	if (num < 1 || (num == 1 && line[0] == '\n')) {
+		g_free (line);
+		line = NULL;
+	} else {
+		if (line[num-1] == '\n')
+			line[num-1] = '\0';
+	}
+
+	return line;
+}
+
+/*
+ * Split string in 'line' according to 'delim' to (argument) array.
+ */
+int
+nmc_string_to_arg_array (const char *line, const char *delim, char ***argv, int *argc)
+{
+	int i = 0;
+	char **arr;
+
+	arr = g_strsplit_set (line ? line : "", delim ? delim : " \t", 0);
+	while (arr && arr[i])
+		i++;
+
+	*argc = i;
+	*argv = arr;
+
+	return 0;
+}
+
+/*
+ * Check whether 'input' is contained in 'allowed' array. It performs case
+ * insensitive comparison and supports shortcut strings if they are unique.
+ * Returns: a pointer to found string in allowed array on success or NULL.
+ * On failure: error->code : 0 - string not found; 1 - string is ambiguous
+ */
+const char *
+nmc_string_is_valid (const char *input, const char **allowed, GError **error)
+{
+	const char **p;
+	size_t input_ln, p_len;
+	gboolean prev_match = FALSE;
+	const char *ret = NULL;
+
+	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+	if (!input || !*input)
+		goto finish;
+
+	input_ln = strlen (input);
+	for (p = allowed; p && *p; p++) {
+		p_len = strlen (*p);
+		if (g_ascii_strncasecmp (input, *p, input_ln) == 0) {
+			if (input_ln == p_len) {
+				ret = *p;
+				break;
+			}
+			if (!prev_match)
+				ret = *p;
+			else {
+				g_set_error (error, 1, 1, _("'%s' is ambiguous (%s x %s)"),
+				             input, ret, *p);
+				return NULL;
+			}
+			prev_match = TRUE;
+		}
+	}
+
+finish:
+	if (ret == NULL) {
+		char *valid_vals = g_strjoinv (", ", (char **) allowed);
+		if (!input || !*input) {
+			g_set_error (error, 1, 0, _("missing name, try one of [%s]"),
+			             valid_vals);
+		} else {
+			g_set_error (error, 1, 0, _("'%s' not among [%s]"),
+			             input ? input : "", valid_vals);
+		}
+
+		g_free (valid_vals);
+	}
+	return ret;
+}
+
+/*
+ * Convert string array (char **) to GSList.
+ *
+ * Returns: pointer to newly created GSList. Caller should free it.
+ */
+GSList *
+nmc_util_strv_to_slist (char **strv)
+{
+	GSList *list = NULL;
+	guint i = 0;
+
+	while (strv && strv[i])
+		list = g_slist_prepend (list, g_strdup (strv[i++]));
+
+	return g_slist_reverse (list);
+}
+
+/*
+ * Wrapper function for g_strsplit_set() that removes empty strings
+ * from the vector as they are not useful in most cases.
+ */
+char **
+nmc_strsplit_set (const char *str, const char *delimiter, int max_tokens)
+{
+	char **result;
+	uint i;
+	uint j;
+
+	result = g_strsplit_set (str, delimiter, max_tokens);
+
+	/* remove empty strings */
+	for (i = 0; result && result[i]; i++) {
+		if (*(result[i]) == '\0') {
+			g_free (result[i]);
+			for (j = i; result[j]; j++)
+				result[j] = result[j + 1];
+			i--;
+		}
+	}
+	return result;
+}
+
 /*
  * Find out how many columns an UTF-8 string occupies on the screen
  */
@@ -189,54 +582,165 @@ nmc_string_screen_width (const char *start, const char *end)
 }
 
 void
-set_val_str (NmcOutputField fields_array[], guint32 idx, const char *value)
+set_val_str (NmcOutputField fields_array[], guint32 idx, char *value)
 {
-	fields_array[idx].flags = 0;
 	fields_array[idx].value = value;
+	fields_array[idx].value_is_array = FALSE;
+	fields_array[idx].free_value = TRUE;
 }
 
 void
-set_val_arr (NmcOutputField fields_array[], guint32 idx, const char **value)
+set_val_strc (NmcOutputField fields_array[], guint32 idx, const char *value)
+{
+	fields_array[idx].value = (char *) value;
+	fields_array[idx].value_is_array = FALSE;
+	fields_array[idx].free_value = FALSE;
+}
+
+void
+set_val_arr (NmcOutputField fields_array[], guint32 idx, char **value)
 {
-	fields_array[idx].flags = NMC_OF_FLAG_ARRAY;
 	fields_array[idx].value = value;
+	fields_array[idx].value_is_array = TRUE;
+	fields_array[idx].free_value = TRUE;
+}
+
+void
+set_val_arrc (NmcOutputField fields_array[], guint32 idx, const char **value)
+{
+	fields_array[idx].value = (char **) value;
+	fields_array[idx].value_is_array = TRUE;
+	fields_array[idx].free_value = FALSE;
 }
 
 /*
- * Parse comma separated fields in 'fields_str' according to 'fields_array'.
- * IN:  'field_str':    comma-separated fields names
- *      'fields_array': array of allowed fields
- * RETURN: GArray with indices representing fields in 'fields_array'.
- *         Caller is responsible to free it.
+ * Free 'value' members in array of NmcOutputField
+ */
+void
+nmc_free_output_field_values (NmcOutputField fields_array[])
+{
+	NmcOutputField *iter = fields_array;
+
+	while (iter && iter->name) {
+		if (iter->free_value) {
+			if (iter->value_is_array)
+				g_strfreev ((char **) iter->value);
+			else
+				g_free ((char *) iter->value);
+			iter->value = NULL;
+		}
+		iter++;
+	}
+}
+
+/**
+ * parse_output_fields:
+ * @field_str: comma-separated field names to parse
+ * @fields_array: array of allowed fields
+ * @parse_groups: whether the fields can contain group prefix (e.g. general.driver)
+ * @group_fields: (out) (allow-none): array of field names for particular groups
+ * @error: (out) (allow-none): location to store error, or %NULL
+ *
+ * Parses comma separated fields in @fields_str according to @fields_array.
+ * When @parse_groups is %TRUE, fields can be in the form 'group.field'. Then
+ * @group_fields will be filled with the required field for particular group.
+ * @group_fields array corresponds to the returned array.
+ * Examples:
+ *   @field_str:     "type,name,uuid" | "ip4,general.device" | "ip4.address,ip6"
+ *   returned array:   2    0    1    |   7         0        |     7         9
+ *   @group_fields:   NULL NULL NULL  |  NULL    "device"    | "address"    NULL
+ *
+ * Returns: #GArray with indices representing fields in @fields_array.
+ *   Caller is responsible for freeing the array.
  */
 GArray *
-parse_output_fields (const char *fields_str, const NmcOutputField fields_array[], GError **error)
+parse_output_fields (const char *fields_str,
+                     const NmcOutputField fields_array[],
+                     gboolean parse_groups,
+                     GPtrArray **group_fields,
+                     GError **error)
 {
 	char **fields, **iter;
 	GArray *array;
-	int i;
+	int i, j;
 
 	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+	g_return_val_if_fail (group_fields == NULL || *group_fields == NULL, NULL);
 
 	array = g_array_new (FALSE, FALSE, sizeof (int));
+	if (parse_groups && group_fields)
+		*group_fields = g_ptr_array_new_full (20, (GDestroyNotify) g_free);
 
 	/* Split supplied fields string */
 	fields = g_strsplit_set (fields_str, ",", -1);
 	for (iter = fields; iter && *iter; iter++) {
-		for (i = 0; fields_array[i].name; i++) {
-			if (strcasecmp (*iter, fields_array[i].name) == 0) {
-				g_array_append_val (array, i);
-				break;
+		int idx = -1;
+
+		g_strstrip (*iter);
+		if (parse_groups) {
+			/* e.g. "general.device,general.driver,ip4,ip6" */
+			gboolean found = FALSE;
+			char *left = *iter;
+			char *right = strchr (*iter, '.');
+
+			if (right)
+				*right++ = '\0';
+
+			for (i = 0; fields_array[i].name; i++) {
+				if (strcasecmp (left, fields_array[i].name) == 0) {
+					NmcOutputField *valid_names = fields_array[i].group;
+					idx = i;
+					if (!right && !valid_names) {
+						found = TRUE;
+						break;
+					}
+					for (j = 0; valid_names && valid_names[j].name; j++) {
+						if (!right || strcasecmp (right, valid_names[j].name) == 0) {
+							found = TRUE;
+							break;
+						}
+					}
+				}
+				if (found)
+					break;
+			}
+			if (found) {
+				/* Add index to array, and field name (or NULL) to group_fields array */
+				g_array_append_val (array, idx);
+				if (group_fields && *group_fields)
+					g_ptr_array_add (*group_fields, g_strdup (right));
+			}
+			if (right)
+				*(right-1) = '.';  /* Restore the original string */
+		} else {
+			/* e.g. "general,ip4,ip6" */
+			for (i = 0; fields_array[i].name; i++) {
+				if (strcasecmp (*iter, fields_array[i].name) == 0) {
+					g_array_append_val (array, i);
+					break;
+				}
 			}
 		}
+
+		/* Field was not found - error case */
 		if (fields_array[i].name == NULL) {
+			/* Set GError */
 			if (!strcasecmp (*iter, "all") || !strcasecmp (*iter, "common"))
 				g_set_error (error, NMCLI_ERROR, 0, _("field '%s' has to be alone"), *iter);
+			else {
+				char *allowed_fields = nmc_get_allowed_fields (fields_array, idx);
+				g_set_error (error, NMCLI_ERROR, 1, _("invalid field '%s'; allowed fields: %s"),
+				             *iter, allowed_fields);
+				g_free (allowed_fields);
+			}
 
-			else
-				g_set_error (error, NMCLI_ERROR, 1, _("invalid field '%s'"), *iter);
+			/* Free arrays on error */
 			g_array_free (array, TRUE);
 			array = NULL;
+			if (group_fields && *group_fields) {
+				g_ptr_array_free (*group_fields, TRUE);
+				*group_fields = NULL;
+			}
 			goto done;
 		}
 	}
@@ -246,6 +750,35 @@ done:
 	return array;
 }
 
+/**
+* nmc_get_allowed_fields:
+* @fields_array: array of fields
+* @group_idx: index to the array (for second-level array in 'group' member),
+*   or -1
+*
+* Returns: string of allowed fields names.
+*   Caller is responsible for freeing the array.
+*/
+char *
+nmc_get_allowed_fields (const NmcOutputField fields_array[], int group_idx)
+{
+	GString *allowed_fields = g_string_sized_new (256);
+	int i;
+
+	if (group_idx != -1 && fields_array[group_idx].group) {
+		NmcOutputField *second_level = fields_array[group_idx].group;
+		for (i = 0; second_level[i].name; i++)
+			g_string_append_printf (allowed_fields, "%s.%s,",
+			                        fields_array[group_idx].name, second_level[i].name);
+	} else {
+		for (i = 0; fields_array[i].name; i++)
+			g_string_append_printf (allowed_fields, "%s,", fields_array[i].name);
+	}
+	g_string_truncate (allowed_fields, allowed_fields->len - 1);
+
+	return g_string_free (allowed_fields, FALSE);
+}
+
 gboolean
 nmc_terse_option_check (NMCPrintOutput print_output, const char *fields, GError **error)
 {
@@ -264,14 +797,68 @@ nmc_terse_option_check (NMCPrintOutput print_output, const char *fields, GError
 	return TRUE;
 }
 
+NmcOutputField *
+nmc_dup_fields_array (NmcOutputField fields[], size_t size, guint32 flags)
+{
+	NmcOutputField *row;
+
+	row = g_malloc0 (size);
+	memcpy (row, fields, size);
+	row[0].flags = flags;
+
+	return row;
+}
+
+void
+nmc_empty_output_fields (NmCli *nmc)
+{
+	guint i;
+
+	/* Free values in field structure */
+	for (i = 0; i < nmc->output_data->len; i++) {
+		NmcOutputField *fld_arr = g_ptr_array_index (nmc->output_data, i);
+		nmc_free_output_field_values (fld_arr);
+	}
+
+	/* Empty output_data array */
+	if (nmc->output_data->len > 0)
+		g_ptr_array_remove_range (nmc->output_data, 0, nmc->output_data->len);
+
+	if (nmc->print_fields.indices) {
+		g_array_free (nmc->print_fields.indices, TRUE);
+		nmc->print_fields.indices = NULL;
+	}
+}
+
+static char *
+get_value_to_print (NmcOutputField *fields,
+                    gboolean field_name,
+                    const char *not_set_str,
+                    gboolean *dealloc)
+{
+	gboolean is_array = fields->value_is_array;
+	char *value;
+
+	if (field_name)
+		value = _(fields->name_l10n);
+	else
+		value = fields->value ?
+		          (is_array ? g_strjoinv (" | ", (char **) fields->value) :
+		                      (char *) fields->value) :
+		          (char *) not_set_str;
+	*dealloc = fields->value && is_array && !field_name;
+	return value;
+}
+
 /*
  * Print both headers or values of 'field_values' array.
- * Entries to print and their order are specified via indices
- * in 'fields.indices' array.
- * 'fields.flags' specify various aspects influencing the output.
+ * Entries to print and their order are specified via indices in
+ * 'nmc->print_fields.indices' array.
+ * Various flags influencing the output of fields are set up in the first item
+ * of 'field_values' array.
  */
 void
-print_fields (const NmcPrintFields fields, const NmcOutputField field_values[])
+print_required_fields (NmCli *nmc, const NmcOutputField field_values[])
 {
 	GString *str;
 	int width1, width2;
@@ -280,14 +867,15 @@ print_fields (const NmcPrintFields fields, const NmcOutputField field_values[])
 	char *indent_str;
 	const char *not_set_str = "--";
 	int i;
-	gboolean multiline = fields.flags & NMC_PF_FLAG_MULTILINE;
-	gboolean terse = fields.flags & NMC_PF_FLAG_TERSE;
-	gboolean pretty = fields.flags & NMC_PF_FLAG_PRETTY;
-	gboolean main_header_add = fields.flags & NMC_PF_FLAG_MAIN_HEADER_ADD;
-	gboolean main_header_only = fields.flags & NMC_PF_FLAG_MAIN_HEADER_ONLY;
-	gboolean field_names = fields.flags & NMC_PF_FLAG_FIELD_NAMES;
-	gboolean escape = fields.flags & NMC_PF_FLAG_ESCAPE;
-	gboolean section_prefix = fields.flags & NMC_PF_FLAG_SECTION_PREFIX;
+	const NmcPrintFields fields = nmc->print_fields;
+	gboolean multiline = nmc->multiline_output;
+	gboolean terse = (nmc->print_output == NMC_PRINT_TERSE);
+	gboolean pretty = (nmc->print_output == NMC_PRINT_PRETTY);
+	gboolean escape = nmc->escape_values;
+	gboolean main_header_add = field_values[0].flags & NMC_OF_FLAG_MAIN_HEADER_ADD;
+	gboolean main_header_only = field_values[0].flags & NMC_OF_FLAG_MAIN_HEADER_ONLY;
+	gboolean field_names = field_values[0].flags & NMC_OF_FLAG_FIELD_NAMES;
+	gboolean section_prefix = field_values[0].flags & NMC_OF_FLAG_SECTION_PREFIX;
 	gboolean main_header = main_header_add || main_header_only;
 
 	/* No headers are printed in terse mode:
@@ -319,25 +907,29 @@ print_fields (const NmcPrintFields fields, const NmcOutputField field_values[])
 			for (i = 0; i < fields.indices->len; i++) {
 				char *tmp;
 				int idx = g_array_index (fields.indices, int, i);
-				guint32 value_is_array = field_values[idx].flags & NMC_OF_FLAG_ARRAY;
+				gboolean is_array = field_values[idx].value_is_array;
 
 				/* section prefix can't be an array */
-				g_assert (!value_is_array || !section_prefix || idx != 0);
+				g_assert (!is_array || !section_prefix || idx != 0);
 
 				if (section_prefix && idx == 0)  /* The first field is section prefix */
 					continue;
 
-				if (value_is_array) {
+				if (is_array) {
 					/* value is a null-terminated string array */
 					const char **p;
 					int j;
 
 					for (p = (const char **) field_values[idx].value, j = 1; p && *p; p++, j++) {
-						tmp = g_strdup_printf ("%s%s%s[%d]:", section_prefix ? (const char*) field_values[0].value : "",
-						                                      section_prefix ? "." : "",
-						                                      _(field_values[idx].name_l10n),
-						                                      j);
-						printf ("%-*s%s\n", terse ? 0 : ML_VALUE_INDENT, tmp, *p ? *p : not_set_str);
+						tmp = g_strdup_printf ("%s%s%s[%d]:",
+						                       section_prefix ? (const char*) field_values[0].value : "",
+						                       section_prefix ? "." : "",
+						                       _(field_values[idx].name_l10n),
+						                       j);
+						width1 = strlen (tmp);
+						width2 = nmc_string_screen_width (tmp, NULL);
+						printf ("%-*s%s\n", terse ? 0 : ML_VALUE_INDENT+width1-width2, tmp,
+						                    *p ? *p : not_set_str);
 						g_free (tmp);
 					}
 				} else {
@@ -345,10 +937,14 @@ print_fields (const NmcPrintFields fields, const NmcOutputField field_values[])
 					const char *hdr_name = (const char*) field_values[0].value;
 					const char *val = (const char*) field_values[idx].value;
 
-					tmp = g_strdup_printf ("%s%s%s:", section_prefix ? hdr_name : "",
-					                                  section_prefix ? "." : "",
-					                                  _(field_values[idx].name_l10n));
-					printf ("%-*s%s\n", terse ? 0 : ML_VALUE_INDENT, tmp, val ? val : not_set_str);
+					tmp = g_strdup_printf ("%s%s%s:",
+					                       section_prefix ? hdr_name : "",
+					                       section_prefix ? "." : "",
+					                       _(field_values[idx].name_l10n));
+					width1 = strlen (tmp);
+					width2 = nmc_string_screen_width (tmp, NULL);
+					printf ("%-*s%s\n", terse ? 0 : ML_VALUE_INDENT+width1-width2, tmp,
+					                    val ? val : not_set_str);
 					g_free (tmp);
 				}
 			}
@@ -366,14 +962,8 @@ print_fields (const NmcPrintFields fields, const NmcOutputField field_values[])
 
 	for (i = 0; i < fields.indices->len; i++) {
 		int idx = g_array_index (fields.indices, int, i);
-		guint32 value_is_array = field_values[idx].flags & NMC_OF_FLAG_ARRAY;
-		char *value;
-		if (field_names)
-			value = _(field_values[idx].name_l10n);
-		else
-			value = field_values[idx].value ?
-			        (value_is_array ? g_strjoinv (" | ", (char **) field_values[idx].value) : (char *) field_values[idx].value) :
-			        (char *) not_set_str;
+		gboolean dealloc;
+		char *value = get_value_to_print ((NmcOutputField *) field_values+idx, field_names, not_set_str, &dealloc);
 
 		if (terse) {
 			if (escape) {
@@ -396,7 +986,7 @@ print_fields (const NmcPrintFields fields, const NmcOutputField field_values[])
 			table_width += field_values[idx].width + width1 - width2 + 1;
 		}
 
-		if (value_is_array && field_values[idx].value && !field_values)
+		if (dealloc)
 			g_free (value);
 	}
 
@@ -438,57 +1028,56 @@ print_fields (const NmcPrintFields fields, const NmcOutputField field_values[])
 }
 
 /*
- * Find out whether NetworkManager is running (via D-Bus NameHasOwner), assuring
- * NetworkManager won't be autostart (by D-Bus) if not running.
- * We can't use NMClient (nm_client_get_manager_running()) because NMClient
- * constructor calls GetPermissions of NM_DBUS_SERVICE, which would autostart
- * NetworkManger if it is configured as D-Bus launchable service.
+ * Print nmc->output_data
+ *
+ * It first finds out maximal string length in columns and fill the value to
+ * 'width' member of NmcOutputField, so that columns in tabular output are
+ * properly aligned. Then each object (row in tabular) is printed using
+ * print_required_fields() function.
  */
-gboolean
-nmc_is_nm_running (NmCli *nmc, GError **error)
+void
+print_data (NmCli *nmc)
 {
-	DBusGConnection *connection = NULL;
-	DBusGProxy *proxy = NULL;
-	GError *err = NULL;
-	gboolean has_owner = FALSE;
+	int i, j;
+	size_t len;
+	NmcOutputField *row;
+	int num_fields = 0;
 
-	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+	if (!nmc->output_data || nmc->output_data->len < 1)
+		return;
 
-	connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &err);
-	if (!connection) {
-		g_string_printf (nmc->return_text, _("Error: Couldn't connect to system bus: %s"), err->message);
-		nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
-		g_propagate_error (error, err);
-		goto done;
+	/* How many fields? */
+	row = g_ptr_array_index (nmc->output_data, 0);
+	while (row->name) {
+		num_fields++;
+		row++;
 	}
 
-	proxy = dbus_g_proxy_new_for_name (connection,
-	                                   "org.freedesktop.DBus",
-	                                   "/org/freedesktop/DBus",
-	                                   "org.freedesktop.DBus");
-	if (!proxy) {
-		g_string_printf (nmc->return_text, _("Error: Couldn't create D-Bus object proxy for org.freedesktop.DBus"));
-		nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
-		if (error)
-			g_set_error_literal (error, NMCLI_ERROR, 0, nmc->return_text->str);
-		goto done;
+	/* Find out maximal string lengths */
+	for (i = 0; i < num_fields; i++) {
+		size_t max_width = 0;
+		for (j = 0; j < nmc->output_data->len; j++) {
+			gboolean field_names, dealloc;
+			char *value;
+			row = g_ptr_array_index (nmc->output_data, j);
+			field_names = row[0].flags & NMC_OF_FLAG_FIELD_NAMES;
+			value = get_value_to_print (row+i, field_names, "--", &dealloc);
+			len = nmc_string_screen_width (value, NULL);
+			max_width = len > max_width ? len : max_width;
+			if (dealloc)
+				g_free (value);
+		}
+		for (j = 0; j < nmc->output_data->len; j++) {
+			row = g_ptr_array_index (nmc->output_data, j);
+			row[i].width = max_width + 1;
+		}
 	}
 
-	if (!org_freedesktop_DBus_name_has_owner (proxy, NM_DBUS_SERVICE, &has_owner, &err)) {
-		g_string_printf (nmc->return_text, _("Error: NameHasOwner request failed: %s"),
-		                 (err && err->message) ? err->message : _("(unknown)"));
-		nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
-		g_propagate_error (error, err);
-		goto done;
+	/* Now we can print the data. */
+	for (i = 0; i < nmc->output_data->len; i++) {
+		row = g_ptr_array_index (nmc->output_data, i);
+		print_required_fields (nmc, row);
 	}
-
-done:
-	if (connection)
-		dbus_g_connection_unref (connection);
-	if (proxy)
-		g_object_unref (proxy);
-
-	return has_owner;
 }
 
 /*
diff --git a/cli/src/utils.h b/cli/src/utils.h
index 81ce1633..e92952f3 100644
--- a/cli/src/utils.h
+++ b/cli/src/utils.h
@@ -14,7 +14,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * (C) Copyright 2010 - 2012 Red Hat, Inc.
+ * (C) Copyright 2010 - 2014 Red Hat, Inc.
  */
 
 #ifndef NMC_UTILS_H
@@ -24,21 +24,74 @@
 
 #include "nmcli.h"
 
+/* === Types === */
+
+typedef struct {
+	const char *name;
+	gboolean has_value;
+	const char **value;
+	gboolean mandatory;
+	gboolean found;
+} nmc_arg_t;
+
 /* === Functions === */
 int matches (const char *cmd, const char *pattern);
 int next_arg (int *argc, char ***argv);
-char *ssid_to_printable (const char *str, gsize len);
+gboolean nmc_arg_is_help (const char *arg);
+gboolean nmc_arg_is_option (const char *arg, const char *opt_name);
+gboolean nmc_parse_args (nmc_arg_t *arg_arr, gboolean last, int *argc, char ***argv, GError **error);
+char *ssid_to_hex (const char *str, gsize len);
+gboolean nmc_string_to_int_base (const char *str,
+                                 int base,
+                                 gboolean range_check,
+                                 long int min,
+                                 long int max,
+                                 long int *value);
+gboolean nmc_string_to_uint_base (const char *str,
+                                  int base,
+                                  gboolean range_check,
+                                  unsigned long int min,
+                                  unsigned long int max,
+                                  unsigned long int *value);
+gboolean nmc_string_to_int (const char *str,
+                            gboolean range_check,
+                            long int min,
+                            long int max,
+                            long int *value);
+gboolean nmc_string_to_uint (const char *str,
+                             gboolean range_check,
+                             unsigned long int min,
+                             unsigned long int max,
+                             unsigned long int *value);
+gboolean nmc_string_to_bool (const char *str, gboolean *val_bool, GError **error);
 char *nmc_ip4_address_as_string (guint32 ip, GError **error);
 char *nmc_ip6_address_as_string (const struct in6_addr *ip, GError **error);
 void nmc_terminal_erase_line (void);
 void nmc_terminal_show_progress (const char *str);
+const char *nmc_term_color_sequence (NmcTermColor color);
+char *nmc_colorize (NmcTermColor color, const char * fmt, ...);
+char *nmc_get_user_input (const char *ask_str);
+int nmc_string_to_arg_array (const char *line, const char *delim, char ***argv, int *argc);
+const char *nmc_string_is_valid (const char *input, const char **allowed, GError **error);
+GSList *nmc_util_strv_to_slist (char **strv);
+char **nmc_strsplit_set (const char *str, const char *delimiter, int max_tokens);
 int nmc_string_screen_width (const char *start, const char *end);
-void set_val_str (NmcOutputField fields_array[], guint32 index, const char *value);
-void set_val_arr (NmcOutputField fields_array[], guint32 index, const char **value);
-GArray *parse_output_fields (const char *fields_str, const NmcOutputField fields_array[], GError **error);
+void set_val_str  (NmcOutputField fields_array[], guint32 index, char *value);
+void set_val_strc (NmcOutputField fields_array[], guint32 index, const char *value);
+void set_val_arr  (NmcOutputField fields_array[], guint32 index, char **value);
+void set_val_arrc (NmcOutputField fields_array[], guint32 index, const char **value);
+void nmc_free_output_field_values (NmcOutputField fields_array[]);
+GArray *parse_output_fields (const char *fields_str,
+                             const NmcOutputField fields_array[],
+                             gboolean parse_groups,
+                             GPtrArray **group_fields,
+                             GError **error);
+char *nmc_get_allowed_fields (const NmcOutputField fields_array[], int group_idx);
 gboolean nmc_terse_option_check (NMCPrintOutput print_output, const char *fields, GError **error);
-void print_fields (const NmcPrintFields fields, const NmcOutputField field_values[]);
-gboolean nmc_is_nm_running (NmCli *nmc, GError **error);
+NmcOutputField *nmc_dup_fields_array (NmcOutputField fields[], size_t size, guint32 flags);
+void nmc_empty_output_fields (NmCli *nmc);
+void print_required_fields (NmCli *nmc, const NmcOutputField field_values[]);
+void print_data (NmCli *nmc);
 gboolean nmc_versions_match (NmCli *nmc);
 
 #endif /* NMC_UTILS_H */