summary refs log tree commit diff
path: root/cli/src/connections.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2012-03-24 01:37:02 +0100
committerMichael Biebl <biebl@debian.org>2012-03-24 01:37:02 +0100
commitde06e5715e780baade318f3490ac7a4c9ce84e32 (patch)
tree23fbc3fafc12072476eff98bee60100eb54c29db /cli/src/connections.c
parentb436a68a20ff3114ded32a7a3d70cdd4954039f9 (diff)
Imported Upstream version 0.9.4.0 upstream/0.9.4.0
Diffstat (limited to 'cli/src/connections.c')
-rw-r--r--cli/src/connections.c1053
1 files changed, 594 insertions, 459 deletions
diff --git a/cli/src/connections.c b/cli/src/connections.c
index 7d4fffc0..ea5211f5 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 - 2011 Red Hat, Inc.
+ * (C) Copyright 2010 - 2012 Red Hat, Inc.
  */
 
 #include "config.h"
@@ -32,17 +32,6 @@
 #include <netinet/ether.h>
 
 #include <nm-client.h>
-#include <nm-setting-connection.h>
-#include <nm-setting-wired.h>
-#include <nm-setting-pppoe.h>
-#include <nm-setting-wireless.h>
-#include <nm-setting-gsm.h>
-#include <nm-setting-cdma.h>
-#include <nm-setting-bluetooth.h>
-#include <nm-setting-olpc-mesh.h>
-#if WITH_WIMAX
-#include <nm-setting-wimax.h>
-#endif
 #include <nm-device-ethernet.h>
 #include <nm-device-wifi.h>
 #if WITH_WIMAX
@@ -50,29 +39,20 @@
 #endif
 #include <nm-device-modem.h>
 #include <nm-device-bt.h>
-//#include <nm-device-olpc-mesh.h>
+#include <nm-device-olpc-mesh.h>
+#include <nm-device-infiniband.h>
+#include <nm-device-bond.h>
+#include <nm-device-vlan.h>
 #include <nm-remote-settings.h>
 #include <nm-vpn-connection.h>
+#include <nm-utils.h>
 
 #include "utils.h"
+#include "common.h"
 #include "settings.h"
 #include "connections.h"
 
 
