1    	/* nmcli - command-line tool to control NetworkManager
2    	 *
3    	 * This program is free software; you can redistribute it and/or modify
4    	 * it under the terms of the GNU General Public License as published by
5    	 * the Free Software Foundation; either version 2 of the License, or
6    	 * (at your option) any later version.
7    	 *
8    	 * This program is distributed in the hope that it will be useful,
9    	 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10   	 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11   	 * GNU General Public License for more details.
12   	 *
13   	 * You should have received a copy of the GNU General Public License along
14   	 * with this program; if not, write to the Free Software Foundation, Inc.,
15   	 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16   	 *
17   	 * (C) Copyright 2010 - 2012 Red Hat, Inc.
18   	 */
19   	
20   	#include "config.h"
21   	
22   	#include <stdio.h>
23   	#include <string.h>
24   	#include <stdlib.h>
25   	#include <errno.h>
26   	#include <netinet/ether.h>
27   	
28   	#include <glib.h>
29   	#include <glib/gi18n.h>
30   	
31   	#include <nm-client.h>
32   	#include <nm-device.h>
33   	#include <nm-device-ethernet.h>
34   	#include <nm-device-adsl.h>
35   	#include <nm-device-wifi.h>
36   	#include <nm-device-modem.h>
37   	#include <nm-device-bt.h>
38   	#include <nm-device-olpc-mesh.h>
39   	#if WITH_WIMAX
40   	#include <nm-device-wimax.h>
41   	#endif
42   	#include <nm-device-infiniband.h>
43   	#include <nm-device-bond.h>
44   	#include <nm-device-bridge.h>
45   	#include <nm-device-vlan.h>
46   	#include <nm-utils.h>
47   	#include <nm-setting-ip4-config.h>
48   	#include <nm-setting-ip6-config.h>
49   	#include <nm-vpn-connection.h>
50   	#include <nm-setting-connection.h>
51   	#include <nm-setting-wired.h>
52   	#include <nm-setting-adsl.h>
53   	#include <nm-setting-pppoe.h>
54   	#include <nm-setting-wireless.h>
55   	#include <nm-setting-gsm.h>
56   	#include <nm-setting-cdma.h>
57   	#include <nm-setting-bluetooth.h>
58   	#include <nm-setting-olpc-mesh.h>
59   	#if WITH_WIMAX
60   	#include <nm-setting-wimax.h>
61   	#endif
62   	#include <nm-setting-infiniband.h>
63   	
64   	#include "utils.h"
65   	#include "common.h"
66   	#include "devices.h"
67   	
68   	
69   	/* Available fields for 'device status' */
70   	static NmcOutputField nmc_fields_dev_status[] = {
71   		{"DEVICE",    N_("DEVICE"),    10},  /* 0 */
72   		{"TYPE",      N_("TYPE"),      17},  /* 1 */
73   		{"STATE",     N_("STATE"),     13},  /* 2 */
74   		{"DBUS-PATH", N_("DBUS-PATH"), 43},  /* 3 */
75   		{NULL,        NULL,             0}
76   	};
77   	#define NMC_FIELDS_DEV_STATUS_ALL     "DEVICE,TYPE,STATE,DBUS-PATH"
78   	#define NMC_FIELDS_DEV_STATUS_COMMON  "DEVICE,TYPE,STATE"
79   	
80   	
81   	/* Available sections for 'device show' */
82   	static NmcOutputField nmc_fields_dev_show_sections[] = {
83   		{"GENERAL",           N_("GENERAL"),           0},  /* 0 */
84   		{"CAPABILITIES",      N_("CAPABILITIES"),      0},  /* 1 */
85   		{"WIFI-PROPERTIES",   N_("WIFI-PROPERTIES"),   0},  /* 2 */
86   		{"AP",                N_("AP"),                0},  /* 3 */
87   		{"WIRED-PROPERTIES",  N_("WIRED-PROPERTIES"),  0},  /* 4 */
88   		{"WIMAX-PROPERTIES",  N_("WIMAX-PROPERTIES"),  0},  /* 5 */
89   		{"NSP",               N_("NSP"),               0},  /* 6 */
90   		{"IP4",               N_("IP4"),               0},  /* 7 */
91   		{"DHCP4",             N_("DHCP4"),             0},  /* 8 */
92   		{"IP6",               N_("IP6"),               0},  /* 9 */
93   		{"DHCP6",             N_("DHCP6"),             0},  /* 10 */
94   		{"BOND",              N_("BOND"),              0},  /* 11 */
95   		{"VLAN",              N_("VLAN"),              0},  /* 12 */
96   		{"CONNECTIONS",       N_("CONNECTIONS"),       0},  /* 13 */
97   		{NULL,                NULL,                    0}
98   	};
99   	#if WITH_WIMAX
100  	#define NMC_FIELDS_DEV_SHOW_SECTIONS_ALL     "GENERAL,CAPABILITIES,BOND,VLAN,CONNECTIONS,WIFI-PROPERTIES,AP,WIRED-PROPERTIES,WIMAX-PROPERTIES,NSP,IP4,DHCP4,IP6,DHCP6"
101  	#define NMC_FIELDS_DEV_SHOW_SECTIONS_COMMON  "GENERAL,CAPABILITIES,BOND,VLAN,CONNECTIONS,WIFI-PROPERTIES,AP,WIRED-PROPERTIES,WIMAX-PROPERTIES,NSP,IP4,DHCP4,IP6,DHCP6"
102  	#else
103  	#define NMC_FIELDS_DEV_SHOW_SECTIONS_ALL     "GENERAL,CAPABILITIES,BOND,VLAN,CONNECTIONS,WIFI-PROPERTIES,AP,WIRED-PROPERTIES,IP4,DHCP4,IP6,DHCP6"
104  	#define NMC_FIELDS_DEV_SHOW_SECTIONS_COMMON  "GENERAL,CAPABILITIES,BOND,VLAN,CONNECTIONS,WIFI-PROPERTIES,AP,WIRED-PROPERTIES,IP4,DHCP4,IP6,DHCP6"
105  	#endif
106  	
107  	/* Available fields for 'device show' - GENERAL part */
108  	static NmcOutputField nmc_fields_dev_show_general[] = {
109  		{"NAME",              N_("NAME"),              10},  /* 0 */
110  		{"DEVICE",            N_("DEVICE"),            10},  /* 1 */
111  		{"TYPE",              N_("TYPE"),              17},  /* 2 */
112  		{"VENDOR",            N_("VENDOR"),            20},  /* 3 */
113  		{"PRODUCT",           N_("PRODUCT"),           50},  /* 4 */
114  		{"DRIVER",            N_("DRIVER"),             9},  /* 5 */
115  		{"DRIVER-VERSION",    N_("DRIVER-VERSION"),    18},  /* 6 */
116  		{"FIRMWARE-VERSION",  N_("FIRMWARE-VERSION"),  18},  /* 7 */
117  		{"HWADDR",            N_("HWADDR"),            19},  /* 8 */
118  		{"STATE",             N_("STATE"),             14},  /* 9 */
119  		{"REASON",            N_("REASON"),            25},  /* 10 */
120  		{"UDI",               N_("UDI"),               64},  /* 11 */
121  		{"IP-IFACE",          N_("IP-IFACE"),          10},  /* 12 */
122  		{"NM-MANAGED",        N_("NM-MANAGED"),        15},  /* 13 */
123  		{"AUTOCONNECT",       N_("AUTOCONNECT"),       15},  /* 14 */
124  		{"FIRMWARE-MISSING",  N_("FIRMWARE-MISSING"),  18},  /* 15 */
125  		{"CONNECTION",        N_("CONNECTION"),        51},  /* 16 */
126  		{NULL, NULL, 0}
127  	};
128  	#define NMC_FIELDS_DEV_SHOW_GENERAL_ALL     "NAME,DEVICE,TYPE,VENDOR,PRODUCT,DRIVER,DRIVER-VERSION,FIRMWARE-VERSION,HWADDR,STATE,REASON,UDI,IP-IFACE,"\
129  	                                            "NM-MANAGED,AUTOCONNECT,FIRMWARE-MISSING,CONNECTION"
130  	#define NMC_FIELDS_DEV_SHOW_GENERAL_COMMON  "NAME,DEVICE,TYPE,VENDOR,PRODUCT,DRIVER,HWADDR,STATE"
131  	
132  	/* Available fields for 'device show' - CONNECTIONS part */
133  	static NmcOutputField nmc_fields_dev_show_connections[] = {
134  		{"NAME",                       N_("NAME"),                       10},  /* 0 */
135  		{"AVAILABLE-CONNECTION-PATHS", N_("AVAILABLE-CONNECTION-PATHS"), 80},  /* 1 */
136  		{"AVAILABLE-CONNECTIONS",      N_("AVAILABLE-CONNECTIONS"),      80},  /* 2 */
137  		{NULL, NULL, 0}
138  	};
139  	#define NMC_FIELDS_DEV_SHOW_CONNECTIONS_ALL     "AVAILABLE-CONNECTION-PATHS,AVAILABLE-CONNECTIONS"
140  	#define NMC_FIELDS_DEV_SHOW_CONNECTIONS_COMMON  "AVAILABLE-CONNECTION-PATHS,AVAILABLE-CONNECTIONS"
141  	
142  	/* Available fields for 'device show' - CAPABILITIES part */
143  	static NmcOutputField nmc_fields_dev_show_cap[] = {
144  		{"NAME",            N_("NAME"),            13},  /* 0 */
145  		{"CARRIER-DETECT",  N_("CARRIER-DETECT"),  16},  /* 1 */
146  		{"SPEED",           N_("SPEED"),           10},  /* 2 */
147  		{NULL,              NULL,                   0}
148  	};
149  	#define NMC_FIELDS_DEV_SHOW_CAP_ALL     "NAME,CARRIER-DETECT,SPEED"
150  	#define NMC_FIELDS_DEV_SHOW_CAP_COMMON  "NAME,CARRIER-DETECT,SPEED"
151  	
152  	/* Available fields for 'device show' - wired properties part */
153  	static NmcOutputField nmc_fields_dev_show_wired_prop[] = {
154  		{"NAME",            N_("NAME"),     18},  /* 0 */
155  		{"CARRIER",         N_("CARRIER"),  10},  /* 1 */
156  		{NULL,              NULL,            0}
157  	};
158  	#define NMC_FIELDS_DEV_SHOW_WIRED_PROP_ALL     "NAME,CARRIER"
159  	#define NMC_FIELDS_DEV_SHOW_WIRED_PROP_COMMON  "NAME,CARRIER"
160  	
161  	
162  	/* Available fields for 'device show' - wireless properties part */
163  	static NmcOutputField nmc_fields_dev_show_wifi_prop[] = {
164  		{"NAME",       N_("NAME"),   18},  /* 0 */
165  		{"WEP",        N_("WEP"),     5},  /* 1 */
166  		{"WPA",        N_("WPA"),     5},  /* 2 */
167  		{"WPA2",       N_("WPA2"),    6},  /* 3 */
168  		{"TKIP",       N_("TKIP"),    6},  /* 4 */
169  		{"CCMP",       N_("CCMP"),    6},  /* 5 */
170  		{"AP",         N_("AP"),      6},  /* 6 */
171  		{"ADHOC",      N_("ADHOC"),   6},  /* 7 */
172  		{NULL,         NULL,          0}
173  	};
174  	#define NMC_FIELDS_DEV_SHOW_WIFI_PROP_ALL     "NAME,WEP,WPA,WPA2,TKIP,CCMP,AP,ADHOC"
175  	#define NMC_FIELDS_DEV_SHOW_WIFI_PROP_COMMON  "NAME,WEP,WPA,WPA2,TKIP,CCMP,AP,ADHOC"
176  	
177  	#if WITH_WIMAX
178  	/* Available fields for 'device show' - wimax properties part */
179  	static NmcOutputField nmc_fields_dev_show_wimax_prop[] = {
180  		{"NAME",       N_("NAME"),     18},  /* 0 */
181  		{"CTR-FREQ",   N_("CTR-FREQ"),  7},  /* 1 */
182  		{"RSSI",       N_("RSSI"),      5},  /* 2 */
183  		{"CINR",       N_("CINR"),      5},  /* 3 */
184  		{"TX-POW",     N_("TX-POW"),    5},  /* 4 */
185  		{"BSID",       N_("BSID"),     18},  /* 5 */
186  		{NULL,         NULL,            0}
187  	};
188  	#define NMC_FIELDS_DEV_SHOW_WIMAX_PROP_ALL     "NAME,CTR-FREQ,RSSI,CINR,TX-POW,BSID"
189  	#define NMC_FIELDS_DEV_SHOW_WIMAX_PROP_COMMON  "NAME,CTR-FREQ,RSSI,CINR,TX-POW,BSID"
190  	#endif
191  	
192  	/* Available fields for 'device wifi list' */
193  	static NmcOutputField nmc_fields_dev_wifi_list[] = {
194  		{"NAME",       N_("NAME"),       15},  /* 0 */
195  		{"SSID",       N_("SSID"),       33},  /* 1 */
196  		{"SSID-HEX",   N_("SSID-HEX"),   66},  /* 2 */
197  		{"BSSID",      N_("BSSID"),      19},  /* 3 */
198  		{"MODE",       N_("MODE"),       16},  /* 4 */
199  		{"CHAN",       N_("CHAN"),        6},  /* 5 */
200  		{"FREQ",       N_("FREQ"),       10},  /* 6 */
201  		{"RATE",       N_("RATE"),       10},  /* 7 */
202  		{"SIGNAL",     N_("SIGNAL"),      8},  /* 8 */
203  		{"BARS",       N_("BARS"),        6},  /* 9 */
204  		{"SECURITY",   N_("SECURITY"),   10},  /* 10 */
205  		{"WPA-FLAGS",  N_("WPA-FLAGS"),  25},  /* 11 */
206  		{"RSN-FLAGS",  N_("RSN-FLAGS"),  25},  /* 12 */
207  		{"DEVICE",     N_("DEVICE"),     10},  /* 13 */
208  		{"ACTIVE",     N_("ACTIVE"),      8},  /* 14 */
209  		{"IN-USE",     N_("*"),           1},  /* 15 */
210  		{"DBUS-PATH",  N_("DBUS-PATH"),  46},  /* 16 */
211  		{NULL,         NULL,              0}
212  	};
213  	#define NMC_FIELDS_DEV_WIFI_LIST_ALL           "SSID,SSID-HEX,BSSID,MODE,CHAN,FREQ,RATE,SIGNAL,BARS,SECURITY,"\
214  	                                               "WPA-FLAGS,RSN-FLAGS,DEVICE,ACTIVE,IN-USE,DBUS-PATH"
215  	#define NMC_FIELDS_DEV_WIFI_LIST_COMMON        "IN-USE,SSID,MODE,CHAN,RATE,SIGNAL,BARS,SECURITY"
216  	#define NMC_FIELDS_DEV_WIFI_LIST_FOR_DEV_LIST  "NAME,"NMC_FIELDS_DEV_WIFI_LIST_COMMON
217  	
218  	#if WITH_WIMAX
219  	/* Available fields for 'device wimax list' */
220  	static NmcOutputField nmc_fields_dev_wimax_list[] = {
221  		{"NAME",       N_("NAME"),        15},  /* 0 */
222  		{"NSP",        N_("NSP"),         33},  /* 1 */
223  		{"SIGNAL",     N_("SIGNAL"),       8},  /* 2 */
224  		{"TYPE",       N_("TYPE"),        16},  /* 3 */
225  		{"DEVICE",     N_("DEVICE"),      10},  /* 4 */
226  		{"ACTIVE",     N_("ACTIVE"),       8},  /* 5 */
227  		{"DBUS-PATH",  N_("DBUS-PATH"),   46},  /* 6 */
228  		{NULL,         NULL,               0}
229  	};
230  	#define NMC_FIELDS_DEV_WIMAX_LIST_ALL           "NSP,SIGNAL,TYPE,DEVICE,ACTIVE,DBUS-PATH"
231  	#define NMC_FIELDS_DEV_WIMAX_LIST_COMMON        "NSP,SIGNAL,TYPE,DEVICE,ACTIVE"
232  	#define NMC_FIELDS_DEV_WIMAX_LIST_FOR_DEV_LIST  "NAME,"NMC_FIELDS_DEV_WIMAX_LIST_COMMON
233  	#endif
234  	
235  	/* Available fields for 'device show' - BOND part */
236  	static NmcOutputField nmc_fields_dev_show_bond_prop[] = {
237  		{"NAME",           N_("NAME"),     18},  /* 0 */
238  		{"SLAVES",         N_("SLAVES"),   20},  /* 1 */
239  		{NULL,             NULL,            0}
240  	};
241  	#define NMC_FIELDS_DEV_SHOW_BOND_PROP_ALL     "NAME,SLAVES"
242  	#define NMC_FIELDS_DEV_SHOW_BOND_PROP_COMMON  "NAME,SLAVES"
243  	
244  	/* Available fields for 'device show' - VLAN part */
245  	static NmcOutputField nmc_fields_dev_show_vlan_prop[] = {
246  		{"NAME",           N_("NAME"),     18},  /* 0 */
247  		{"ID",             N_("ID"),        5},  /* 1 */
248  		{NULL,             NULL,            0}
249  	};
250  	#define NMC_FIELDS_DEV_SHOW_VLAN_PROP_ALL     "NAME,ID"
251  	#define NMC_FIELDS_DEV_SHOW_VLAN_PROP_COMMON  "NAME,ID"
252  	
253  	
254  	/* glib main loop variable - defined in nmcli.c */
255  	extern GMainLoop *loop;
256  	
257  	static guint progress_id = 0;  /* ID of event source for displaying progress */
258  	
259  	static void
260  	usage (void)
261  	{
262  		fprintf (stderr,
263  		         _("Usage: nmcli device { COMMAND | help }\n\n"
264  	#if WITH_WIMAX
265  		         "  COMMAND := { status | show | disconnect | wifi | wimax }\n\n"
266  	#else
267  		         "  COMMAND := { status | show | disconnect | wifi }\n\n"
268  	#endif
269  		         "  status\n\n"
270  		         "  show [<ifname>]\n\n"
271  		         "  disconnect <ifname>\n\n"
272  		         "  wifi [list [ifname <ifname>] [bssid <BSSID>]]\n\n"
273  		         "  wifi connect <(B)SSID> [password <password>] [wep-key-type key|phrase] [ifname <ifname>] [bssid <BSSID>] [name <name>]\n\n"
274  		         "               [private yes|no]\n\n"
275  		         "  wifi rescan [[ifname] <ifname>]\n\n"
276  	#if WITH_WIMAX
277  		         "  wimax [list [ifname <ifname>] [nsp <name>]]\n\n"
278  	#endif
279  		         ));
280  	}
281  	
282  	/* quit main loop */
283  	static void
284  	quit (void)
285  	{
286  		if (progress_id) {
287  			g_source_remove (progress_id);
288  			nmc_terminal_erase_line ();
289  		}
290  	
291  		g_main_loop_quit (loop);  /* quit main loop */
292  	}
293  	
294  	static int
295  	compare_devices (const void *a, const void *b)
296  	{
297  		NMDevice *da = *(NMDevice **)a;
298  		NMDevice *db = *(NMDevice **)b;
299  		int cmp;
300  	
301  		/* Sort by later device states first */
302  		cmp = nm_device_get_state (db) - nm_device_get_state (da);
303  		if (cmp != 0)
304  			return cmp;
305  	
306  		cmp = g_strcmp0 (nm_device_get_type_description (da),
307  		                 nm_device_get_type_description (db));
308  		if (cmp != 0)
309  			return cmp;
310  	
311  		return g_strcmp0 (nm_device_get_iface (da),
312  		                  nm_device_get_iface (db));
313  	}
314  	
315  	static NMDevice **
316  	get_devices_sorted (NMClient *client)
317  	{
318  		const GPtrArray *devs;
319  		NMDevice **sorted;
320  	
321  		devs = nm_client_get_devices (client);
322  		if (!devs) {
323  			sorted = g_new (NMDevice *, 1);
324  			sorted[0] = NULL;
325  			return sorted;
326  		}
327  	
328  		sorted = g_new (NMDevice *, devs->len + 1);
329  		memcpy (sorted, devs->pdata, devs->len * sizeof (NMDevice *));
330  		sorted[devs->len] = NULL;
331  	
332  		qsort (sorted, devs->len, sizeof (NMDevice *), compare_devices);
333  		return sorted;
334  	}
335  	
336  	static char *
337  	ap_wpa_rsn_flags_to_string (NM80211ApSecurityFlags flags)
338  	{
339  		char *flags_str[16]; /* Enough space for flags and terminating NULL */
340  		char *ret_str;
341  		int i = 0;
342  	
343  		if (flags & NM_802_11_AP_SEC_PAIR_WEP40)
344  			flags_str[i++] = g_strdup ("pair_wpe40");
345  		if (flags & NM_802_11_AP_SEC_PAIR_WEP104)
346  			flags_str[i++] = g_strdup ("pair_wpe104");
347  		if (flags & NM_802_11_AP_SEC_PAIR_TKIP)
348  			flags_str[i++] = g_strdup ("pair_tkip");
349  		if (flags & NM_802_11_AP_SEC_PAIR_CCMP)
350  			flags_str[i++] = g_strdup ("pair_ccmp");
351  		if (flags & NM_802_11_AP_SEC_GROUP_WEP40)
352  			flags_str[i++] = g_strdup ("group_wpe40");
353  		if (flags & NM_802_11_AP_SEC_GROUP_WEP104)
354  			flags_str[i++] = g_strdup ("group_wpe104");
355  		if (flags & NM_802_11_AP_SEC_GROUP_TKIP)
356  			flags_str[i++] = g_strdup ("group_tkip");
357  		if (flags & NM_802_11_AP_SEC_GROUP_CCMP)
358  			flags_str[i++] = g_strdup ("group_ccmp");
359  		if (flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)
360  			flags_str[i++] = g_strdup ("psk");
361  		if (flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)
362  			flags_str[i++] = g_strdup ("802.1X");
363  	
364  		if (i == 0)
365  			flags_str[i++] = g_strdup (_("(none)"));
366  	
367  		flags_str[i] = NULL;
368  	
369  		ret_str = g_strjoinv (" ", flags_str);
370  	
371  		i = 0;
372  		while (flags_str[i])
373  			g_free (flags_str[i++]);
374  	
375  		return ret_str;
376  	}
377  	
378  	typedef struct {
379  		NmCli *nmc;
380  		int index;
381  		guint32 output_flags;
382  		const char* active_bssid;
383  		const char* device;
384  	} APInfo;
385  	
386  	static void
387  	fill_output_access_point (gpointer data, gpointer user_data)
388  	{
389  		NMAccessPoint *ap = NM_ACCESS_POINT (data);
390  		APInfo *info = (APInfo *) user_data;
391  		NmcOutputField *arr;
392  		gboolean active = FALSE;
393  		NM80211ApFlags flags;
394  		NM80211ApSecurityFlags wpa_flags, rsn_flags;
395  		guint32 freq, bitrate;
396  		guint8 strength;
397  		const GByteArray *ssid;
398  		const char *bssid;
399  		NM80211Mode mode;
400  		char *channel_str, *freq_str, *ssid_str, *ssid_hex_str, *bitrate_str,
401  		     *strength_str, *wpa_flags_str, *rsn_flags_str;
402  		GString *security_str;
403  		char *ap_name;
404  		const char *sig_level_0 = "____";
405  		const char *sig_level_1 = "���___";
406  		const char *sig_level_2 = "������__";
407  		const char *sig_level_3 = "���������_";
408  		const char *sig_level_4 = "������������";
409  		const char *sig_bars;
410  	
411  		if (info->active_bssid) {
412  			const char *current_bssid = nm_access_point_get_bssid (ap);
413  			if (current_bssid && !strcmp (current_bssid, info->active_bssid))
414  				active = TRUE;
415  		}
416  	
417  		/* Get AP properties */
418  		flags = nm_access_point_get_flags (ap);
419  		wpa_flags = nm_access_point_get_wpa_flags (ap);
420  		rsn_flags = nm_access_point_get_rsn_flags (ap);
421  		ssid = nm_access_point_get_ssid (ap);
422  		bssid = nm_access_point_get_bssid (ap);
423  		freq = nm_access_point_get_frequency (ap);
424  		mode = nm_access_point_get_mode (ap);
425  		bitrate = nm_access_point_get_max_bitrate (ap);
(1) Event unsigned_compare: This less-than-zero comparison of an unsigned value is never true. "nm_access_point_get_strength(ap) < 0".
426  		strength = CLAMP (nm_access_point_get_strength (ap), 0, 100);
427  	
428  		/* Convert to strings */
429  		ssid_str = nm_utils_ssid_to_utf8 (ssid);
430  		ssid_hex_str = ssid_to_hex ((const char *)ssid->data, ssid->len);
431  		channel_str = g_strdup_printf ("%u", nm_utils_wifi_freq_to_channel (freq));
432  		freq_str = g_strdup_printf (_("%u MHz"), freq);
433  		bitrate_str = g_strdup_printf (_("%u MB/s"), bitrate/1000);
434  		strength_str = g_strdup_printf ("%u", strength);
435  		wpa_flags_str = ap_wpa_rsn_flags_to_string (wpa_flags);
436  		rsn_flags_str = ap_wpa_rsn_flags_to_string (rsn_flags);
437  		sig_bars = strength > 80 ? sig_level_4 :
438  		           strength > 55 ? sig_level_3 :
439  		           strength > 30 ? sig_level_2 :
440  		           strength > 5  ? sig_level_1 :
441  		                           sig_level_0;
442  	
443  		security_str = g_string_new (NULL);
444  	
445  		if (   (flags & NM_802_11_AP_FLAGS_PRIVACY)
446  		    && (wpa_flags == NM_802_11_AP_SEC_NONE)
447  		    && (rsn_flags == NM_802_11_AP_SEC_NONE)) {
448  			g_string_append (security_str, _("WEP"));
449  			g_string_append_c (security_str, ' ');
450  		}
451  		if (wpa_flags != NM_802_11_AP_SEC_NONE) {
452  			g_string_append (security_str, _("WPA1"));
453  			g_string_append_c (security_str, ' ');
454  		}
455  		if (rsn_flags != NM_802_11_AP_SEC_NONE) {
456  			g_string_append (security_str, _("WPA2"));
457  			g_string_append_c (security_str, ' ');
458  		}
459  		if (   (wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)
460  		    || (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) {
461  			g_string_append   (security_str, _("802.1X"));
462  			g_string_append_c (security_str, ' ');
463  		}
464  	
465  		if (security_str->len > 0)
466  			g_string_truncate (security_str, security_str->len-1);  /* Chop off last space */
467  	
468  		arr = nmc_dup_fields_array (nmc_fields_dev_wifi_list,
469  		                            sizeof (nmc_fields_dev_wifi_list),
470  		                            info->output_flags);
471  	
472  		ap_name = g_strdup_printf ("AP[%d]", info->index++); /* AP */
473  		set_val_str  (arr, 0, ap_name);
474  		set_val_str  (arr, 1, ssid_str);
475  		set_val_str  (arr, 2, ssid_hex_str);
476  		set_val_strc (arr, 3, bssid);
477  		set_val_strc (arr, 4, mode == NM_802_11_MODE_ADHOC ? _("Ad-Hoc")
478  		                    : mode == NM_802_11_MODE_INFRA ? _("Infra")
479  		                    : _("N/A"));
480  		set_val_str  (arr, 5, channel_str);
481  		set_val_str  (arr, 6, freq_str);
482  		set_val_str  (arr, 7, bitrate_str);
483  		set_val_str  (arr, 8, strength_str);
484  		set_val_strc (arr, 9, sig_bars);
485  		set_val_str  (arr, 10, security_str->str);
486  		set_val_str  (arr, 11, wpa_flags_str);
487  		set_val_str  (arr, 12, rsn_flags_str);
488  		set_val_strc (arr, 13, info->device);
489  		set_val_strc (arr, 14, active ? _("yes") : _("no"));
490  		set_val_strc (arr, 15, active ? "*" : " ");
491  		set_val_strc (arr, 16, nm_object_get_path (NM_OBJECT (ap)));
492  	
493  		g_ptr_array_add (info->nmc->output_data, arr);
494  	
495  		g_string_free (security_str, FALSE);
496  	}
497  	
498  	#if WITH_WIMAX
499  	static void
500  	fill_output_wimax_nsp (NMWimaxNsp *nsp, NmCli *nmc, NMDevice *dev, int idx, guint32 o_flags)
501  	{
502  		NMDeviceWimax *wimax = NM_DEVICE_WIMAX (dev);
503  		char *nsp_name, *quality_str;
504  		const char *ntype;
505  		gboolean active = FALSE;
506  		NmcOutputField *arr;
507  	
508  		switch (nm_wimax_nsp_get_network_type (nsp)) {
509  		case NM_WIMAX_NSP_NETWORK_TYPE_HOME:
510  			ntype = _("Home");
511  			break;
512  		case NM_WIMAX_NSP_NETWORK_TYPE_PARTNER:
513  			ntype = _("Partner");
514  			break;
515  		case NM_WIMAX_NSP_NETWORK_TYPE_ROAMING_PARTNER:
516  			ntype = _("Roaming");
517  			break;
518  		default:
519  			ntype = _("Unknown");
520  			break;
521  		}
522  	
523  		if (nm_device_get_state (dev) == NM_DEVICE_STATE_ACTIVATED) {
524  			if (nsp == nm_device_wimax_get_active_nsp (wimax))
525  				active = TRUE;
526  		}
527  	
528  		quality_str = g_strdup_printf ("%u", nm_wimax_nsp_get_signal_quality (nsp));
529  		nsp_name = g_strdup_printf ("NSP[%d]", idx); /* NSP */
530  	
531  		arr = nmc_dup_fields_array (nmc_fields_dev_wimax_list,
532  		                            sizeof (nmc_fields_dev_wimax_list),
533  		                            o_flags);
534  		set_val_str  (arr, 0, nsp_name);
535  		set_val_strc (arr, 1, nm_wimax_nsp_get_name (nsp));
536  		set_val_str  (arr, 2, quality_str);
537  		set_val_strc (arr, 3, ntype);
538  		set_val_strc (arr, 4, nm_device_get_iface (dev));
539  		set_val_strc (arr, 5, active ? _("yes") : _("no"));
540  		set_val_strc (arr, 6, nm_object_get_path (NM_OBJECT (nsp)));
541  	
542  		g_ptr_array_add (nmc->output_data, arr);
543  	}
544  	#endif
545  	
546  	static const char *
547  	construct_header_name (const char *base, const char *spec)
548  	{
549  		static char header_name[128];
550  	
551  		if (spec == NULL)
552  			return base;
553  	
554  		g_strlcpy (header_name, base, sizeof (header_name));
555  		g_strlcat (header_name, " (", sizeof (header_name));
556  		g_strlcat (header_name, spec, sizeof (header_name));
557  		g_strlcat (header_name, ")", sizeof (header_name));
558  	
559  		return header_name;
560  	}
561  	
562  	static void
563  	show_device_info (NMDevice *device, NmCli *nmc)
564  	{
565  		GError *error = NULL;
566  		APInfo *info;
567  		const char *hwaddr = NULL;
568  		NMDeviceState state = NM_DEVICE_STATE_UNKNOWN;
569  		NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
570  		NMDeviceCapabilities caps;
571  		NMActiveConnection *acon;
572  		guint32 speed;
573  		char *speed_str = NULL;
574  		char *state_str = NULL;
575  		char *reason_str = NULL;
576  		GArray *sections_array;
577  		int k;
578  		char *fields_str;
579  		char *fields_all =    NMC_FIELDS_DEV_SHOW_SECTIONS_ALL;
580  		char *fields_common = NMC_FIELDS_DEV_SHOW_SECTIONS_COMMON;
581  		NmcOutputField *tmpl, *arr;
582  		size_t tmpl_len;
583  		gboolean was_output = FALSE;
584  		NMIP4Config *cfg4;
585  		NMIP6Config *cfg6;
586  		NMDHCP4Config *dhcp4;
587  		NMDHCP6Config *dhcp6;
588  		const char *base_hdr = _("Device details");
589  	
590  		if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0)
591  			fields_str = fields_common;
592  		else if (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0)
593  			fields_str = fields_all;
594  		else
595  			fields_str = nmc->required_fields;
596  	
597  		sections_array = parse_output_fields (fields_str, nmc_fields_dev_show_sections, &error);
598  		if (error) {
599  			if (error->code == 0)
600  				g_string_printf (nmc->return_text, _("Error: 'device show': %s"), error->message);
601  			else
602  				g_string_printf (nmc->return_text, _("Error: 'device show': %s; allowed fields: %s"),
603  				                 error->message, NMC_FIELDS_DEV_SHOW_SECTIONS_ALL);
604  			g_error_free (error);
605  			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
606  			return;
607  		}
608  	
609  		/* Main header */
610  		nmc->print_fields.header_name = (char *) construct_header_name (base_hdr, nm_device_get_iface (device));
611  		nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_DEV_SHOW_GENERAL_ALL,
612  		                                                 nmc_fields_dev_show_general, NULL);
613  	
614  		nmc_fields_dev_show_general[0].flags = NMC_OF_FLAG_MAIN_HEADER_ONLY;
615  		print_required_fields (nmc, nmc_fields_dev_show_general);
616  	
617  		/* Loop through the required sections and print them. */
618  		for (k = 0; k < sections_array->len; k++) {
619  			int section_idx = g_array_index (sections_array, int, k);
620  	
621  			if (nmc->print_output != NMC_PRINT_TERSE && !nmc->multiline_output && was_output)
622  				printf ("\n"); /* Print empty line between groups in tabular mode */
623  	
624  			was_output = FALSE;
625  	
626  			/* Remove any previous data */
627  			nmc_empty_output_fields (nmc);
628  	
629  			state = nm_device_get_state_reason (device, &reason);
630  	
631  			/* section GENERAL */
632  			if (!strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[0].name)) {
633  				tmpl = nmc_fields_dev_show_general;
634  				tmpl_len = sizeof (nmc_fields_dev_show_general);
635  				nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_DEV_SHOW_GENERAL_ALL, tmpl, NULL);
636  				arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_FIELD_NAMES);
637  				g_ptr_array_add (nmc->output_data, arr);
638  	
639  				if (NM_IS_DEVICE_ETHERNET (device))
640  					hwaddr = nm_device_ethernet_get_hw_address (NM_DEVICE_ETHERNET (device));
641  				else if (NM_IS_DEVICE_WIFI (device))
642  					hwaddr = nm_device_wifi_get_hw_address (NM_DEVICE_WIFI (device));
643  	#if WITH_WIMAX
644  				else if (NM_IS_DEVICE_WIMAX (device))
645  					hwaddr = nm_device_wimax_get_hw_address (NM_DEVICE_WIMAX (device));
646  	#endif
647  				else if (NM_IS_DEVICE_INFINIBAND (device))
648  					hwaddr = nm_device_infiniband_get_hw_address (NM_DEVICE_INFINIBAND (device));
649  				else if (NM_IS_DEVICE_BOND (device))
650  					hwaddr = nm_device_bond_get_hw_address (NM_DEVICE_BOND (device));
651  				else if (NM_IS_DEVICE_VLAN (device))
652  					hwaddr = nm_device_vlan_get_hw_address (NM_DEVICE_VLAN (device));
653  				else if (NM_IS_DEVICE_BRIDGE (device))
654  					hwaddr = nm_device_bridge_get_hw_address (NM_DEVICE_BRIDGE (device));
655  	
656  				state_str = g_strdup_printf ("%d (%s)", state, nmc_device_state_to_string (state));
657  				reason_str = g_strdup_printf ("%d (%s)", reason, nmc_device_reason_to_string (reason));
658  	
659  				arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
660  				set_val_strc (arr, 0, nmc_fields_dev_show_sections[0].name);  /* "GENERAL"*/
661  				set_val_strc (arr, 1, nm_device_get_iface (device));
662  				set_val_strc (arr, 2, nm_device_get_type_description (device));
663  				set_val_strc (arr, 3, nm_device_get_vendor (device));
664  				set_val_strc (arr, 4, nm_device_get_product (device));
665  				set_val_strc (arr, 5, nm_device_get_driver (device) ? nm_device_get_driver (device) : _("(unknown)"));
666  				set_val_strc (arr, 6, nm_device_get_driver_version (device));
667  				set_val_strc (arr, 7, nm_device_get_firmware_version (device));
668  				set_val_strc (arr, 8, hwaddr ? hwaddr : _("(unknown)"));
669  				set_val_str  (arr, 9, state_str);
670  				set_val_str  (arr, 10, reason_str);
671  				set_val_strc (arr, 11, nm_device_get_udi (device));
672  				set_val_strc (arr, 12, nm_device_get_ip_iface (device));
673  				set_val_strc (arr, 13, nm_device_get_managed (device) ? _("yes") : _("no"));
674  				set_val_strc (arr, 14, nm_device_get_autoconnect (device) ? _("yes") : _("no"));
675  				set_val_strc (arr, 15, nm_device_get_firmware_missing (device) ? _("yes") : _("no"));
676  				set_val_strc (arr, 16, ((acon = nm_device_get_active_connection (device)) ?
677  				                         nm_object_get_path (NM_OBJECT (acon)) : _("not connected")));
678  				g_ptr_array_add (nmc->output_data, arr);
679  	
680  				print_data (nmc);  /* Print all data */
681  				was_output = TRUE;
682  			}
683  	
684  			/* section CAPABILITIES */
685  			if (!strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[1].name)) {
686  				tmpl = nmc_fields_dev_show_cap;
687  				tmpl_len = sizeof (nmc_fields_dev_show_cap);
688  				nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_DEV_SHOW_CAP_ALL, tmpl, NULL);
689  				arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_FIELD_NAMES);
690  				g_ptr_array_add (nmc->output_data, arr);
691  	
692  				caps = nm_device_get_capabilities (device);
693  				speed = 0;
694  				if (NM_IS_DEVICE_ETHERNET (device)) {
695  					/* Speed in Mb/s */
696  					speed = nm_device_ethernet_get_speed (NM_DEVICE_ETHERNET (device));
697  				} else if (NM_IS_DEVICE_WIFI (device)) {
698  					/* Speed in b/s */
699  					speed = nm_device_wifi_get_bitrate (NM_DEVICE_WIFI (device));
700  					speed /= 1000;
701  				}
702  				speed_str = speed ? g_strdup_printf (_("%u Mb/s"), speed) : g_strdup (_("unknown"));
703  	
704  				arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
705  				set_val_strc (arr, 0, nmc_fields_dev_show_sections[1].name);  /* "CAPABILITIES" */
706  				set_val_strc (arr, 1, (caps & NM_DEVICE_CAP_CARRIER_DETECT) ? _("yes") : _("no"));
707  				set_val_str  (arr, 2, speed_str);
708  				g_ptr_array_add (nmc->output_data, arr);
709  	
710  				print_data (nmc);  /* Print all data */
711  				was_output = TRUE;
712  			}
713  	
714  			/* Wireless specific information */
715  			if ((NM_IS_DEVICE_WIFI (device))) {
716  				NMDeviceWifiCapabilities wcaps;
717  				NMAccessPoint *active_ap = NULL;
718  				const char *active_bssid = NULL;
719  				const GPtrArray *aps;
720  	
721  				/* section WIFI-PROPERTIES */
722  				if (!strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[2].name)) {
723  					wcaps = nm_device_wifi_get_capabilities (NM_DEVICE_WIFI (device));
724  	
725  					tmpl = nmc_fields_dev_show_wifi_prop;
726  					tmpl_len = sizeof (nmc_fields_dev_show_wifi_prop);
727  					nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_DEV_SHOW_WIFI_PROP_ALL, tmpl, NULL);
728  					arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_FIELD_NAMES);
729  					g_ptr_array_add (nmc->output_data, arr);
730  	
731  					arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
732  					set_val_strc (arr, 0, nmc_fields_dev_show_sections[2].name);  /* "WIFI-PROPERTIES" */
733  					set_val_strc (arr, 1, (wcaps & (NM_WIFI_DEVICE_CAP_CIPHER_WEP40 | NM_WIFI_DEVICE_CAP_CIPHER_WEP104)) ?
734  					                        _("yes") : _("no"));
735  					set_val_strc (arr, 2, (wcaps & NM_WIFI_DEVICE_CAP_WPA) ? _("yes") : _("no"));
736  					set_val_strc (arr, 3, (wcaps & NM_WIFI_DEVICE_CAP_RSN) ? _("yes") : _("no"));
737  					set_val_strc (arr, 4, (wcaps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP) ? _("yes") : _("no"));
738  					set_val_strc (arr, 5, (wcaps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP) ? _("yes") : _("no"));
739  					set_val_strc (arr, 6, (wcaps & NM_WIFI_DEVICE_CAP_AP) ? _("yes") : _("no"));
740  					set_val_strc (arr, 7, (wcaps & NM_WIFI_DEVICE_CAP_ADHOC) ? _("yes") : _("no"));
741  					g_ptr_array_add (nmc->output_data, arr);
742  	
743  					print_data (nmc);  /* Print all data */
744  					was_output = TRUE;
745  				}
746  	
747  				/* section AP */
748  				if (!strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[3].name)) {
749  					if (state == NM_DEVICE_STATE_ACTIVATED) {
750  						active_ap = nm_device_wifi_get_active_access_point (NM_DEVICE_WIFI (device));
751  						active_bssid = active_ap ? nm_access_point_get_bssid (active_ap) : NULL;
752  					}
753  	
754  					tmpl = nmc_fields_dev_wifi_list;
755  					tmpl_len = sizeof (nmc_fields_dev_wifi_list);
756  					nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_DEV_WIFI_LIST_FOR_DEV_LIST, tmpl, NULL);
757  					arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_FIELD_NAMES);
758  					g_ptr_array_add (nmc->output_data, arr);
759  	
760  					info = g_malloc0 (sizeof (APInfo));
761  					info->nmc = nmc;
762  					info->index = 1;
763  					info->output_flags = NMC_OF_FLAG_SECTION_PREFIX;
764  					info->active_bssid = active_bssid;
765  					info->device = nm_device_get_iface (device);
766  					aps = nm_device_wifi_get_access_points (NM_DEVICE_WIFI (device));
767  					if (aps && aps->len)
768  						g_ptr_array_foreach ((GPtrArray *) aps, fill_output_access_point, (gpointer) info);
769  					g_free (info);
770  					print_data (nmc);  /* Print all data */
771  					was_output = TRUE;
772  				}
773  			} else if (NM_IS_DEVICE_ETHERNET (device)) {
774  				/* WIRED-PROPERTIES */
775  				if (!strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[4].name)) {
776  					tmpl = nmc_fields_dev_show_wired_prop;
777  					tmpl_len = sizeof (nmc_fields_dev_show_wired_prop);
778  					nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_DEV_SHOW_WIRED_PROP_ALL, tmpl, NULL);
779  					arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_FIELD_NAMES);
780  					g_ptr_array_add (nmc->output_data, arr);
781  	
782  					arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
783  					set_val_strc (arr, 0, nmc_fields_dev_show_sections[4].name);  /* "WIRED-PROPERTIES" */
784  					set_val_strc (arr, 1, (nm_device_ethernet_get_carrier (NM_DEVICE_ETHERNET (device))) ?
785  					                        _("on") : _("off"));
786  					g_ptr_array_add (nmc->output_data, arr);
787  	
788  					print_data (nmc);  /* Print all data */
789  					was_output = TRUE;
790  				}
791  			}
792  	#if WITH_WIMAX
793  			else if (NM_IS_DEVICE_WIMAX (device)) {
794  				/* WIMAX-PROPERTIES */
795  				if (!strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[5].name)) {
796  					char *cfreq = NULL, *rssi = NULL, *cinr = NULL, *txpow = NULL;
797  					guint tmp_uint;
798  					gint tmp_int;
799  	
800  					/* Field names */
801  					tmpl = nmc_fields_dev_show_wimax_prop;
802  					tmpl_len = sizeof (nmc_fields_dev_show_wimax_prop);
803  					nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_DEV_SHOW_WIMAX_PROP_ALL, tmpl, NULL);
804  					arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_FIELD_NAMES);
805  					g_ptr_array_add (nmc->output_data, arr);
806  	
807  					/* Center frequency */
808  					tmp_uint = nm_device_wimax_get_center_frequency (NM_DEVICE_WIMAX (device));
809  					if (tmp_uint)
810  						cfreq = g_strdup_printf ("%'.1f MHz", (double) tmp_uint / 1000.0);
811  	
812  					/* RSSI */
813  					tmp_int = nm_device_wimax_get_rssi (NM_DEVICE_WIMAX (device));
814  					if (tmp_int)
815  						rssi = g_strdup_printf ("%d dBm", tmp_int);
816  	
817  					/* CINR */
818  					tmp_int = nm_device_wimax_get_cinr (NM_DEVICE_WIMAX (device));
819  					if (tmp_int)
820  						cinr = g_strdup_printf ("%d dB", tmp_int);
821  	
822  					/* TX Power */
823  					tmp_int = nm_device_wimax_get_tx_power (NM_DEVICE_WIMAX (device));
824  					if (tmp_int)
825  						txpow = g_strdup_printf ("%'.2f dBm", (float) tmp_int / 2.0);
826  	
827  					arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
828  					set_val_strc (arr, 0, nmc_fields_dev_show_sections[5].name);  /* "WIMAX-PROPERTIES" */
829  					set_val_str  (arr, 1, cfreq);
830  					set_val_str  (arr, 2, rssi);
831  					set_val_str  (arr, 3, cinr);
832  					set_val_str  (arr, 4, txpow);
833  					set_val_strc (arr, 5, nm_device_wimax_get_bsid (NM_DEVICE_WIMAX (device)));
834  					g_ptr_array_add (nmc->output_data, arr);
835  	
836  					print_data (nmc);  /* Print all data */
837  					was_output = TRUE;
838  				}
839  	
840  				/* section NSP */
841  				if (!strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[6].name)) {
842  					const GPtrArray *nsps;
843  					int g, idx = 1;
844  	
845  					tmpl = nmc_fields_dev_wimax_list;
846  					tmpl_len = sizeof (nmc_fields_dev_wimax_list);
847  					nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_DEV_WIMAX_LIST_FOR_DEV_LIST, tmpl, NULL);
848  					arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_FIELD_NAMES);
849  					g_ptr_array_add (nmc->output_data, arr);
850  	
851  					nsps = nm_device_wimax_get_nsps (NM_DEVICE_WIMAX (device));
852  					for (g = 0; nsps && g < nsps->len; g++) {
853  						NMWimaxNsp *nsp = g_ptr_array_index (nsps, g);
854  	
855  						fill_output_wimax_nsp (nsp, nmc, device, idx++, NMC_OF_FLAG_SECTION_PREFIX);
856  					}
857  					print_data (nmc);  /* Print all data */
858  					was_output = TRUE;
859  				}
860  			}
861  	#endif
862  	
863  			/* IP configuration info */
864  			cfg4 = nm_device_get_ip4_config (device);
865  			cfg6 = nm_device_get_ip6_config (device);
866  			dhcp4 = nm_device_get_dhcp4_config (device);
867  			dhcp6 = nm_device_get_dhcp6_config (device);
868  	
869  			/* IP4 */
870  			if (cfg4 && !strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[7].name))
871  				was_output = print_ip4_config (cfg4, nmc, nmc_fields_dev_show_sections[7].name);
872  	
873  			/* DHCP4 */
874  			if (dhcp4 && !strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[8].name))
875  				was_output = print_dhcp4_config (dhcp4, nmc, nmc_fields_dev_show_sections[8].name);
876  	
877  			/* IP6 */
878  			if (cfg6 && !strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[9].name))
879  				was_output = print_ip6_config (cfg6, nmc, nmc_fields_dev_show_sections[9].name);
880  	
881  			/* DHCP6 */
882  			if (dhcp6 && !strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[10].name))
883  				was_output = print_dhcp6_config (dhcp6, nmc, nmc_fields_dev_show_sections[10].name);
884  	
885  			/* Bond-specific information */
886  			if ((NM_IS_DEVICE_BOND (device))) {
887  				if (!strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[11].name)) {
888  					const GPtrArray *slaves;
889  					GString *bond_slaves_str;
890  					int idx;
891  	
892  					bond_slaves_str = g_string_new (NULL);
893  					slaves = nm_device_bond_get_slaves (NM_DEVICE_BOND (device));
894  					for (idx = 0; slaves && idx < slaves->len; idx++) {
895  						NMDevice *slave = g_ptr_array_index (slaves, idx);
896  						const char *iface = nm_device_get_iface (slave);
897  	
898  						if (iface) {
899  							g_string_append (bond_slaves_str, iface);
900  							g_string_append_c (bond_slaves_str, ' ');
901  						}
902  					}
903  					if (bond_slaves_str->len > 0)
904  						g_string_truncate (bond_slaves_str, bond_slaves_str->len-1);  /* Chop off last space */
905  	
906  					tmpl = nmc_fields_dev_show_bond_prop;
907  					tmpl_len = sizeof (nmc_fields_dev_show_bond_prop);
908  					nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_DEV_SHOW_BOND_PROP_ALL, tmpl, NULL);
909  					arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_FIELD_NAMES);
910  					g_ptr_array_add (nmc->output_data, arr);
911  	
912  					arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
913  					set_val_strc (arr, 0, nmc_fields_dev_show_sections[11].name);  /* "BOND" */
914  					set_val_str  (arr, 1, bond_slaves_str->str);
915  					g_ptr_array_add (nmc->output_data, arr);
916  	
917  					print_data (nmc);  /* Print all data */
918  	
919  					g_string_free (bond_slaves_str, FALSE);
920  					was_output = TRUE;
921  				}
922  			}
923  	
924  			/* VLAN-specific information */
925  			if ((NM_IS_DEVICE_VLAN (device))) {
926  				if (!strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[12].name)) {
927  					char * vlan_id_str = g_strdup_printf ("%u", nm_device_vlan_get_vlan_id (NM_DEVICE_VLAN (device)));
928  	
929  					tmpl = nmc_fields_dev_show_vlan_prop;
930  					tmpl_len = sizeof (nmc_fields_dev_show_vlan_prop);
931  					nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_DEV_SHOW_VLAN_PROP_ALL, tmpl, NULL);
932  					arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_FIELD_NAMES);
933  					g_ptr_array_add (nmc->output_data, arr);
934  	
935  					arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
936  					set_val_strc (arr, 0, nmc_fields_dev_show_sections[12].name);  /* "VLAN" */
937  					set_val_str  (arr, 1, vlan_id_str);
938  					g_ptr_array_add (nmc->output_data, arr);
939  	
940  					print_data (nmc);  /* Print all data */
941  	
942  					was_output = TRUE;
943  				}
944  			}
945  	
946  			/* section CONNECTIONS */
947  			if (!strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[13].name)) {
948  				const GPtrArray *avail_cons;
949  				GString *ac_paths_str;
950  				char **ac_arr = NULL;
951  				int i;
952  	
953  				tmpl = nmc_fields_dev_show_connections;
954  				tmpl_len = sizeof (nmc_fields_dev_show_connections);
955  				nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_DEV_SHOW_CONNECTIONS_ALL, tmpl, NULL);
956  				arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_FIELD_NAMES);
957  				g_ptr_array_add (nmc->output_data, arr);
958  	
959  				/* available-connections */
960  				avail_cons = nm_device_get_available_connections (device);
961  				ac_paths_str = g_string_new (NULL);
962  				if (avail_cons && avail_cons->len) {
963  					ac_arr = g_new (char *, avail_cons->len + 1);
964  					ac_arr[avail_cons->len] = NULL;
965  				}
966  				for (i = 0; avail_cons && (i < avail_cons->len); i++) {
967  					NMRemoteConnection *avail_con = g_ptr_array_index (avail_cons, i);
968  					const char *ac_path = nm_connection_get_path (NM_CONNECTION (avail_con));
969  					const char *ac_id = nm_connection_get_id (NM_CONNECTION (avail_con));
970  					const char *ac_uuid = nm_connection_get_uuid (NM_CONNECTION (avail_con));
971  	
972  					ac_arr[i] = g_strdup_printf ("%s | %s", ac_uuid, ac_id);
973  	
974  					if (i == 0)
975  						g_string_printf (ac_paths_str, "%s/{", NM_DBUS_PATH_SETTINGS);
976  					else
977  						g_string_append_c (ac_paths_str, ',');
978  					g_string_append (ac_paths_str, strrchr (ac_path, '/') + 1);
979  				}
980  				if (ac_paths_str->len > 0)
981  					g_string_append_c (ac_paths_str, '}');
982  	
983  				arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
984  				set_val_strc (arr, 0, nmc_fields_dev_show_sections[13].name);  /* "CONNECTIONS" */
985  				set_val_str  (arr, 1, ac_paths_str->str);
986  				set_val_arr  (arr, 2, (ac_arr));
987  				g_ptr_array_add (nmc->output_data, arr);
988  	
989  				print_data (nmc);  /* Print all data */
990  	
991  				g_string_free (ac_paths_str, FALSE);
992  				was_output = TRUE;
993  			}
994  		}
995  	
996  		if (sections_array)
997  			g_array_free (sections_array, TRUE);
998  	}
999  	
1000 	static void
1001 	fill_output_device_status (NMDevice *device, NmCli *nmc)
1002 	{
1003 		NmcOutputField *arr = nmc_dup_fields_array (nmc_fields_dev_status,
1004 		                                            sizeof (nmc_fields_dev_status),
1005 		                                            0);
1006 	
1007 		set_val_strc (arr, 0, nm_device_get_iface (device));
1008 		set_val_strc (arr, 1, nm_device_get_type_description (device));
1009 		set_val_strc (arr, 2, nmc_device_state_to_string (nm_device_get_state (device)));
1010 		set_val_strc (arr, 3, nm_object_get_path (NM_OBJECT (device)));
1011 	
1012 		g_ptr_array_add (nmc->output_data, arr);
1013 	}
1014 	
1015 	static NMCResultCode
1016 	do_devices_status (NmCli *nmc, int argc, char **argv)
1017 	{
1018 		GError *error = NULL;
1019 		NMDevice **devices;
1020 		int i;
1021 		char *fields_str;
1022 		char *fields_all =    NMC_FIELDS_DEV_STATUS_ALL;
1023 		char *fields_common = NMC_FIELDS_DEV_STATUS_COMMON;
1024 		NmcOutputField *tmpl, *arr;
1025 		size_t tmpl_len;
1026 	
1027 		while (argc > 0) {
1028 			fprintf (stderr, _("Unknown parameter: %s\n"), *argv);
1029 			argc--;
1030 			argv++;
1031 		}
1032 	
1033 		if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0)
1034 			fields_str = fields_common;
1035 		else if (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0)
1036 			fields_str = fields_all;
1037 		else
1038 			fields_str = nmc->required_fields;
1039 	
1040 		tmpl = nmc_fields_dev_status;
1041 		tmpl_len = sizeof (nmc_fields_dev_status);
1042 		nmc->print_fields.indices = parse_output_fields (fields_str, tmpl, &error);
1043 	
1044 		if (error) {
1045 			if (error->code == 0)
1046 				g_string_printf (nmc->return_text, _("Error: 'device status': %s"), error->message);
1047 			else
1048 				g_string_printf (nmc->return_text, _("Error: 'device status': %s; allowed fields: %s"),
1049 				                 error->message, NMC_FIELDS_DEV_STATUS_ALL);
1050 			g_error_free (error);
1051 			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
1052 			goto error;
1053 		}
1054 	
1055 		nmc->get_client (nmc);
1056 	
1057 		if (!nm_client_get_manager_running (nmc->client)) {
1058 			g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
1059 			nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
1060 			goto error;
1061 		}
1062 	
1063 		if (!nmc_versions_match (nmc))
1064 			goto error;
1065 	
1066 		/* Add headers */
1067 		nmc->print_fields.header_name = _("Status of devices");
1068 		arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_MAIN_HEADER_ADD | NMC_OF_FLAG_FIELD_NAMES);
1069 		g_ptr_array_add (nmc->output_data, arr);
1070 	
1071 		devices = get_devices_sorted (nmc->client);
1072 		for (i = 0; devices[i]; i++)
1073 			fill_output_device_status (devices[i], nmc);
1074 	
1075 		/* Now print all data */
1076 		print_data (nmc);
1077 	
1078 		g_free (devices);
1079 	
1080 		return NMC_RESULT_SUCCESS;
1081 	
1082 	error:
1083 		return nmc->return_value;
1084 	}
1085 	
1086 	static NMCResultCode
1087 	do_devices_show (NmCli *nmc, int argc, char **argv)
1088 	{
1089 		NMDevice **devices = NULL;
1090 		NMDevice *device = NULL;
1091 		const char *ifname = NULL;
1092 		int i;
1093 	
1094 		if (argc == 1)
1095 			ifname = *argv;
1096 		else if (argc > 1) {
1097 			g_string_printf (nmc->return_text, _("Error: invalid extra argument '%s'."), *(argv+1));
1098 			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
1099 			goto error;
1100 		}
1101 	
1102 		nmc->get_client (nmc);
1103 	
1104 		if (!nm_client_get_manager_running (nmc->client)) {
1105 			g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
1106 			nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
1107 			goto error;
1108 		}
1109 	
1110 		if (!nmc_versions_match (nmc))
1111 			goto error;
1112 	
1113 		devices = get_devices_sorted (nmc->client);
1114 	
1115 		if (ifname) {
1116 			/* Interface specified; show details only for the device */
1117 			for (i = 0; devices[i]; i++) {
1118 				NMDevice *candidate = devices[i];
1119 				const char *dev_iface = nm_device_get_iface (candidate);
1120 	
1121 				if (!g_strcmp0 (dev_iface, ifname))
1122 					device = candidate;
1123 			}
1124 			if (!device) {
1125 				g_string_printf (nmc->return_text, _("Error: Device '%s' not found."), ifname);
1126 				nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
1127 				goto error;
1128 			}
1129 			show_device_info (device, nmc);
1130 		} else {
1131 			/* Show details for all devices */
1132 			for (i = 0; devices[i]; i++) {
1133 				nmc_empty_output_fields (nmc);
1134 				show_device_info (devices[i], nmc);
1135 				if (devices[i + 1])
1136 					printf ("\n"); /* Empty line */
1137 			}
1138 		}
1139 	
1140 	error:
1141 		g_free (devices);
1142 		return nmc->return_value;
1143 	}
1144 	
1145 	static void
1146 	device_state_cb (NMDevice *device, GParamSpec *pspec, gpointer user_data)
1147 	{
1148 		NmCli *nmc = (NmCli *) user_data;
1149 		NMDeviceState state;
1150 	
1151 		state = nm_device_get_state (device);
1152 	
1153 		if (state == NM_DEVICE_STATE_DISCONNECTED) {
1154 			g_string_printf (nmc->return_text, _("Success: Device '%s' successfully disconnected."), nm_device_get_iface (device));
1155 			quit ();
1156 		}
1157 	}
1158 	
1159 	static gboolean
1160 	timeout_cb (gpointer user_data)
1161 	{
1162 		/* Time expired -> exit nmcli */
1163 	
1164 		NmCli *nmc = (NmCli *) user_data;
1165 	
1166 		g_string_printf (nmc->return_text, _("Error: Timeout %d sec expired."), nmc->timeout);
1167 		nmc->return_value = NMC_RESULT_ERROR_TIMEOUT_EXPIRED;
1168 		quit ();
1169 		return FALSE;
1170 	}
1171 	
1172 	static gboolean
1173 	progress_cb (gpointer user_data)
1174 	{
1175 		NMDevice *device = (NMDevice *) user_data;
1176 	
1177 		nmc_terminal_show_progress (device ? nmc_device_state_to_string (nm_device_get_state (device)) : "");
1178 	
1179 		return TRUE;
1180 	}
1181 	
1182 	static void
1183 	disconnect_device_cb (NMDevice *device, GError *error, gpointer user_data)
1184 	{
1185 		NmCli *nmc = (NmCli *) user_data;
1186 		NMDeviceState state;
1187 	
1188 		if (error) {
1189 			g_string_printf (nmc->return_text, _("Error: Device '%s' (%s) disconnecting failed: %s"),
1190 			                 nm_device_get_iface (device),
1191 			                 nm_object_get_path (NM_OBJECT (device)),
1192 			                 error->message ? error->message : _("(unknown)"));
1193 			nmc->return_value = NMC_RESULT_ERROR_DEV_DISCONNECT;
1194 			quit ();
1195 		} else {
1196 			state = nm_device_get_state (device);
1197 	
1198 			if (nmc->nowait_flag || state == NM_DEVICE_STATE_DISCONNECTED) {
1199 				/* Don't want to wait or device already disconnected */
1200 				if (state == NM_DEVICE_STATE_DISCONNECTED) {
1201 					if (nmc->print_output == NMC_PRINT_PRETTY)
1202 						nmc_terminal_erase_line ();
1203 					printf (_("Device '%s' has been disconnected.\n"), nm_device_get_iface (device));
1204 				}
1205 				quit ();
1206 			} else {
1207 				g_signal_connect (device, "notify::state", G_CALLBACK (device_state_cb), nmc);
1208 				/* Start timer not to loop forever if "notify::state" signal is not issued */
1209 				g_timeout_add_seconds (nmc->timeout, timeout_cb, nmc);
1210 			}
1211 	
1212 		}
1213 	}
1214 	
1215 	static NMCResultCode
1216 	do_device_disconnect (NmCli *nmc, int argc, char **argv)
1217 	{
1218 		NMDevice **devices;
1219 		NMDevice *device = NULL;
1220 		const char *ifname = NULL;
1221 		char *ifname_ask = NULL;
1222 		int i;
1223 	
1224 		/* Set default timeout for disconnect operation. */
1225 		if (nmc->timeout == -1)
1226 			nmc->timeout = 10;
1227 	
1228 		if (argc == 0) {
1229 			if (nmc->ask) {
1230 				ifname = ifname_ask = nmc_get_user_input (_("Interface: "));
1231 				// TODO: list available devices when just Enter is pressed ?
1232 			}
1233 			if (!ifname_ask) {
1234 				g_string_printf (nmc->return_text, _("Error: No interface specified."));
1235 				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
1236 				goto error;
1237 			}
1238 		} else {
1239 			ifname = *argv;
1240 		}
1241 	
1242 		if (!ifname) {
1243 			g_string_printf (nmc->return_text, _("Error: No interface specified."));
1244 			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
1245 			goto error;
1246 		}
1247 	
1248 		if (next_arg (&argc, &argv) == 0) {
1249 			g_string_printf (nmc->return_text, _("Error: extra argument not allowed: '%s'."), *argv);
1250 			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
1251 			goto error;
1252 		}
1253 	
1254 		nmc->get_client (nmc);
1255 		if (!nm_client_get_manager_running (nmc->client)) {
1256 			g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
1257 			nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
1258 			goto error;
1259 		}
1260 	
1261 		if (!nmc_versions_match (nmc))
1262 			goto error;
1263 	
1264 		devices = get_devices_sorted (nmc->client);
1265 		for (i = 0; devices[i]; i++) {
1266 			NMDevice *candidate = devices[i];
1267 			const char *dev_iface = nm_device_get_iface (candidate);
1268 	
1269 			if (!g_strcmp0 (dev_iface, ifname))
1270 				device = candidate;
1271 		}
1272 		g_free (devices);
1273 	
1274 		if (!device) {
1275 			g_string_printf (nmc->return_text, _("Error: Device '%s' not found."), ifname);
1276 			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
1277 			goto error;
1278 		}
1279 	
1280 		/*
1281 		 * Use nowait_flag instead of should_wait, because exiting has to be postponed
1282 		 * till disconnect_device_cb() is called, giving NM time to check our permissions.
1283 		 */
1284 		nmc->nowait_flag = (nmc->timeout == 0);
1285 		nmc->should_wait = TRUE;
1286 		nm_device_disconnect (device, disconnect_device_cb, nmc);
1287 	
1288 		/* Start progress indication */
1289 		if (nmc->print_output == NMC_PRINT_PRETTY)
1290 			progress_id = g_timeout_add (120, progress_cb, device);
1291 	
1292 	error:
1293 		return nmc->return_value;
1294 	}
1295 	
1296 	static void
1297 	show_acces_point_info (NMDevice *device, NmCli *nmc)
1298 	{
1299 		NMAccessPoint *active_ap = NULL;
1300 		const char *active_bssid = NULL;
1301 		const GPtrArray *aps;
1302 		APInfo *info;
1303 		NmcOutputField *arr;
1304 	
1305 		if (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED) {
1306 			active_ap = nm_device_wifi_get_active_access_point (NM_DEVICE_WIFI (device));
1307 			active_bssid = active_ap ? nm_access_point_get_bssid (active_ap) : NULL;
1308 		}
1309 	
1310 		arr = nmc_dup_fields_array (nmc_fields_dev_wifi_list, sizeof (nmc_fields_dev_wifi_list),
1311 		                            NMC_OF_FLAG_MAIN_HEADER_ADD | NMC_OF_FLAG_FIELD_NAMES);
1312 		g_ptr_array_add (nmc->output_data, arr);
1313 	
1314 		info = g_malloc0 (sizeof (APInfo));
1315 		info->nmc = nmc;
1316 		info->index = 1;
1317 		info->output_flags = 0;
1318 		info->active_bssid = active_bssid;
1319 		info->device = nm_device_get_iface (device);
1320 		aps = nm_device_wifi_get_access_points (NM_DEVICE_WIFI (device));
1321 		if (aps && aps->len)
1322 			g_ptr_array_foreach ((GPtrArray *) aps, fill_output_access_point, (gpointer) info);
1323 	
1324 		print_data (nmc);  /* Print all data */
1325 		nmc_empty_output_fields (nmc);
1326 		g_free (info);
1327 	}
1328 	
1329 	static NMCResultCode
1330 	do_device_wifi_list (NmCli *nmc, int argc, char **argv)
1331 	{
1332 		GError *error = NULL;
1333 		NMDevice *device = NULL;
1334 		NMAccessPoint *ap = NULL;
1335 		const char *ifname = NULL;
1336 		const char *bssid_user = NULL;
1337 		NMDevice **devices = NULL;
1338 		const GPtrArray *aps;
1339 		APInfo *info;
1340 		int i, j;
1341 		char *fields_str;
1342 		char *fields_all =    NMC_FIELDS_DEV_WIFI_LIST_ALL;
1343 		char *fields_common = NMC_FIELDS_DEV_WIFI_LIST_COMMON;
1344 		NmcOutputField *tmpl, *arr;
1345 		size_t tmpl_len;
1346 		const char *base_hdr = _("Wi-Fi scan list");
1347 	
1348 		while (argc > 0) {
1349 			if (strcmp (*argv, "ifname") == 0) {
1350 				if (next_arg (&argc, &argv) != 0) {
1351 					g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
1352 					nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
1353 					goto error;
1354 				}
1355 				ifname = *argv;
1356 			} else if (strcmp (*argv, "bssid") == 0 || strcmp (*argv, "hwaddr") == 0) {
1357 				/* hwaddr is deprecated and will be removed later */
1358 				if (next_arg (&argc, &argv) != 0) {
1359 					g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
1360 					nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
1361 					goto error;
1362 				}
1363 				bssid_user = *argv;
1364 			} else {
1365 				fprintf (stderr, _("Unknown parameter: %s\n"), *argv);
1366 			}
1367 	
1368 			argc--;
1369 			argv++;
1370 		}
1371 	
1372 		if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0)
1373 			fields_str = fields_common;
1374 		else if (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0)
1375 			fields_str = fields_all;
1376 		else
1377 			fields_str = nmc->required_fields;
1378 	
1379 		tmpl = nmc_fields_dev_wifi_list;
1380 		tmpl_len = sizeof (nmc_fields_dev_wifi_list);
1381 		nmc->print_fields.indices = parse_output_fields (fields_str, tmpl, &error);
1382 	
1383 		if (error) {
1384 			if (error->code == 0)
1385 				g_string_printf (nmc->return_text, _("Error: 'device wifi': %s"), error->message);
1386 			else
1387 				g_string_printf (nmc->return_text, _("Error: 'device wifi': %s; allowed fields: %s"),
1388 				                 error->message, NMC_FIELDS_DEV_WIFI_LIST_ALL);
1389 			g_error_free (error);
1390 			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
1391 			goto error;
1392 		}
1393 	
1394 		nmc->get_client (nmc);
1395 	
1396 		if (!nm_client_get_manager_running (nmc->client)) {
1397 			g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
1398 			nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
1399 			goto error;
1400 		}
1401 	
1402 		if (!nmc_versions_match (nmc))
1403 			goto error;
1404 	
1405 		devices = get_devices_sorted (nmc->client);
1406 		if (ifname) {
1407 			/* Device specified - list only APs of this interface */
1408 			for (i = 0; devices[i]; i++) {
1409 				NMDevice *candidate = devices[i];
1410 				const char *dev_iface = nm_device_get_iface (candidate);
1411 	
1412 				if (!g_strcmp0 (dev_iface, ifname)) {
1413 					device = candidate;
1414 					break;
1415 				}
1416 			}
1417 			if (!device) {
1418 				g_string_printf (nmc->return_text, _("Error: Device '%s' not found."), ifname);
1419 				nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
1420 				goto error;
1421 			}
1422 	
1423 			/* Main header name */
1424 			nmc->print_fields.header_name = (char *) construct_header_name (base_hdr, ifname);
1425 	
1426 			if (NM_IS_DEVICE_WIFI (device)) {
1427 				if (bssid_user) {
1428 					/* Specific AP requested - list only that */
1429 					aps = nm_device_wifi_get_access_points (NM_DEVICE_WIFI (device));
1430 					for (j = 0; aps && (j < aps->len); j++) {
1431 						char *bssid_up;
1432 						NMAccessPoint *candidate_ap = g_ptr_array_index (aps, j);
1433 						const char *candidate_bssid = nm_access_point_get_bssid (candidate_ap);
1434 	
1435 						bssid_up = g_ascii_strup (bssid_user, -1);
1436 						if (!strcmp (bssid_up, candidate_bssid))
1437 							ap = candidate_ap;
1438 						g_free (bssid_up);
1439 					}
1440 					if (!ap) {
1441 						g_string_printf (nmc->return_text, _("Error: Access point with bssid '%s' not found."),
1442 						                 bssid_user);
1443 						nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
1444 						goto error;
1445 					}
1446 					/* Add headers (field names) */
1447 					arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_MAIN_HEADER_ADD | NMC_OF_FLAG_FIELD_NAMES);
1448 					g_ptr_array_add (nmc->output_data, arr);
1449 	
1450 					info = g_malloc0 (sizeof (APInfo));
1451 					info->nmc = nmc;
1452 					info->index = 1;
1453 					info->output_flags = 0;
1454 					info->active_bssid = NULL;
1455 					info->device = nm_device_get_iface (device);
1456 	
1457 					fill_output_access_point (ap, info);
1458 	
1459 					print_data (nmc);  /* Print all data */
1460 					g_free (info);
1461 				} else {
1462 					show_acces_point_info (device, nmc);
1463 				}
1464 			} else {
1465 				g_string_printf (nmc->return_text, _("Error: Device '%s' is not a Wi-Fi device."), ifname);
1466 				nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
1467 				goto error;
1468 			}
1469 		} else {
1470 			/* List APs for all devices */
1471 			if (bssid_user) {
1472 				/* Specific AP requested - list only that */
1473 				for (i = 0; devices[i]; i++) {
1474 					NMDevice *dev = devices[i];
1475 	
1476 					if (!NM_IS_DEVICE_WIFI (dev))
1477 						continue;
1478 	
1479 					/* Main header name */
1480 					nmc->print_fields.header_name = (char *) construct_header_name (base_hdr, nm_device_get_iface (dev));
1481 	
1482 					arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_MAIN_HEADER_ADD | NMC_OF_FLAG_FIELD_NAMES);
1483 					g_ptr_array_add (nmc->output_data, arr);
1484 	
1485 					aps = nm_device_wifi_get_access_points (NM_DEVICE_WIFI (dev));
1486 					for (j = 0; aps && (j < aps->len); j++) {
1487 						char *bssid_up;
1488 						NMAccessPoint *candidate_ap = g_ptr_array_index (aps, j);
1489 						const char *candidate_bssid = nm_access_point_get_bssid (candidate_ap);
1490 	
1491 						bssid_up = g_ascii_strup (bssid_user, -1);
1492 						if (!strcmp (bssid_up, candidate_bssid)) {
1493 							ap = candidate_ap;
1494 	
1495 							info = g_malloc0 (sizeof (APInfo));
1496 							info->nmc = nmc;
1497 							info->index = 1;
1498 							info->output_flags = 0;
1499 							info->active_bssid = NULL;
1500 							info->device = nm_device_get_iface (dev);
1501 							fill_output_access_point (ap, info);
1502 							g_free (info);
1503 						}
1504 						g_free (bssid_up);
1505 					}
1506 					print_data (nmc);  /* Print all data */
1507 					nmc_empty_output_fields (nmc);
1508 				}
1509 				if (!ap) {
1510 					g_string_printf (nmc->return_text, _("Error: Access point with bssid '%s' not found."),
1511 					                 bssid_user);
1512 					nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
1513 					goto error;
1514 				}
1515 			} else {
1516 				for (i = 0; devices[i]; i++) {
1517 					NMDevice *dev = devices[i];
1518 	
1519 					/* Main header name */
1520 					nmc->print_fields.header_name = (char *) construct_header_name (base_hdr,
1521 					                                                                nm_device_get_iface (dev));
1522 					if (NM_IS_DEVICE_WIFI (dev))
1523 						show_acces_point_info (dev, nmc);
1524 				}
1525 			}
1526 		}
1527 	
1528 	error:
1529 		g_free (devices);
1530 		return nmc->return_value;
1531 	}
1532 	
1533 	static void
1534 	monitor_device_state_cb (NMDevice *device, GParamSpec *pspec, gpointer user_data)
1535 	{
1536 		NmCli *nmc = (NmCli *) user_data;
1537 		NMDeviceState state;
1538 		NMDeviceStateReason reason;
1539 	
1540 		state = nm_device_get_state_reason (device, &reason);
1541 	
1542 		if (state == NM_DEVICE_STATE_ACTIVATED) {
1543 			NMActiveConnection *active = nm_device_get_active_connection (device);
1544 	
1545 			if (nmc->print_output == NMC_PRINT_PRETTY)
1546 				nmc_terminal_erase_line ();
1547 			printf (_("Connection with UUID '%s' created and activated on device '%s'\n"),
1548 			        nm_active_connection_get_uuid (active), nm_device_get_iface (device));
1549 			quit ();
1550 		} else if (state == NM_DEVICE_STATE_FAILED) {
1551 			g_string_printf (nmc->return_text, _("Error: Connection activation failed: (%d) %s."),
1552 			                 reason, nmc_device_reason_to_string (reason));
1553 			nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
1554 			quit ();
1555 		}
1556 	}
1557 	
1558 	typedef struct {
1559 		NmCli *nmc;
1560 		NMDevice *device;
1561 	} AddAndActivateInfo;
1562 	
1563 	static void
1564 	add_and_activate_cb (NMClient *client,
1565 	                     NMActiveConnection *active,
1566 	                     const char *connection_path,
1567 	                     GError *error,
1568 	                     gpointer user_data)
1569 	{
1570 		AddAndActivateInfo *info = (AddAndActivateInfo *) user_data;
1571 		NmCli *nmc = info->nmc;
1572 		NMDevice *device = info->device;
1573 		NMActiveConnectionState state;
1574 	
1575 	        if (error) {
1576 			g_string_printf (nmc->return_text, _("Error: Failed to add/activate new connection: (%d) %s"),
1577 			                 error->code, error->message);
1578 			nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
1579 			quit ();
1580 		} else {
1581 			state = nm_active_connection_get_state (active);
1582 	
1583 			if (state == NM_ACTIVE_CONNECTION_STATE_UNKNOWN) {
1584 				g_string_printf (nmc->return_text, _("Error: Failed to add/activate new connection: Unknown error"));
1585 				nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
1586 				quit ();
1587 			}
1588 	
1589 			if (nmc->nowait_flag || state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
1590 				/* User doesn't want to wait or already activated */
1591 				if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
1592 					if (nmc->print_output == NMC_PRINT_PRETTY)
1593 						nmc_terminal_erase_line ();
1594 					printf (_("Connection with UUID '%s' created and activated on device '%s'\n"),
1595 					        nm_active_connection_get_uuid (active), nm_device_get_iface (device));
1596 				}
1597 				quit ();
1598 			} else {
1599 				g_signal_connect (device, "notify::state", G_CALLBACK (monitor_device_state_cb), nmc);
1600 				g_timeout_add_seconds (nmc->timeout, timeout_cb, nmc);  /* Exit if timeout expires */
1601 	
1602 				if (nmc->print_output == NMC_PRINT_PRETTY)
1603 					progress_id = g_timeout_add (120, progress_cb, device);
1604 			}
1605 		}
1606 	
1607 		g_free (info);
1608 	}
1609 	
1610 	/*
1611 	 * Find a Wi-Fi device with 'iface' in 'devices' array. If 'iface' is NULL,
1612 	 * the first Wi-Fi device is returned. 'idx' parameter is updated to the point
1613 	 * where the function finished so that the function can be called repeatedly
1614 	 * to get next matching device.
1615 	 * Returns: found device or NULL
1616 	 */
1617 	static NMDevice *
1618 	find_wifi_device_by_iface (const GPtrArray *devices, const char *iface, int *idx)
1619 	{
1620 		NMDevice *device = NULL;
1621 		int i;
1622 	
1623 		for (i = *idx; devices && (i < devices->len); i++) {
1624 			NMDevice *candidate = g_ptr_array_index (devices, i);
1625 			const char *dev_iface = nm_device_get_iface (candidate);
1626 	
1627 			if (!NM_IS_DEVICE_WIFI (candidate))
1628 				continue;
1629 	
1630 			if (iface) {
1631 				/* If a iface was specified then use it. */
1632 				if (g_strcmp0 (dev_iface, iface) == 0) {
1633 					device = candidate;
1634 					break;
1635 				}
1636 			} else {
1637 				/* Else return the first Wi-Fi device. */
1638 				device = candidate;
1639 				break;
1640 			}
1641 		}
1642 	
1643 		*idx = i + 1;
1644 		return device;
1645 	}
1646 	
1647 	/*
1648 	 * Find AP on 'device' according to 'bssid' or 'ssid' parameter.
1649 	 * Returns: found AP or NULL
1650 	 */
1651 	static NMAccessPoint *
1652 	find_ap_on_device (NMDevice *device, GByteArray *bssid, const char *ssid)
1653 	{
1654 		const GPtrArray *aps;
1655 		NMAccessPoint *ap = NULL;
1656 		int i;
1657 	
1658 		g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), NULL);
1659 		g_return_val_if_fail ((bssid && !ssid) || (!bssid && ssid), NULL);
1660 	
1661 		aps = nm_device_wifi_get_access_points (NM_DEVICE_WIFI (device));
1662 		for (i = 0; aps && (i < aps->len); i++) {
1663 			NMAccessPoint *candidate_ap = g_ptr_array_index (aps, i);
1664 	
1665 			if (ssid) {
1666 				/* Parameter is SSID */
1667 				const GByteArray *candidate_ssid = nm_access_point_get_ssid (candidate_ap);
1668 				char *ssid_tmp = nm_utils_ssid_to_utf8 (candidate_ssid);
1669 	
1670 				/* Compare SSIDs */
1671 				if (strcmp (ssid, ssid_tmp) == 0) {
1672 					ap = candidate_ap;
1673 					g_free (ssid_tmp);
1674 					break;
1675 				}
1676 				g_free (ssid_tmp);
1677 			} else if (bssid) {
1678 				/* Parameter is BSSID */
1679 				const char *candidate_bssid = nm_access_point_get_bssid (candidate_ap);
1680 				char *bssid_up = nm_utils_hwaddr_ntoa (bssid->data, ARPHRD_ETHER);
1681 	
1682 				/* Compare BSSIDs */
1683 				if (strcmp (bssid_up, candidate_bssid) == 0) {
1684 					ap = candidate_ap;
1685 					g_free (bssid_up);
1686 					break;
1687 				}
1688 				g_free (bssid_up);
1689 			}
1690 		}
1691 	
1692 		return ap;
1693 	}
1694 	
1695 	static NMCResultCode
1696 	do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
1697 	{
1698 		NMDevice *device = NULL;
1699 		NMAccessPoint *ap = NULL;
1700 		NM80211ApFlags ap_flags;
1701 		NM80211ApSecurityFlags ap_wpa_flags;
1702 		NM80211ApSecurityFlags ap_rsn_flags;
1703 		NMConnection *connection = NULL;
1704 		NMSettingConnection *s_con;
1705 		NMSettingWireless *s_wifi;
1706 		NMSettingWirelessSecurity *s_wsec;
1707 		AddAndActivateInfo *info;
1708 		const char *param_user = NULL;
1709 		const char *ifname = NULL;
1710 		const char *bssid = NULL;
1711 		const char *password = NULL;
1712 		const char *con_name = NULL;
1713 		gboolean private = FALSE;
1714 		gboolean wep_passphrase = FALSE;
1715 		GByteArray *bssid1_arr = NULL;
1716 		GByteArray *bssid2_arr = NULL;
1717 		const GPtrArray *devices;
1718 		int devices_idx;
1719 		char *ssid_ask = NULL;
1720 		char *passwd_ask = NULL;
1721 	
1722 		/* Set default timeout waiting for operation completion. */
1723 		if (nmc->timeout == -1)
1724 			nmc->timeout = 90;
1725 	
1726 		/* Get the first compulsory argument (SSID or BSSID) */
1727 		if (argc > 0) {
1728 			param_user = *argv;
1729 			bssid1_arr = nm_utils_hwaddr_atoba (param_user, ARPHRD_ETHER);
1730 	
1731 			argc--;
1732 			argv++;
1733 		} else {
1734 			if (nmc->ask) {
1735 				ssid_ask = nmc_get_user_input (_("SSID or BSSID: "));
1736 				param_user = ssid_ask ? ssid_ask : "";
1737 				bssid1_arr = nm_utils_hwaddr_atoba (param_user, ARPHRD_ETHER);
1738 			}
1739 			if (!ssid_ask) {
1740 				g_string_printf (nmc->return_text, _("Error: SSID or BSSID are missing."));
1741 				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
1742 				goto error;
1743 			}
1744 		}
1745 	
1746 		/* Get the rest of the parameters */
1747 		while (argc > 0) {
1748 			if (strcmp (*argv, "ifname") == 0) {
1749 				if (next_arg (&argc, &argv) != 0) {
1750 					g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
1751 					nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
1752 					goto error;
1753 				}
1754 				ifname = *argv;
1755 			} else if (strcmp (*argv, "bssid") == 0) {
1756 				if (next_arg (&argc, &argv) != 0) {
1757 					g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
1758 					nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
1759 					goto error;
1760 				}
1761 				bssid = *argv;
1762 				bssid2_arr = nm_utils_hwaddr_atoba (bssid, ARPHRD_ETHER);
1763 				if (!bssid2_arr) {
1764 					g_string_printf (nmc->return_text, _("Error: bssid argument value '%s' is not a valid BSSID."),
1765 					                 bssid);
1766 					nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
1767 					goto error;
1768 				}
1769 			} else if (strcmp (*argv, "password") == 0) {
1770 				if (next_arg (&argc, &argv) != 0) {
1771 					g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
1772 					nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
1773 					goto error;
1774 				}
1775 				password = *argv;
1776 			} else if (strcmp (*argv, "wep-key-type") == 0) {
1777 				if (next_arg (&argc, &argv) != 0) {
1778 					g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
1779 					nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
1780 					goto error;
1781 				}
1782 				if (strcmp (*argv, "key") == 0)
1783 					wep_passphrase = FALSE;
1784 				else if (strcmp (*argv, "phrase") == 0)
1785 					wep_passphrase = TRUE;
1786 				else {
1787 					g_string_printf (nmc->return_text,
1788 					                 _("Error: wep-key-type argument value '%s' is invalid, use 'key' or 'phrase'."),
1789 					                 *argv);
1790 					nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
1791 					goto error;
1792 				}
1793 			} else if (strcmp (*argv, "name") == 0) {
1794 				if (next_arg (&argc, &argv) != 0) {
1795 					g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
1796 					nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
1797 					goto error;
1798 				}
1799 				con_name = *argv;
1800 			} else if (strcmp (*argv, "private") == 0) {
1801 				GError *err_tmp = NULL;
1802 				if (next_arg (&argc, &argv) != 0) {
1803 					g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
1804 					nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
1805 					goto error;
1806 				}
1807 				if (!nmc_string_to_bool (*argv, &private, &err_tmp)) {
1808 					g_string_printf (nmc->return_text, _("Error: %s: %s."), *(argv-1), err_tmp->message);
1809 					nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
1810 					g_clear_error (&err_tmp);
1811 					goto error;
1812 				}
1813 			} else {
1814 				fprintf (stderr, _("Unknown parameter: %s\n"), *argv);
1815 			}
1816 	
1817 			argc--;
1818 			argv++;
1819 		}
1820 	
1821 		/* Verify SSID/BSSID parameters */
1822 		if (bssid1_arr && bssid2_arr && memcmp (bssid1_arr->data, bssid2_arr->data, ETH_ALEN)) {
1823 			g_string_printf (nmc->return_text, _("Error: BSSID to connect to (%s) differs from bssid argument (%s)."),
1824 			                 param_user, bssid);
1825 			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
1826 			goto error;
1827 		}
1828 		if (!bssid1_arr && strlen (param_user) > 32) {
1829 			g_string_printf (nmc->return_text, _("Error: Parameter '%s' is neither SSID nor BSSID."), param_user);
1830 			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
1831 			goto error;
1832 		}
1833 	
1834 		nmc->get_client (nmc);
1835 	
1836 		if (!nm_client_get_manager_running (nmc->client)) {
1837 			g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
1838 			nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
1839 			goto error;
1840 		}
1841 	
1842 		if (!nmc_versions_match (nmc))
1843 			goto error;
1844 	
1845 		devices = nm_client_get_devices (nmc->client);
1846 	
1847 		/* Find a device to activate the connection on */
1848 		devices_idx = 0;
1849 		device = find_wifi_device_by_iface (devices, ifname, &devices_idx);
1850 	
1851 		if (!device) {
1852 			if (ifname)
1853 				g_string_printf (nmc->return_text, _("Error: Device '%s' is not a Wi-Fi device."), ifname);
1854 			else
1855 				g_string_printf (nmc->return_text, _("Error: No Wi-Fi device found."));
1856 			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
1857 			goto error;
1858 		}
1859 	
1860 		/* Find an AP to connect to */
1861 		ap = find_ap_on_device (device, bssid1_arr, bssid1_arr ? NULL : param_user);
1862 		if (!ap && !ifname) {
1863 			/* AP not found. ifname was not specified, so try finding the AP on another device. */
1864 			while ((device = find_wifi_device_by_iface (devices, NULL, &devices_idx)) != NULL) {
1865 				ap = find_ap_on_device (device, bssid1_arr, bssid1_arr ? NULL : param_user);
1866 				if (ap)
1867 					break;
1868 			}
1869 		}
1870 	
1871 		if (!ap) {
1872 			if (!bssid1_arr)
1873 				g_string_printf (nmc->return_text, _("Error: No network with SSID '%s' found."), param_user);
1874 			else
1875 				g_string_printf (nmc->return_text, _("Error: No access point with BSSID '%s' found."), param_user);
1876 			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
1877 			goto error;
1878 		}
1879 	
1880 		/* If there are some connection data from user, create a connection and
1881 		 * fill them into proper settings. */
1882 		if (con_name || private || bssid2_arr || password)
1883 			connection = nm_connection_new ();
1884 	
1885 		if (con_name || private) {
1886 			s_con =  (NMSettingConnection *) nm_setting_connection_new ();
1887 			nm_connection_add_setting (connection, NM_SETTING (s_con));
1888 	
1889 			/* Set user provided connection name */
1890 			if (con_name)
1891 				g_object_set (s_con, NM_SETTING_CONNECTION_ID, con_name, NULL);
1892 	
1893 			/* Connection will only be visible to this user when '--private' is specified */
1894 			if (private)
1895 				nm_setting_connection_add_permission (s_con, "user", g_get_user_name (), NULL);
1896 		}
1897 		if (bssid2_arr) {
1898 			s_wifi = (NMSettingWireless *) nm_setting_wireless_new ();
1899 			nm_connection_add_setting (connection, NM_SETTING (s_wifi));
1900 	
1901 			/* 'bssid' parameter is used to restrict the conenction only to the BSSID */
1902 			g_object_set (s_wifi, NM_SETTING_WIRELESS_BSSID, bssid2_arr, NULL);
1903 		}
1904 	
1905 		/* handle password */
1906 		ap_flags = nm_access_point_get_flags (ap);
1907 		ap_wpa_flags = nm_access_point_get_wpa_flags (ap);
1908 		ap_rsn_flags = nm_access_point_get_rsn_flags (ap);
1909 	
1910 		/* Set password for WEP or WPA-PSK. */
1911 		if (ap_flags & NM_802_11_AP_FLAGS_PRIVACY) {
1912 			/* Ask for missing password when one is expected and '--ask' is used */
1913 			if (!password && nmc->ask)
1914 				password = passwd_ask = nmc_get_user_input (_("Password: "));
1915 	
1916 			if (password) {
1917 				if (!connection)
1918 					connection = nm_connection_new ();
1919 				s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
1920 				nm_connection_add_setting (connection, NM_SETTING (s_wsec));
1921 	
1922 				if (ap_wpa_flags == NM_802_11_AP_SEC_NONE && ap_rsn_flags == NM_802_11_AP_SEC_NONE) {
1923 					/* WEP */
1924 					nm_setting_wireless_security_set_wep_key (s_wsec, 0, password);
1925 					g_object_set (G_OBJECT (s_wsec),
1926 					              NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE,
1927 					              wep_passphrase ? NM_WEP_KEY_TYPE_PASSPHRASE: NM_WEP_KEY_TYPE_KEY,
1928 					              NULL);
1929 				} else if (   !(ap_wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)
1930 					   && !(ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) {
1931 					/* WPA PSK */
1932 					g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_PSK, password, NULL);
1933 				}
1934 			}
1935 		}
1936 		// FIXME: WPA-Enterprise is not supported yet.
1937 		// We are not able to determine and fill all the parameters for
1938 		// 802.1X authentication automatically without user providing
1939 		// the data. Adding nmcli options for the 8021x setting would
1940 		// clutter the command. However, that could be solved later by
1941 		// implementing add/edit connections support for nmcli.
1942 	
1943 		/* nowait_flag indicates user input. should_wait says whether quit in start().
1944 		 * We have to delay exit after add_and_activate_cb() is called, even if
1945 		 * the user doesn't want to wait, in order to give NM time to check our
1946 		 * permissions. */
1947 		nmc->nowait_flag = (nmc->timeout == 0);
1948 		nmc->should_wait = TRUE;
1949 	
1950 		info = g_malloc0 (sizeof (AddAndActivateInfo));
1951 		info->nmc = nmc;
1952 		info->device = device;
1953 	
1954 		nm_client_add_and_activate_connection (nmc->client,
1955 		                                       connection,
1956 		                                       device,
1957 		                                       nm_object_get_path (NM_OBJECT (ap)),
1958 		                                       add_and_activate_cb,
1959 		                                       info);
1960 	
1961 	error:
1962 		if (bssid1_arr)
1963 			g_byte_array_free (bssid1_arr, TRUE);
1964 		if (bssid2_arr)
1965 			g_byte_array_free (bssid2_arr, TRUE);
1966 		g_free (ssid_ask);
1967 		g_free (passwd_ask);
1968 	
1969 		return nmc->return_value;
1970 	}
1971 	
1972 	static void
1973 	request_rescan_cb (NMDeviceWifi *device, GError *error, gpointer user_data)
1974 	{
1975 		NmCli *nmc = (NmCli *) user_data;
1976 	
1977 		if (error) {
1978 			g_string_printf (nmc->return_text, _("Error: %s."),
1979 			                 error->message ? error->message : _("unknown"));
1980 			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
1981 		}
1982 		quit ();
1983 	}
1984 	
1985 	static NMCResultCode
1986 	do_device_wifi_rescan (NmCli *nmc, int argc, char **argv)
1987 	{
1988 		NMDevice *device;
1989 		const char *ifname = NULL;
1990 		const GPtrArray *devices;
1991 		int devices_idx;
1992 	
1993 		nmc->should_wait = TRUE;
1994 	
1995 		/* Get the parameters */
1996 		if (argc > 0) {
1997 			if (strcmp (*argv, "ifname") == 0) {
1998 				if (next_arg (&argc, &argv) != 0) {
1999 					g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
2000 					nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
2001 					goto error;
2002 				}
2003 			}
2004 			ifname = *argv;
2005 		}
2006 	
2007 		/* Find Wi-Fi device to scan on. When no ifname is provided, the first Wi-Fi is used. */
2008 		nmc->get_client (nmc);
2009 		devices = nm_client_get_devices (nmc->client);
2010 		devices_idx = 0;
2011 		device = find_wifi_device_by_iface (devices, ifname, &devices_idx);
2012 	
2013 		if (!device) {
2014 			if (ifname)
2015 				g_string_printf (nmc->return_text, _("Error: Device '%s' is not a Wi-Fi device."), ifname);
2016 			else
2017 				g_string_printf (nmc->return_text, _("Error: No Wi-Fi device found."));
2018 			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
2019 			goto error;
2020 		}
2021 	
2022 		nm_device_wifi_request_scan_simple (NM_DEVICE_WIFI (device), request_rescan_cb, nmc);
2023 	
2024 		return nmc->return_value;
2025 	error:
2026 		nmc->should_wait = FALSE;
2027 		return nmc->return_value;
2028 	}
2029 	
2030 	static NMCResultCode
2031 	do_device_wifi (NmCli *nmc, int argc, char **argv)
2032 	{
2033 		if (argc == 0)
2034 			nmc->return_value = do_device_wifi_list (nmc, argc-1, argv+1);
2035 		else if (argc > 0) {
2036 			if (matches (*argv, "list") == 0) {
2037 				nmc->return_value = do_device_wifi_list (nmc, argc-1, argv+1);
2038 			} else if (matches (*argv, "connect") == 0) {
2039 				nmc->return_value = do_device_wifi_connect_network (nmc, argc-1, argv+1);
2040 			} else if (matches (*argv, "rescan") == 0) {
2041 				nmc->return_value = do_device_wifi_rescan (nmc, argc-1, argv+1);
2042 			} else {
2043 				g_string_printf (nmc->return_text, _("Error: 'device wifi' command '%s' is not valid."), *argv);
2044 				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
2045 			}
2046 		}
2047 	
2048 		return nmc->return_value;
2049 	}
2050 	
2051 	#if WITH_WIMAX
2052 	static void
2053 	show_nsp_info (NMDevice *device, NmCli *nmc)
2054 	{
2055 		const GPtrArray *nsps;
2056 		int i, idx = 1;
2057 		NmcOutputField *arr;
2058 	
2059 		/* Add headers (field names) */
2060 		arr = nmc_dup_fields_array (nmc_fields_dev_wimax_list, sizeof (nmc_fields_dev_wimax_list),
2061 		                            NMC_OF_FLAG_MAIN_HEADER_ADD | NMC_OF_FLAG_FIELD_NAMES);
2062 		g_ptr_array_add (nmc->output_data, arr);
2063 	
2064 		nsps = nm_device_wimax_get_nsps (NM_DEVICE_WIMAX (device));
2065 		for (i = 0; nsps && i < nsps->len; i++) {
2066 			NMWimaxNsp *nsp = g_ptr_array_index (nsps, i);
2067 	
2068 			fill_output_wimax_nsp (nsp, nmc, device, idx++, 0);
2069 		}
2070 		print_data (nmc);  /* Print all data */
2071 		nmc_empty_output_fields (nmc);
2072 	}
2073 	
2074 	static NMCResultCode
2075 	do_device_wimax_list (NmCli *nmc, int argc, char **argv)
2076 	{
2077 		GError *error = NULL;
2078 		NMDevice *device = NULL;
2079 		NMWimaxNsp *nsp = NULL;
2080 		const char *ifname = NULL;
2081 		const char *nsp_user = NULL;
2082 		const GPtrArray *devices;
2083 		const GPtrArray *nsps;
2084 		int i, j;
2085 		char *fields_str;
2086 		char *fields_all =    NMC_FIELDS_DEV_WIMAX_LIST_ALL;
2087 		char *fields_common = NMC_FIELDS_DEV_WIMAX_LIST_COMMON;
2088 		NmcOutputField *tmpl, *arr;
2089 		size_t tmpl_len;
2090 		const char *base_hdr = _("WiMAX NSP list");
2091 	
2092 		while (argc > 0) {
2093 			if (strcmp (*argv, "ifname") == 0) {
2094 				if (next_arg (&argc, &argv) != 0) {
2095 					g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
2096 					nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
2097 					goto error;
2098 				}
2099 				ifname = *argv;
2100 			} else if (strcmp (*argv, "nsp") == 0) {
2101 				if (next_arg (&argc, &argv) != 0) {
2102 					g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
2103 					nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
2104 					goto error;
2105 				}
2106 				nsp_user = *argv;
2107 			} else {
2108 				fprintf (stderr, _("Unknown parameter: %s\n"), *argv);
2109 			}
2110 	
2111 			argc--;
2112 			argv++;
2113 		}
2114 	
2115 		if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0)
2116 			fields_str = fields_common;
2117 		else if (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0)
2118 			fields_str = fields_all;
2119 		else
2120 			fields_str = nmc->required_fields;
2121 	
2122 		tmpl = nmc_fields_dev_wimax_list;
2123 		tmpl_len = sizeof (nmc_fields_dev_wimax_list);
2124 		nmc->print_fields.indices = parse_output_fields (fields_str, tmpl, &error);
2125 	
2126 		if (error) {
2127 			if (error->code == 0)
2128 				g_string_printf (nmc->return_text, _("Error: 'device wimax': %s"), error->message);
2129 			else
2130 				g_string_printf (nmc->return_text, _("Error: 'device wimax': %s; allowed fields: %s"),
2131 				                 error->message, NMC_FIELDS_DEV_WIMAX_LIST_ALL);
2132 			g_error_free (error);
2133 			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
2134 			goto error;
2135 		}
2136 	
2137 		nmc->get_client (nmc);
2138 	
2139 		if (!nm_client_get_manager_running (nmc->client)) {
2140 			g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
2141 			nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
2142 			goto error;
2143 		}
2144 	
2145 		if (!nmc_versions_match (nmc))
2146 			goto error;
2147 	
2148 		devices = nm_client_get_devices (nmc->client);
2149 		if (ifname) {
2150 			/* Device specified - list only NSPs of this interface */
2151 			for (i = 0; devices && (i < devices->len); i++) {
2152 				NMDevice *candidate = g_ptr_array_index (devices, i);
2153 				const char *dev_iface = nm_device_get_iface (candidate);
2154 	
2155 				if (!g_strcmp0 (dev_iface, ifname)) {
2156 					device = candidate;
2157 					break;
2158 				}
2159 			}
2160 	
2161 			if (!device) {
2162 				g_string_printf (nmc->return_text, _("Error: Device '%s' not found."), ifname);
2163 				nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
2164 				goto error;
2165 			}
2166 	
2167 			/* Main header name */
2168 			nmc->print_fields.header_name = (char *) construct_header_name (base_hdr, ifname);
2169 	
2170 			if (NM_IS_DEVICE_WIMAX (device)) {
2171 				if (nsp_user) {
2172 					/* Specific NSP requested - list only that */
2173 					nsps = nm_device_wimax_get_nsps (NM_DEVICE_WIMAX (device));
2174 					for (j = 0, nsp = NULL; nsps && (j < nsps->len); j++) {
2175 						NMWimaxNsp *candidate_nsp = g_ptr_array_index (nsps, j);
2176 						const char *candidate_name = nm_wimax_nsp_get_name (candidate_nsp);
2177 						char *nsp_up;
2178 	
2179 						nsp_up = g_ascii_strup (nsp_user, -1);
2180 						if (!strcmp (nsp_up, candidate_name))
2181 							nsp = candidate_nsp;
2182 						g_free (nsp_up);
2183 					}
2184 					if (!nsp) {
2185 						g_string_printf (nmc->return_text, _("Error: NSP with name '%s' not found."), nsp_user);
2186 						nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
2187 						goto error;
2188 					}
2189 					/* Add headers (field names) */
2190 					arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_MAIN_HEADER_ADD | NMC_OF_FLAG_FIELD_NAMES);
2191 					g_ptr_array_add (nmc->output_data, arr);
2192 					fill_output_wimax_nsp (nsp, nmc, device, 1, 0);
2193 					print_data (nmc);  /* Print all data */
2194 				} else {
2195 					show_nsp_info (device, nmc);
2196 				}
2197 			} else {
2198 				g_string_printf (nmc->return_text, _("Error: Device '%s' is not a WiMAX device."), ifname);
2199 				nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
2200 				goto error;
2201 			}
2202 		} else {
2203 			/* List NSPs for all devices */
2204 			if (nsp_user) {
2205 				/* Specific NSP requested - list only that */
2206 				for (i = 0; devices && (i < devices->len); i++) {
2207 					NMDevice *dev = g_ptr_array_index (devices, i);
2208 					int idx = 1;
2209 	
2210 					if (!NM_IS_DEVICE_WIMAX (dev))
2211 						continue;
2212 	
2213 					/* Main header name */
2214 					nmc->print_fields.header_name = (char *) construct_header_name (base_hdr, nm_device_get_iface (dev));
2215 	
2216 					arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_MAIN_HEADER_ADD | NMC_OF_FLAG_FIELD_NAMES);
2217 					g_ptr_array_add (nmc->output_data, arr);
2218 	
2219 					nsps = nm_device_wimax_get_nsps (NM_DEVICE_WIMAX (dev));
2220 					for (j = 0, nsp = NULL; nsps && (j < nsps->len); j++) {
2221 						NMWimaxNsp *candidate_nsp = g_ptr_array_index (nsps, j);
2222 						const char *candidate_name = nm_wimax_nsp_get_name (candidate_nsp);
2223 						char *nsp_up;
2224 	
2225 						nsp_up = g_ascii_strup (nsp_user, -1);
2226 						if (!strcmp (nsp_up, candidate_name)) {
2227 							nsp = candidate_nsp;
2228 							fill_output_wimax_nsp (nsp, nmc, dev, idx, 0);
2229 						}
2230 						g_free (nsp_up);
2231 					}
2232 					print_data (nmc);  /* Print all data */
2233 					nmc_empty_output_fields (nmc);
2234 				}
2235 				if (!nsp) {
2236 					g_string_printf (nmc->return_text, _("Error: Access point with nsp '%s' not found."), nsp_user);
2237 					nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
2238 					goto error;
2239 				}
2240 			} else {
2241 				for (i = 0; devices && (i < devices->len); i++) {
2242 					NMDevice *dev = g_ptr_array_index (devices, i);
2243 	
2244 					/* Main header name */
2245 					nmc->print_fields.header_name = (char *) construct_header_name (base_hdr,
2246 					                                                                nm_device_get_iface (dev));
2247 	
2248 					if (NM_IS_DEVICE_WIMAX (dev))
2249 						show_nsp_info (dev, nmc);
2250 				}
2251 			}
2252 		}
2253 	
2254 	error:
2255 		return nmc->return_value;
2256 	}
2257 	
2258 	static NMCResultCode
2259 	do_device_wimax (NmCli *nmc, int argc, char **argv)
2260 	{
2261 		if (argc == 0)
2262 			nmc->return_value = do_device_wimax_list (nmc, argc-1, argv+1);
2263 		else if (argc > 0) {
2264 			if (matches (*argv, "list") == 0) {
2265 				nmc->return_value = do_device_wimax_list (nmc, argc-1, argv+1);
2266 			}
2267 			else {
2268 				g_string_printf (nmc->return_text, _("Error: 'device wimax' command '%s' is not valid."), *argv);
2269 				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
2270 			}
2271 		}
2272 	
2273 		return nmc->return_value;
2274 	}
2275 	#endif
2276 	
2277 	NMCResultCode
2278 	do_devices (NmCli *nmc, int argc, char **argv)
2279 	{
2280 		GError *error = NULL;
2281 	
2282 		if (argc == 0) {
2283 			if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error))
2284 				goto opt_error;
2285 			nmc->return_value = do_devices_status (nmc, 0, NULL);
2286 		}
2287 	
2288 		if (argc > 0) {
2289 			if (matches (*argv, "status") == 0) {
2290 				if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error))
2291 					goto opt_error;
2292 				nmc->return_value = do_devices_status (nmc, argc-1, argv+1);
2293 			}
2294 			else if (matches (*argv, "show") == 0) {
2295 				if (!nmc->mode_specified)
2296 					nmc->multiline_output = TRUE;  /* multiline mode is default for 'device show' */
2297 				nmc->return_value = do_devices_show (nmc, argc-1, argv+1);
2298 			}
2299 			else if (matches (*argv, "disconnect") == 0) {
2300 				nmc->return_value = do_device_disconnect (nmc, argc-1, argv+1);
2301 			}
2302 			else if (matches (*argv, "wifi") == 0) {
2303 				if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error))
2304 					goto opt_error;
2305 				nmc->return_value = do_device_wifi (nmc, argc-1, argv+1);
2306 			}
2307 	#if WITH_WIMAX
2308 			else if (matches (*argv, "wimax") == 0) {
2309 				if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error))
2310 					goto opt_error;
2311 				nmc->return_value = do_device_wimax (nmc, argc-1, argv+1);
2312 			}
2313 	#endif
2314 			else if (nmc_arg_is_help (*argv)) {
2315 				usage ();
2316 			}
2317 			else {
2318 				usage ();
2319 				g_string_printf (nmc->return_text, _("Error: 'dev' command '%s' is not valid."), *argv);
2320 				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
2321 			}
2322 		}
2323 	
2324 		return nmc->return_value;
2325 	
2326 	opt_error:
2327 		g_string_printf (nmc->return_text, _("Error: %s."), error->message);
2328 		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
2329 		g_error_free (error);
2330 		return nmc->return_value;
2331 	}
2332