-/* Available fields for 'con status' */
-static NmcOutputField nmc_fields_con_status[] = {
-	{"NAME",          N_("NAME"),         25, NULL, 0},  /* 0 */
-	{"UUID",          N_("UUID"),         38, NULL, 0},  /* 1 */
-	{"DEVICES",       N_("DEVICES"),      10, NULL, 0},  /* 2 */
-	{"DEFAULT",       N_("DEFAULT"),       8, NULL, 0},  /* 3 */
-	{"SPEC-OBJECT",   N_("SPEC-OBJECT"),  10, NULL, 0},  /* 4 */
-	{"VPN",           N_("VPN"),           5, NULL, 0},  /* 5 */
-	{"DBUS-PATH",     N_("DBUS-PATH"),    51, NULL, 0},  /* 6 */
-	{NULL,            NULL,                0, NULL, 0}
-};
-#define NMC_FIELDS_CON_STATUS_ALL     "NAME,UUID,DEVICES,DEFAULT,VPN,DBUS-PATH,SPEC-OBJECT"
-#define NMC_FIELDS_CON_STATUS_COMMON  "NAME,UUID,DEVICES,DEFAULT,VPN"
-
 /* Available fields for 'con list' */
 static NmcOutputField nmc_fields_con_list[] = {
 	{"NAME",            N_("NAME"),           25, NULL, 0},  /* 0 */
@@ -88,7 +68,6 @@ static NmcOutputField nmc_fields_con_list[] = {
 #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"
 
-
 /* Helper macro to define fields */
 #define SETTING_FIELD(setting, width) { setting, N_(setting), width, NULL, 0 }
 
@@ -110,6 +89,9 @@ static NmcOutputField nmc_fields_settings_names[] = {
 	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 */
 	{NULL, NULL, 0, NULL, 0}
 };
 #define NMC_FIELDS_SETTINGS_NAMES_ALL_X  NM_SETTING_CONNECTION_SETTING_NAME","\
@@ -126,7 +108,10 @@ static NmcOutputField nmc_fields_settings_names[] = {
                                          NM_SETTING_CDMA_SETTING_NAME","\
                                          NM_SETTING_BLUETOOTH_SETTING_NAME","\
                                          NM_SETTING_OLPC_MESH_SETTING_NAME","\
-                                         NM_SETTING_VPN_SETTING_NAME
+                                         NM_SETTING_VPN_SETTING_NAME","\
+                                         NM_SETTING_INFINIBAND_SETTING_NAME","\
+                                         NM_SETTING_BOND_SETTING_NAME","\
+                                         NM_SETTING_VLAN_SETTING_NAME
 #if WITH_WIMAX
 #define NMC_FIELDS_SETTINGS_NAMES_ALL    NMC_FIELDS_SETTINGS_NAMES_ALL_X","\
                                          NM_SETTING_WIMAX_SETTING_NAME
@@ -135,6 +120,54 @@ static NmcOutputField nmc_fields_settings_names[] = {
 #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}
+};
+#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
+
+/* 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}
+};
+#define NMC_FIELDS_CON_STATUS_DETAILS_VPN_ALL  "GROUP,TYPE,USERNAME,GATEWAY,BANNER,VPN-STATE,CFG"
+
+
 typedef struct {
 	NmCli *nmc;
 	int argc;
@@ -153,7 +186,7 @@ usage (void)
 	         _("Usage: nmcli con { COMMAND | help }\n"
 	         "  COMMAND := { list | status | up | down | delete }\n\n"
 	         "  list [id <id> | uuid <id>]\n"
-	         "  status\n"
+	         "  status [id <id> | uuid <id> | path <path>]\n"
 #if WITH_WIMAX
 	         "  up id <id> | uuid <id> [iface <iface>] [ap <BSSID>] [nsp <name>] [--nowait] [--timeout <timeout>]\n"
 #else
@@ -183,7 +216,6 @@ quit (void)
 static gboolean
 nmc_connection_detail (NMConnection *connection, NmCli *nmc)
 {
-	NMSetting *setting;
 	GError *error = NULL;
 	GArray *print_settings_array;
 	int i;
@@ -229,135 +261,135 @@ nmc_connection_detail (NMConnection *connection, NmCli *nmc)
 		was_output = FALSE;
 
 		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[0].name)) {
-			setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
-			if (setting) {
-				setting_connection_details (setting, nmc);
+			NMSettingConnection *s_con = nm_connection_get_setting_connection (connection);
+			if (s_con) {
+				setting_connection_details (s_con, nmc);
 				was_output = TRUE;
 				continue;
 			}
 		}
 
 		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[1].name)) {
-			setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED);
-			if (setting) {
-				setting_wired_details (setting, nmc);
+			NMSettingWired *s_wired = nm_connection_get_setting_wired (connection);
+			if (s_wired) {
+				setting_wired_details (s_wired, nmc);
 				was_output = TRUE;
 				continue;
 			}
 		}
 
 		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[2].name)) {
-			setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X);
-			if (setting) {
-				setting_802_1X_details (setting, nmc);
+			NMSetting8021x *s_8021X = nm_connection_get_setting_802_1x (connection);
+			if (s_8021X) {
+				setting_802_1X_details (s_8021X, nmc);
 				was_output = TRUE;
 				continue;
 			}
 		}
 
 		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[3].name)) {
-			setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS);
-			if (setting) {
-				setting_wireless_details (setting, nmc);
+			NMSettingWireless *s_wireless = nm_connection_get_setting_wireless (connection);
+			if (s_wireless) {
+				setting_wireless_details (s_wireless, nmc);
 				was_output = TRUE;
 				continue;
 			}
 		}
 
 		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[4].name)) {
-			setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
-			if (setting) {
-				setting_wireless_security_details (setting, nmc);
+			NMSettingWirelessSecurity *s_wsec = nm_connection_get_setting_wireless_security (connection);
+			if (s_wsec) {
+				setting_wireless_security_details (s_wsec, nmc);
 				was_output = TRUE;
 				continue;
 			}
 		}
 
 		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[5].name)) {
-			setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
-			if (setting) {
-				setting_ip4_config_details (setting, nmc);
+			NMSettingIP4Config *s_ip4 = nm_connection_get_setting_ip4_config (connection);
+			if (s_ip4) {
+				setting_ip4_config_details (s_ip4, nmc);
 				was_output = TRUE;
 				continue;
 			}
 		}
 
 		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[6].name)) {
-			setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG);
-			if (setting) {
-				setting_ip6_config_details (setting, nmc);
+			NMSettingIP6Config *s_ip6 = nm_connection_get_setting_ip6_config (connection);
+			if (s_ip6) {
+				setting_ip6_config_details (s_ip6, nmc);
 				was_output = TRUE;
 				continue;
 			}
 		}
 
 		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[7].name)) {
-			setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_SERIAL);
-			if (setting) {
-				setting_serial_details (setting, nmc);
+			NMSettingSerial *s_serial = nm_connection_get_setting_serial (connection);
+			if (s_serial) {
+				setting_serial_details (s_serial, nmc);
 				was_output = TRUE;
 				continue;
 			}
 		}
 
 		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[8].name)) {
-			setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_PPP);
-			if (setting) {
-				setting_ppp_details (setting, nmc);
+			NMSettingPPP *s_ppp = nm_connection_get_setting_ppp (connection);
+			if (s_ppp) {
+				setting_ppp_details (s_ppp, nmc);
 				was_output = TRUE;
 				continue;
 			}
 		}
 
 		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[9].name)) {
-			setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_PPPOE);
-			if (setting) {
-				setting_pppoe_details (setting, nmc);
+			NMSettingPPPOE *s_pppoe = nm_connection_get_setting_pppoe (connection);
+			if (s_pppoe) {
+				setting_pppoe_details (s_pppoe, nmc);
 				was_output = TRUE;
 				continue;
 			}
 		}
 
 		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[10].name)) {
-			setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_GSM);
-			if (setting) {
-				setting_gsm_details (setting, nmc);
+			NMSettingGsm *s_gsm = nm_connection_get_setting_gsm (connection);
+			if (s_gsm) {
+				setting_gsm_details (s_gsm, nmc);
 				was_output = TRUE;
 				continue;
 			}
 		}
 
 		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[11].name)) {
-			setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_CDMA);
-			if (setting) {
-				setting_cdma_details (setting, nmc);
+			NMSettingCdma *s_cdma = nm_connection_get_setting_cdma (connection);
+			if (s_cdma) {
+				setting_cdma_details (s_cdma, nmc);
 				was_output = TRUE;
 				continue;
 			}
 		}
 
 		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[12].name)) {
-			setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_BLUETOOTH);
-			if (setting) {
-				setting_bluetooth_details (setting, nmc);
+			NMSettingBluetooth *s_bluetooth = nm_connection_get_setting_bluetooth (connection);
+			if (s_bluetooth) {
+				setting_bluetooth_details (s_bluetooth, nmc);
 				was_output = TRUE;
 				continue;
 			}
 		}
 
 		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[13].name)) {
-			setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_OLPC_MESH);
-			if (setting) {
-				setting_olpc_mesh_details (setting, nmc);
+			NMSettingOlpcMesh *s_olpc_mesh = nm_connection_get_setting_olpc_mesh (connection);
+			if (s_olpc_mesh) {
+				setting_olpc_mesh_details (s_olpc_mesh, nmc);
 				was_output = TRUE;
 				continue;
 			}
 		}
 
 		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[14].name)) {
-			setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN);
-			if (setting) {
-				setting_vpn_details (setting, nmc);
+			NMSettingVPN *s_vpn = nm_connection_get_setting_vpn (connection);
+			if (s_vpn) {
+				setting_vpn_details (s_vpn, nmc);
 				was_output = TRUE;
 				continue;
 			}
@@ -365,14 +397,41 @@ nmc_connection_detail (NMConnection *connection, NmCli *nmc)
 
 #if WITH_WIMAX
 		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[15].name)) {
-			setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_WIMAX);
-			if (setting) {
-				setting_wimax_details (setting, nmc);
+			NMSettingWimax *s_wimax = nm_connection_get_setting_wimax (connection);
+			if (s_wimax) {
+				setting_wimax_details (s_wimax, nmc);
 				was_output = TRUE;
 				continue;
 			}
 		}
 #endif
+
+		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[16].name)) {
+			NMSettingInfiniband *s_infiniband = nm_connection_get_setting_infiniband (connection);
+			if (s_infiniband) {
+				setting_infiniband_details (s_infiniband, nmc);
+				was_output = TRUE;
+				continue;
+			}
+		}
+
+		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[17].name)) {
+			NMSettingBond *s_bond = nm_connection_get_setting_bond (connection);
+			if (s_bond) {
+				setting_bond_details (s_bond, nmc);
+				was_output = TRUE;
+				continue;
+			}
+		}
+
+		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[18].name)) {
+			NMSettingVlan *s_vlan = nm_connection_get_setting_vlan (connection);
+			if (s_vlan) {
+				setting_vlan_details (s_vlan, nmc);
+				was_output = TRUE;
+				continue;
+			}
+		}
 	}
 
 	if (print_settings_array)
@@ -544,19 +603,77 @@ error:
 	return nmc->return_value;
 }
 
-static void
-show_active_connection (gpointer data, gpointer user_data)
+static const char *
+active_connection_state_to_string (NMActiveConnectionState state)
 {
-	NMActiveConnection *active = NM_ACTIVE_CONNECTION (data);
-	NmCli *nmc = (NmCli *) user_data;
-	GSList *con_list, *iter;
+	switch (state) {
+	case NM_ACTIVE_CONNECTION_STATE_ACTIVATING:
+		return _("activating");
+	case NM_ACTIVE_CONNECTION_STATE_ACTIVATED:
+		return _("activated");
+	case NM_ACTIVE_CONNECTION_STATE_DEACTIVATING:
+		return _("deactivating");
+	case NM_ACTIVE_CONNECTION_STATE_UNKNOWN:
+	default:
+		return _("unknown");
+	}
+}
+
+static const char *
+vpn_connection_state_to_string (NMVPNConnectionState state)
+{
+	switch (state) {
+	case NM_VPN_CONNECTION_STATE_PREPARE:
+		return _("VPN connecting (prepare)");
+	case NM_VPN_CONNECTION_STATE_NEED_AUTH:
+		return _("VPN connecting (need authentication)");
+	case NM_VPN_CONNECTION_STATE_CONNECT:
+		return _("VPN connecting");
+	case NM_VPN_CONNECTION_STATE_IP_CONFIG_GET:
+		return _("VPN connecting (getting IP configuration)");
+	case NM_VPN_CONNECTION_STATE_ACTIVATED:
+		return _("VPN connected");
+	case NM_VPN_CONNECTION_STATE_FAILED:
+		return _("VPN connection failed");
+	case NM_VPN_CONNECTION_STATE_DISCONNECTED:
+		return _("VPN disconnected");
+	default:
+		return _("unknown");
+	}
+}
+
+static NMConnection *
+get_connection_for_active (const GSList *con_list, NMActiveConnection *active)
+{
+	const GSList *iter;
+	const char *path;
+
+	path = nm_active_connection_get_connection (active);
+	g_return_val_if_fail (path != NULL, NULL);
+
+	for (iter = con_list; iter; iter = g_slist_next (iter)) {
+		NMConnection *candidate = NM_CONNECTION (iter->data);
+
+		if (strcmp (nm_connection_get_path (candidate), path) == 0)
+			return candidate;
+	}
+	return NULL;
+}
+
+static gboolean
+fill_in_fields_con_status (NMActiveConnection *active, GSList *con_list)
+{
+	GSList *iter;
 	const char *active_path;
 	NMSettingConnection *s_con;
 	const GPtrArray *devices;
 	GString *dev_str;
+	NMActiveConnectionState state;
 	int i;
+	gboolean success = FALSE;
 
 	active_path = nm_active_connection_get_connection (active);
+	state = nm_active_connection_get_state (active);
 
 	/* Get devices of the active connection */
 	dev_str = g_string_new (NULL);
@@ -570,7 +687,6 @@ show_active_connection (gpointer data, gpointer user_data)
 	if (dev_str->len > 0)
 		g_string_truncate (dev_str, dev_str->len - 1);  /* Cut off last ',' */
 
-	con_list = nmc->system_connections; 
 	for (iter = con_list; iter; iter = g_slist_next (iter)) {
 		NMConnection *connection = (NMConnection *) iter->data;
 		const char *con_path = nm_connection_get_path (connection);
@@ -580,410 +696,432 @@ show_active_connection (gpointer data, gpointer user_data)
 			s_con = nm_connection_get_setting_connection (connection);
 			g_assert (s_con != NULL);
 
-			/* Obtain field values */
-			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 = dev_str->str;
-			nmc->allowed_fields[3].value = nm_active_connection_get_default (active) ? _("yes") : _("no");
-			nmc->allowed_fields[4].value = nm_active_connection_get_specific_object (active);
-			nmc->allowed_fields[5].value = NM_IS_VPN_CONNECTION (active) ? _("yes") : _("no");
-			nmc->allowed_fields[6].value = nm_object_get_path (NM_OBJECT (active));
-
-			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);
+			/* Fill field values */
+			nmc_fields_con_status[0].value = nmc_fields_status_details_groups[0].name;
+			nmc_fields_con_status[1].value = nm_setting_connection_get_id (s_con);
+			nmc_fields_con_status[2].value = nm_setting_connection_get_uuid (s_con);
+			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 = nm_setting_connection_get_zone (s_con);
+			nmc_fields_con_status[12].value = nm_active_connection_get_master (active);
+
+			success = TRUE;
 			break;
 		}
 	}
 
-	g_string_free (dev_str, TRUE);
+	/* 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 NMCResultCode
-do_connections_status (NmCli *nmc, int argc, char **argv)
+static void
+free_fields_con_status (void)
 {
-	const GPtrArray *active_cons;
-	GError *error = NULL;
-	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;
-
-	nmc->should_wait = 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;
+	/* Just DEVICES string was dynamically allocated */
+	g_free ((char *) nmc_fields_con_status[3].value);
+	nmc_fields_con_status[3].value = NULL;
+}
 
-	nmc->allowed_fields = nmc_fields_con_status;
-	nmc->print_fields.indices = parse_output_fields (fields_str, nmc->allowed_fields, &error);
+static void
+show_active_connection (gpointer data, gpointer user_data)
+{
+	NMActiveConnection *active = NM_ACTIVE_CONNECTION (data);
+	NmCli *nmc = (NmCli *) user_data;
 
-	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_ALL);
-		g_error_free (error);
-		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-		goto error;
-	}
+	fill_in_fields_con_status (active, nmc->system_connections);
 
-	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;
-	}
-
-	/* 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");
+	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);
 
-	nmc->get_client (nmc);
-	active_cons = nm_client_get_active_connections (nmc->client);
-	if (active_cons && active_cons->len)
-		g_ptr_array_foreach ((GPtrArray *) active_cons, show_active_connection, (gpointer) nmc);
-
-error:
-	return nmc->return_value;
+	free_fields_con_status ();
 }
 
-/* --------------------
- * These function should be moved to libnm-glib in the end.
- */
-static gboolean
-check_ethernet_compatible (NMDeviceEthernet *device, NMConnection *connection, GError **error)
+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;
-	NMSettingWired *s_wired;
-	const char *connection_type;
-	gboolean is_pppoe = FALSE;
-
-	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-
-	s_con = nm_connection_get_setting_connection (connection);
-	g_assert (s_con);
-
-	connection_type = nm_setting_connection_get_connection_type (s_con);
-	if (   strcmp (connection_type, NM_SETTING_WIRED_SETTING_NAME)
-	    && strcmp (connection_type, NM_SETTING_PPPOE_SETTING_NAME)) {
-		g_set_error (error, 0, 0,
-		             "The connection was not a wired or PPPoE connection.");
-		return FALSE;
-	}
 
-	if (!strcmp (connection_type, NM_SETTING_PPPOE_SETTING_NAME))
-		is_pppoe = TRUE;
-
-	s_wired = nm_connection_get_setting_wired (connection);
-	/* Wired setting is optional for PPPoE */
-	if (!is_pppoe && !s_wired) {
-		g_set_error (error, 0, 0,
-		             "The connection was not a valid wired connection.");
-		return FALSE;
-	}
-
-	if (s_wired) {
-		const GByteArray *mac;
-		const char *device_mac_str;
-		struct ether_addr *device_mac = NULL;
-
-		device_mac_str = nm_device_ethernet_get_permanent_hw_address (device);
-		if (device_mac_str)
-			device_mac = ether_aton (device_mac_str);
-		if (!device_mac) {
-			g_set_error (error, 0, 0, "Invalid device MAC address.");
-			return FALSE;
-		}
+	for (i = 0; active_cons && (i < active_cons->len); i++) {
+		NMActiveConnection *candidate = g_ptr_array_index (active_cons, i);
 
-		mac = nm_setting_wired_get_mac_address (s_wired);
-		if (mac && memcmp (mac->data, device_mac->ether_addr_octet, ETH_ALEN)) {
-			g_set_error (error, 0, 0,
-			             "The connection's MAC address did not match this device.");
-			return FALSE;
+		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;
+}
 
-	// FIXME: check bitrate against device capabilities
+typedef struct {
+	char **array;
+	guint32 idx;
+} FillVPNDataInfo;
 
-	return TRUE;
+static void
+fill_vpn_data_item (const char *key, const char *value, gpointer user_data)
+{
+        FillVPNDataInfo *info = (FillVPNDataInfo *) user_data;
+
+	info->array[info->idx++] = g_strdup_printf ("%s = %s", key, value);
 }
 
-static gboolean
-check_wifi_compatible (NMDeviceWifi *device, NMConnection *connection, GError **error)
+// FIXME: The same or similar code for VPN info appears also in nm-applet (applet-dialogs.c),
+// and in gnome-control-center as well. It could probably be shared somehow.
+static char *
+get_vpn_connection_type (NMConnection *connection)
 {
-	NMSettingConnection *s_con;
-	NMSettingWireless *s_wireless;
+	const char *type, *p;
 
-	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-
-	s_con = nm_connection_get_setting_connection (connection);
-	g_assert (s_con);
+	/* The service type is in form of "org.freedesktop.NetworkManager.vpnc".
+	 * Extract end part after last dot, e.g. "vpnc"
+	 */
+	type = nm_setting_vpn_get_service_type (nm_connection_get_setting_vpn (connection));
+	p = strrchr (type, '.');
+	return g_strdup (p ? p + 1 : type);
+}
 
-	if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_WIRELESS_SETTING_NAME)) {
-		g_set_error (error, 0, 0,
-		             "The connection was not a WiFi connection.");
-		return FALSE;
-	}
+/* VPN parameters can be found at:
+ * http://git.gnome.org/browse/network-manager-openvpn/tree/src/nm-openvpn-service.h
+ * http://git.gnome.org/browse/network-manager-vpnc/tree/src/nm-vpnc-service.h
+ * http://git.gnome.org/browse/network-manager-pptp/tree/src/nm-pptp-service.h
+ * http://git.gnome.org/browse/network-manager-openconnect/tree/src/nm-openconnect-service.h
+ * http://git.gnome.org/browse/network-manager-openswan/tree/src/nm-openswan-service.h
+ * See also 'properties' directory in these plugins.
+ */
+static const gchar *
+find_vpn_gateway_key (const char *vpn_type)
+{
+	if (g_strcmp0 (vpn_type, "openvpn") == 0)     return "remote";
+	if (g_strcmp0 (vpn_type, "vpnc") == 0)        return "IPSec gateway";
+	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";
+	return "";
+}
 
-	s_wireless = nm_connection_get_setting_wireless (connection);
-	if (!s_wireless) {
-		g_set_error (error, 0, 0,
-		             "The connection was not a valid WiFi connection.");
-		return FALSE;
-	}
+static const gchar *
+find_vpn_username_key (const char *vpn_type)
+{
+	if (g_strcmp0 (vpn_type, "openvpn") == 0)     return "username";
+	if (g_strcmp0 (vpn_type, "vpnc") == 0)        return "Xauth username";
+	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";
+	return "";
+}
 
-	if (s_wireless) {
-		const GByteArray *mac;
-		const char *device_mac_str;
-		struct ether_addr *device_mac = NULL;
+enum VpnDataItem {
+	VPN_DATA_ITEM_GATEWAY,
+	VPN_DATA_ITEM_USERNAME
+};
 
-		device_mac_str = nm_device_wifi_get_permanent_hw_address (device);
-		if (device_mac_str)
-			device_mac = ether_aton (device_mac_str);
-		if (!device_mac) {
-			g_set_error (error, 0, 0, "Invalid device MAC address.");
-			return FALSE;
-		}
+static const gchar *
+get_vpn_data_item (NMConnection *connection, enum VpnDataItem vpn_data_item)
+{
+	const char *key;
+	char *type = get_vpn_connection_type (connection);
 
-		mac = nm_setting_wireless_get_mac_address (s_wireless);
-		if (mac && memcmp (mac->data, device_mac->ether_addr_octet, ETH_ALEN)) {
-			g_set_error (error, 0, 0,
-		        	     "The connection's MAC address did not match this device.");
-			return FALSE;
-		}
+	switch (vpn_data_item) {
+	case VPN_DATA_ITEM_GATEWAY:
+		key = find_vpn_gateway_key (type);
+		break;
+	case VPN_DATA_ITEM_USERNAME:
+		key = find_vpn_username_key (type);
+		break;
+	default:
+		key = "";
+		break;
 	}
+	g_free (type);
 
-	// FIXME: check channel/freq/band against bands the hardware supports
-	// FIXME: check encryption against device capabilities
-	// FIXME: check bitrate against device capabilities
-
-	return TRUE;
+	return nm_setting_vpn_get_data_item (nm_connection_get_setting_vpn (connection), key);
 }
+/* FIXME end */
 
 static gboolean
-check_bt_compatible (NMDeviceBt *device, NMConnection *connection, GError **error)
+nmc_active_connection_detail (NMActiveConnection *acon, NmCli *nmc)
 {
-	NMSettingConnection *s_con;
-	NMSettingBluetooth *s_bt;
-	const GByteArray *array;
-	char *str;
-	const char *device_hw_str;
-	int addr_match = FALSE;
-	const char *bt_type_str;
-	guint32 bt_type, bt_capab;
-
-	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+	GError *error = NULL;
+	GArray *print_groups;
+	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;
+	gboolean was_output = FALSE;
 
-	s_con = nm_connection_get_setting_connection (connection);
-	g_assert (s_con);
+	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;
 
-	if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_BLUETOOTH_SETTING_NAME)) {
-		g_set_error (error, 0, 0,
-		             "The connection was not a Bluetooth connection.");
+	print_groups = parse_output_fields (fields_str, nmc_fields_status_details_groups, &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_error_free (error);
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
 		return FALSE;
 	}
 
-	s_bt = nm_connection_get_setting_bluetooth (connection);
-	if (!s_bt) {
-		g_set_error (error, 0, 0,
-		             "The connection was not a valid Bluetooth connection.");
-		return FALSE;
-	}
+	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);
 
-	array = nm_setting_bluetooth_get_bdaddr (s_bt);
-	if (!array || (array->len != ETH_ALEN)) {
-		g_set_error (error, 0, 0,
-		             "The connection did not contain a valid Bluetooth address.");
-		return FALSE;
-	}
+	/* 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);
 
-	bt_type_str = nm_setting_bluetooth_get_connection_type (s_bt);
-	g_assert (bt_type_str);
+		if (nmc->print_output != NMC_PRINT_TERSE && !nmc->multiline_output && was_output)
+			printf ("\n"); /* Empty line */
 
-	bt_type = NM_BT_CAPABILITY_NONE;
-	if (!strcmp (bt_type_str, NM_SETTING_BLUETOOTH_TYPE_DUN))
-		bt_type = NM_BT_CAPABILITY_DUN;
-	else if (!strcmp (bt_type_str, NM_SETTING_BLUETOOTH_TYPE_PANU))
-		bt_type = NM_BT_CAPABILITY_NAP;
+		was_output = FALSE;
 
-	bt_capab = nm_device_bt_get_capabilities (device);
-	if (!(bt_type & bt_capab)) {
-		g_set_error (error, 0, 0,
-		             "The connection was not compatible with the device's capabilities.");
-		return 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);
 
-	device_hw_str = nm_device_bt_get_hw_address (device);
+			/* 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);
 
-	str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
-	                       array->data[0], array->data[1], array->data[2],
-	                       array->data[3], array->data[4], array->data[5]);
-	addr_match = !strcmp (device_hw_str, str);
-	g_free (str);
+			/* Fill in values */
+			fill_in_fields_con_status (acon, nmc->system_connections);
 
-	return addr_match;
-}
+			/* 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);
 
-#if 0
-static gboolean
-check_olpc_mesh_compatible (NMDeviceOlpcMesh *device, NMConnection *connection, GError **error)
-{
-	NMSettingConnection *s_con;
-	NMSettingOlpcMesh *s_mesh;
+			free_fields_con_status ();
+			was_output = TRUE;
+		}
 
-	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+		/* IP */
+		if (strcasecmp (nmc_fields_status_details_groups[group_idx].name,  nmc_fields_status_details_groups[1].name) == 0) {
+			const GPtrArray *devices;
+			int j;
+
+			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");
+				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;
+			}
+		}
 
-	s_con = nm_connection_get_setting_connection (connection);
-	g_assert (s_con);
+		/* VPN */
+		if (NM_IS_VPN_CONNECTION (acon) &&
+		    strcasecmp (nmc_fields_status_details_groups[group_idx].name,  nmc_fields_status_details_groups[2].name) == 0) {
+			NMConnection *con;
+			NMSettingConnection *s_con;
+			NMSettingVPN *s_vpn;
+			NMVPNConnectionState vpn_state;
+			char *type_str, *banner_str, *vpn_state_str;
+			const char *username = NULL;
+			char **vpn_data_array = NULL;
+			guint32 items_num;
+
+			con = get_connection_for_active (nmc->system_connections, acon);
+
+			s_con = nm_connection_get_setting_connection (con);
+			g_assert (s_con != NULL);
 
-	if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_OLPC_MESH_SETTING_NAME)) {
-		g_set_error (error, 0, 0,
-		             "The connection was not a Mesh connection.");
-		return FALSE;
-	}
+			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);
 
-	s_mesh = nm_connection_get_setting_olpc_mesh (connection);
-	if (!s_mesh) {
-		g_set_error (error, 0, 0,
-		             "The connection was not a valid Mesh connection.");
-		return FALSE;
+			/* 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);
+
+			s_vpn = nm_connection_get_setting_vpn (con);
+			if (s_vpn) {
+				items_num = nm_setting_vpn_get_num_data_items (s_vpn);
+				if (items_num > 0) {
+					FillVPNDataInfo info;
+
+					vpn_data_array = g_new (char *, items_num + 1);
+					info.array = vpn_data_array;
+					info.idx = 0;
+					nm_setting_vpn_foreach_data_item (s_vpn, &fill_vpn_data_item, &info);
+					vpn_data_array[items_num] = NULL;
+				}
+				username = nm_setting_vpn_get_user_name (s_vpn);
+			}
+
+			type_str = get_vpn_connection_type (con);
+			banner_str = g_strescape (nm_vpn_connection_get_banner (NM_VPN_CONNECTION (acon)), "");
+			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);
+			was_output = TRUE;
+		}
 	}
 
+	if (print_groups)
+		g_array_free (print_groups, FALSE);
+
 	return TRUE;
 }
-#endif
 
-#if WITH_WIMAX
-static gboolean
-check_wimax_compatible (NMDeviceWimax *device, NMConnection *connection, GError **error)
+static NMCResultCode
+do_connections_status (NmCli *nmc, int argc, char **argv)
 {
-	NMSettingConnection *s_con;
-	NMSettingWimax *s_wimax;
-	const GByteArray *mac;
-	const char *device_mac_str;
-	struct ether_addr *device_mac = NULL;
-
-	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-
-	s_con = nm_connection_get_setting_connection (connection);
-	g_assert (s_con);
-
-	if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_WIMAX_SETTING_NAME)) {
-		g_set_error (error, 0, 0,
-		             "The connection was not a WiMAX connection.");
-		return FALSE;
-	}
+	const GPtrArray *active_cons;
+	GError *err = NULL;
+	GError *err1 = NULL;
 
-	s_wimax = nm_connection_get_setting_wimax (connection);
-	if (!s_wimax) {
-		g_set_error (error, 0, 0,
-		             "The connection was not a valid WiMAX connection.");
-		return FALSE;
-	}
+	nmc->should_wait = FALSE;
 
-	device_mac_str = nm_device_wimax_get_hw_address (device);
-	if (device_mac_str)
-		device_mac = ether_aton (device_mac_str);
-	if (!device_mac) {
-		g_set_error (error, 0, 0, "Invalid device MAC address.");
-		return FALSE;
+	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;
+		}
+		goto error;
 	}
 
-	mac = nm_setting_wimax_get_mac_address (s_wimax);
-	if (mac && memcmp (mac->data, device_mac->ether_addr_octet, ETH_ALEN)) {
-		g_set_error (error, 0, 0,
-	        	     "The connection's MAC address did not match this device.");
-		return FALSE;
-	}
+	/* Get active connections */
+	nmc->get_client (nmc);
+	active_cons = nm_client_get_active_connections (nmc->client);
 
-	return TRUE;
-}
-#endif
+	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;
+
+		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 gboolean
-check_modem_compatible (NMDeviceModem *device, NMConnection *connection, GError **error)
-{
-	NMSettingConnection *s_con;
-	NMSettingGsm *s_gsm;
-	NMSettingCdma *s_cdma;
-	NMDeviceModemCapabilities caps = NM_DEVICE_MODEM_CAPABILITY_NONE;
+		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;
 
-	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+		/* 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);
 
-	s_con = nm_connection_get_setting_connection (connection);
-	g_assert (s_con);
+		if (active_cons && active_cons->len)
+			g_ptr_array_foreach ((GPtrArray *) active_cons, show_active_connection, (gpointer) nmc);
+	} else {
+		while (argc > 0) {
+			if (   strcmp (*argv, "id") == 0
+			    || strcmp (*argv, "uuid") == 0
+			    || strcmp (*argv, "path") == 0) {
+				const char *selector = *argv;
+				NMActiveConnection *acon;
 
-	/* Figure out what the modem supports */
-	caps = nm_device_modem_get_current_capabilities (device);
-	if (caps & NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS) {
-		if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_GSM_SETTING_NAME)) {
-			g_set_error (error, 0, 0,
-				     "The connection was not a GSM connection.");
-			return FALSE;
-		}
+				if (next_arg (&argc, &argv) != 0) {
+					g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *argv);
+					nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+					return nmc->return_value;
+				}
+				if (!nmc->mode_specified)
+					nmc->multiline_output = TRUE;  /* multiline mode is default for 'con status id|uuid|path' */
 
-		s_gsm = nm_connection_get_setting_gsm (connection);
-		if (!s_gsm) {
-			g_set_error (error, 0, 0,
-				     "The connection was not a valid GSM connection.");
-			return FALSE;
-		}
-	} else if (caps & NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO) {
-		if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_CDMA_SETTING_NAME)) {
-			g_set_error (error, 0, 0,
-				     "The connection was not a CDMA connection.");
-			return FALSE;
-		}
+				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;
+				}
+				break;
+			} else {
+				g_string_printf (nmc->return_text, _("Error: unknown parameter: %s"), *argv);
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+			}
 
-		s_cdma = nm_connection_get_setting_cdma (connection);
-		if (!s_cdma) {
-			g_set_error (error, 0, 0,
-				     "The connection was not a valid CDMA connection.");
-			return FALSE;
+			argc--;
+			argv++;
 		}
 	}
 
-	return TRUE;
-}
-
-static gboolean
-nm_device_is_connection_compatible (NMDevice *device, NMConnection *connection, GError **error)
-{
-	g_return_val_if_fail (NM_IS_DEVICE (device), FALSE);
-	g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
-
-	if (NM_IS_DEVICE_ETHERNET (device))
-		return check_ethernet_compatible (NM_DEVICE_ETHERNET (device), connection, error);
-	else if (NM_IS_DEVICE_WIFI (device))
-		return check_wifi_compatible (NM_DEVICE_WIFI (device), connection, error);
-	else if (NM_IS_DEVICE_BT (device))
-		return check_bt_compatible (NM_DEVICE_BT (device), connection, error);
-//	else if (NM_IS_DEVICE_OLPC_MESH (device))
-//		return check_olpc_mesh_compatible (NM_DEVICE_OLPC_MESH (device), connection, error);
-#if WITH_WIMAX
-	else if (NM_IS_DEVICE_WIMAX (device))
-		return check_wimax_compatible (NM_DEVICE_WIMAX (device), connection, error);
-#endif
-	else if (NM_IS_DEVICE_MODEM (device))
-		return check_modem_compatible (NM_DEVICE_MODEM (device), connection, error);
-
-	g_set_error (error, 0, 0, "unhandled device type '%s'", G_OBJECT_TYPE_NAME (device));
-	return FALSE;
+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);
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+	}
+	return nmc->return_value;
 }
 
-/* -------------------- */
-
 static NMActiveConnection *
 get_default_active_connection (NmCli *nmc, NMDevice **device)
 {
@@ -1095,11 +1233,11 @@ find_device_for_connection (NmCli *nmc,
 			if (iface) {
 				const char *dev_iface = nm_device_get_iface (dev);
 				if (   !strcmp (dev_iface, iface)
-				    && nm_device_is_connection_compatible (dev, connection, NULL)) {
+				    && nm_device_connection_compatible (dev, connection, NULL)) {
 					found_device = dev;
 				}
 			} else {
-				if (nm_device_is_connection_compatible (dev, connection, NULL)) {
+				if (nm_device_connection_compatible (dev, connection, NULL)) {
 					found_device = dev;
 				}
 			}
@@ -1158,45 +1296,6 @@ find_device_for_connection (NmCli *nmc,
 }
 
 static const char *
-active_connection_state_to_string (NMActiveConnectionState state)
-{
-	switch (state) {
-	case NM_ACTIVE_CONNECTION_STATE_ACTIVATING:
-		return _("activating");
-	case NM_ACTIVE_CONNECTION_STATE_ACTIVATED:
-		return _("activated");
-	case NM_ACTIVE_CONNECTION_STATE_DEACTIVATING:
-		return _("deactivating");
-	case NM_ACTIVE_CONNECTION_STATE_UNKNOWN:
-	default:
-		return _("unknown");
-	}
-}
-
-static const char *
-vpn_connection_state_to_string (NMVPNConnectionState state)
-{
-	switch (state) {
-	case NM_VPN_CONNECTION_STATE_PREPARE:
-		return _("VPN connecting (prepare)");
-	case NM_VPN_CONNECTION_STATE_NEED_AUTH:
-		return _("VPN connecting (need authentication)");
-	case NM_VPN_CONNECTION_STATE_CONNECT:
-		return _("VPN connecting");
-	case NM_VPN_CONNECTION_STATE_IP_CONFIG_GET:
-		return _("VPN connecting (getting IP configuration)");
-	case NM_VPN_CONNECTION_STATE_ACTIVATED:
-		return _("VPN connected");
-	case NM_VPN_CONNECTION_STATE_FAILED:
-		return _("VPN connection failed");
-	case NM_VPN_CONNECTION_STATE_DISCONNECTED:
-		return _("VPN disconnected");
-	default:
-		return _("unknown");
-	}
-}
-
-static const char *
 vpn_connection_state_reason_to_string (NMVPNConnectionStateReason reason)
 {
 	switch (reason) {
@@ -1341,6 +1440,7 @@ do_connection_up (NmCli *nmc, int argc, char **argv)
 	gboolean id_specified = FALSE;
 	gboolean wait = TRUE;
 	GError *error = NULL;
+	gboolean is_virtual = FALSE;
 
 	/* Set default timeout for connection activation. It can take quite a long time.
 	 * Using 90 seconds.
@@ -1444,9 +1544,13 @@ do_connection_up (NmCli *nmc, int argc, char **argv)
 	g_assert (s_con);
 	con_type = nm_setting_connection_get_connection_type (s_con);
 
-	device_found = find_device_for_connection (nmc, connection, iface, ap, nsp, &device, &spec_object, &error);
+	if (   nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME)
+	    || nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME))
+		is_virtual = TRUE;
 
-	if (!device_found) {
+	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
@@ -1563,6 +1667,27 @@ error:
 	return nmc->return_value;
 }
 
+static void
+delete_cb (NMRemoteConnection *con, GError *err, 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;
+	}
+	quit ();
+}
+
+static void
+connection_removed_cb (NMRemoteConnection *con, gpointer user_data)
+{
+	NmCli *nmc = (NmCli *) user_data;
+
+	nmc->return_value = NMC_RESULT_SUCCESS;
+	quit ();
+}
+
 static NMCResultCode
 do_connection_delete (NmCli *nmc, int argc, char **argv)
 {
@@ -1571,8 +1696,6 @@ do_connection_delete (NmCli *nmc, int argc, char **argv)
 	const char *id = NULL;
 	GError *error = NULL;
 
-	nmc->should_wait = FALSE;
-
 	while (argc > 0) {
 		if (strcmp (*argv, "id") == 0 || strcmp (*argv, "uuid") == 0) {
 			selector = *argv;
@@ -1616,10 +1739,22 @@ do_connection_delete (NmCli *nmc, int argc, char **argv)
 		goto error;
 	}
 
+	/* 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;
+
+	/* 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);
+
 	/* Delete the connection */
-	nm_remote_connection_delete (NM_REMOTE_CONNECTION (connection), NULL, NULL);
+	nm_remote_connection_delete (NM_REMOTE_CONNECTION (connection), delete_cb, nmc);
+
+	return nmc->return_value;
 
 error:
+	nmc->should_wait = FALSE;
 	return nmc->return_value;
 }