summaryrefslogtreecommitdiff
authorJirka Klimes <jklimes@redhat.com>2010-02-25 17:52:30 (GMT)
committer Dan Williams <dcbw@redhat.com>2010-02-25 17:52:30 (GMT)
commitc2ec07f17d69a590b45797de5c8a0f26a4c45eaa (patch) (side-by-side diff)
tree8108309c3a98d7d1d6fe3aeca7a864d07ad5343c
parentbace73c5dc3ee758b1d33dcc6c53510d8f5e3182 (diff)
downloadNetworkManager-c2ec07f17d69a590b45797de5c8a0f26a4c45eaa.zip
NetworkManager-c2ec07f17d69a590b45797de5c8a0f26a4c45eaa.tar.gz
cli: add initial pieces of nmcli
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--.gitignore1
-rw-r--r--Makefile.am1
-rw-r--r--cli/Makefile.am2
-rw-r--r--cli/src/Makefile.am36
-rw-r--r--cli/src/connections.c1261
-rw-r--r--cli/src/connections.h27
-rw-r--r--cli/src/devices.c950
-rw-r--r--cli/src/devices.h27
-rw-r--r--cli/src/network-manager.c186
-rw-r--r--cli/src/network-manager.h27
-rw-r--r--cli/src/nmcli.c283
-rw-r--r--cli/src/nmcli.h77
-rw-r--r--cli/src/utils.c126
-rw-r--r--cli/src/utils.h28
-rw-r--r--configure.ac2
-rw-r--r--po/POTFILES.in5
16 files changed, 3039 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index 6a9d0a6..b4652f6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -72,3 +72,4 @@ m4/lt*.m4
policy/org.freedesktop.network-manager-settings.system.policy
+cli/src/nmcli
diff --git a/Makefile.am b/Makefile.am
index ca819b4..7e34571 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -7,6 +7,7 @@ SUBDIRS = \
introspection \
callouts \
system-settings \
+ cli \
tools \
policy \
initscript \
diff --git a/cli/Makefile.am b/cli/Makefile.am
new file mode 100644
index 0000000..f268924
--- a/dev/null
+++ b/cli/Makefile.am
@@ -0,0 +1,2 @@
+SUBDIRS = src
+
diff --git a/cli/src/Makefile.am b/cli/src/Makefile.am
new file mode 100644
index 0000000..2a1bd12
--- a/dev/null
+++ b/cli/src/Makefile.am
@@ -0,0 +1,36 @@
+bin_PROGRAMS = \
+ nmcli
+
+INCLUDES = \
+ -I${top_srcdir} \
+ -I${top_srcdir}/include \
+ -I${top_builddir}/marshallers \
+ -I${top_srcdir}/libnm-util \
+ -I${top_srcdir}/libnm-glib
+
+nmcli_SOURCES = \
+ connections.c \
+ connections.h \
+ devices.c \
+ devices.h \
+ network-manager.c \
+ network-manager.h \
+ nmcli.c \
+ nmcli.h \
+ utils.c \
+ utils.h
+
+nmcli_CPPFLAGS = \
+ $(DBUS_CFLAGS) \
+ $(GLIB_CFLAGS) \
+ -DNMCLI_LOCALEDIR=\"$(datadir)/locale\" \
+ -DG_DISABLE_DEPRECATED
+
+nmcli_LDADD = \
+ $(DBUS_LIBS) \
+ $(GLIB_LIBS) \
+ $(top_builddir)/marshallers/libmarshallers.la \
+ $(top_builddir)/libnm-util/libnm-util.la \
+ $(top_builddir)/libnm-glib/libnm-glib.la
+
+
diff --git a/cli/src/connections.c b/cli/src/connections.c
new file mode 100644
index 0000000..ae09fe0
--- a/dev/null
+++ b/cli/src/connections.c
@@ -0,0 +1,1261 @@
+/* nmcli - command-line tool to control NetworkManager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2010 Red Hat, Inc.
+ */
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <signal.h>
+#include <netinet/ether.h>
+
+#include <nm-client.h>
+#include <nm-setting-connection.h>
+#include <nm-setting-wired.h>
+#include <nm-setting-pppoe.h>
+#include <nm-setting-wireless.h>
+#include <nm-setting-gsm.h>
+#include <nm-setting-cdma.h>
+#include <nm-setting-bluetooth.h>
+#include <nm-setting-olpc-mesh.h>
+#include <nm-device-ethernet.h>
+#include <nm-device-wifi.h>
+#include <nm-gsm-device.h>
+#include <nm-cdma-device.h>
+#include <nm-device-bt.h>
+//#include <nm-device-olpc-mesh.h>
+#include <nm-remote-settings.h>
+#include <nm-remote-settings-system.h>
+#include <nm-settings-interface.h>
+#include <nm-settings-connection-interface.h>
+#include <nm-vpn-connection.h>
+
+#include "utils.h"
+#include "connections.h"
+
+
+typedef struct {
+ NmCli *nmc;
+ int argc;
+ char **argv;
+} ArgsInfo;
+
+extern GMainLoop *loop; /* glib main loop variable */
+
+static ArgsInfo args_info;
+
+/* static function prototypes */
+static void usage (void);
+static void quit (void);
+static void show_connection (NMConnection *data, gpointer user_data);
+static NMConnection *find_connection (GSList *list, const char *filter_type, const char *filter_val);
+static gboolean find_device_for_connection (NmCli *nmc, NMConnection *connection, const char *iface, const char *ap,
+ NMDevice **device, const char **spec_object, GError **error);
+static const char *active_connection_state_to_string (NMActiveConnectionState state);
+static void active_connection_state_cb (NMActiveConnection *active, GParamSpec *pspec, gpointer user_data);
+static void activate_connection_cb (gpointer user_data, const char *path, GError *error);
+static void get_connections_cb (NMSettingsInterface *settings, gpointer user_data);
+static NMCResultCode do_connections_list (NmCli *nmc, int argc, char **argv);
+static NMCResultCode do_connections_status (NmCli *nmc, int argc, char **argv);
+static NMCResultCode do_connection_up (NmCli *nmc, int argc, char **argv);
+static NMCResultCode do_connection_down (NmCli *nmc, int argc, char **argv);
+
+static void
+usage (void)
+{
+ fprintf (stderr,
+ _("Usage: nmcli con { COMMAND | help }\n"
+ " COMMAND := { list | status | up | down }\n\n"
+ " list [id <id> | uuid <id> | system | user]\n"
+ " status\n"
+ " up id <id> | uuid <id> [iface <iface>] [ap <hwaddr>] [--nowait] [--timeout <timeout>]\n"
+ " down id <id> | uuid <id>\n"));
+}
+
+/* quit main loop */
+static void
+quit (void)
+{
+ g_main_loop_quit (loop); /* quit main loop */
+}
+
+static void
+show_connection (NMConnection *data, gpointer user_data)
+{
+ NMConnection *connection = (NMConnection *) data;
+ NMSettingConnection *s_con;
+ const char *id;
+ const char *uuid;
+ const char *con_type;
+
+ s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
+ if (s_con) {
+ id = nm_setting_connection_get_id (s_con);
+ uuid = nm_setting_connection_get_uuid (s_con);
+ con_type = nm_setting_connection_get_connection_type (s_con);
+ print_table_line (0, con_type, 17, uuid, 38, id, 0, NULL);
+ }
+}
+
+static NMConnection *
+find_connection (GSList *list, const char *filter_type, const char *filter_val)
+{
+ NMSettingConnection *s_con;
+ NMConnection *connection;
+ GSList *iterator;
+ const char *id;
+ const char *uuid;
+
+ iterator = list;
+ while (iterator) {
+ connection = NM_CONNECTION (iterator->data);
+ s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
+ if (s_con) {
+ id = nm_setting_connection_get_id (s_con);
+ uuid = nm_setting_connection_get_uuid (s_con);
+ if (filter_type) {
+ if ((strcmp (filter_type, "id") == 0 && strcmp (filter_val, id) == 0) ||
+ (strcmp (filter_type, "uuid") == 0 && strcmp (filter_val, uuid) == 0)) {
+ return connection;
+ }
+ }
+ }
+ iterator = g_slist_next (iterator);
+ }
+
+ return NULL;
+}
+
+static NMCResultCode
+do_connections_list (NmCli *nmc, int argc, char **argv)
+{
+ gboolean valid_param_specified = FALSE;
+
+ nmc->should_wait = FALSE;
+
+ if (argc == 0) {
+ valid_param_specified = TRUE;
+ if (nmc->print_output == NMC_PRINT_PRETTY)
+ print_table_header (_("Connections"), _("Type"), 17, _("UUID"), 38, _("Name"), 20, NULL);
+ else if (nmc->print_output == NMC_PRINT_NORMAL)
+ print_table_line (0, _("Type"), 17, _("UUID"), 38, _("Name"), 0, NULL);
+
+ if (nmc->print_output > NMC_PRINT_TERSE)
+ printf (_("System connections:\n"));
+ g_slist_foreach (nmc->system_connections, (GFunc) show_connection, NULL);
+
+ if (nmc->print_output > NMC_PRINT_TERSE)
+ printf (_("User connections:\n"));
+ g_slist_foreach (nmc->user_connections, (GFunc) show_connection, NULL);
+ }
+ else {
+ while (argc > 0) {
+ if (strcmp (*argv, "id") == 0 || strcmp (*argv, "uuid") == 0) {
+ const char *selector = *argv;
+ NMConnection *con1;
+ NMConnection *con2;
+
+ if (next_arg (&argc, &argv) != 0) {
+ g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *argv);
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ goto error;
+ }
+ valid_param_specified = TRUE;
+
+ con1 = find_connection (nmc->system_connections, selector, *argv);
+ con2 = find_connection (nmc->user_connections, selector, *argv);
+ if (con1) nm_connection_dump (con1);
+ if (con2) nm_connection_dump (con2);
+ if (!con1 && !con2) {
+ g_string_printf (nmc->return_text, _("Error: %s - no such connection."), *argv);
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ }
+ }
+ else if (strcmp (*argv, "system") == 0) {
+ valid_param_specified = TRUE;
+ if (nmc->print_output == NMC_PRINT_PRETTY)
+ print_table_header (_("System-wide connections"), _("Type"), 17, _("UUID"), 38, _("Name"), 20, NULL);
+ else if (nmc->print_output == NMC_PRINT_NORMAL)
+ print_table_line (0, _("Type"), 17, _("UUID"), 38, _("Name"), 0, NULL);
+
+ g_slist_foreach (nmc->system_connections, (GFunc) show_connection, NULL);
+ }
+ else if (strcmp (*argv, "user") == 0) {
+ valid_param_specified = TRUE;
+ if (nmc->print_output == NMC_PRINT_PRETTY)
+ print_table_header (_("User connections"), _("Type"), 17, _("UUID"), 38, _("Name"), 20, NULL);
+ else if (nmc->print_output == NMC_PRINT_NORMAL)
+ print_table_line (0, _("Type"), 17, _("UUID"), 38, _("Name"), 0, NULL);
+
+ g_slist_foreach (nmc->user_connections, (GFunc) show_connection, NULL);
+ }
+ else {
+ fprintf (stderr, _("Unknown parameter: %s\n"), *argv);
+ }
+
+ argc--;
+ argv++;
+ }
+ }
+
+ if (!valid_param_specified) {
+ g_string_printf (nmc->return_text, _("Error: no valid parameter specified."));
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ }
+
+error:
+ return nmc->return_value;
+}
+
+static void
+show_active_connection (gpointer data, gpointer user_data)
+{
+ NMActiveConnection *active = NM_ACTIVE_CONNECTION (data);
+ GSList *con_list = (GSList *) user_data;
+ GSList *iter;
+ const char *active_path;
+ NMConnectionScope active_service_scope;
+ NMSettingConnection *s_con;
+ const GPtrArray *devices;
+ GString *dev_str;
+ int i;
+
+ dev_str = g_string_new (NULL);
+
+ active_path = nm_active_connection_get_connection (active);
+ active_service_scope = nm_active_connection_get_scope (active);
+
+ /* Get devices of the active connection */
+ devices = nm_active_connection_get_devices (active);
+ for (i = 0; devices && (i < devices->len); i++) {
+ NMDevice *device = g_ptr_array_index (devices, i);
+
+ g_string_append (dev_str, nm_device_get_iface (device));
+ g_string_append_c (dev_str, ',');
+ }
+ if (dev_str->len > 0)
+ g_string_truncate (dev_str, dev_str->len - 1); /* Cut off last ',' */
+
+ for (iter = con_list; iter; iter = g_slist_next (iter)) {
+ NMConnection *connection = (NMConnection *) iter->data;
+ const char *con_path = nm_connection_get_path (connection);
+ NMConnectionScope con_scope = nm_connection_get_scope (connection);
+
+ if (!strcmp (active_path, con_path) && active_service_scope == con_scope) {
+ /* this connection is active */
+ s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
+ g_assert (s_con != NULL);
+ // FIXME: Fix the output
+ print_table_line (0, nm_active_connection_get_default (active) ? _("yes") : _("no"), 8,
+ nm_active_connection_get_service_name (active), 45,
+// nm_active_connection_get_specific_object (active), 0,
+// nm_active_connection_get_connection (active), 0,
+ dev_str->str, 10,
+ nm_setting_connection_get_uuid (s_con), 38,
+ nm_setting_connection_get_id (s_con), 0, NULL);
+
+ }
+ }
+
+ g_string_free (dev_str, TRUE);
+}
+
+static NMCResultCode
+do_connections_status (NmCli *nmc, int argc, char **argv)
+{
+ const GPtrArray *active_cons;
+
+ nmc->should_wait = FALSE;
+
+ /* create NMClient */
+ if (!nmc->get_client (nmc))
+ return nmc->return_value;
+
+ active_cons = nm_client_get_active_connections (nmc->client);
+
+ // FIXME: Fix the output
+ if (nmc->print_output == NMC_PRINT_PRETTY)
+ print_table_header (_("Active connections"), _("Default"), 8, _("Service"), 45, _("Devices"), 10, _("UUID"), 38, _("Name"), 20, NULL);
+ else if (nmc->print_output == NMC_PRINT_NORMAL)
+ print_table_line (0, _("Default"), 8, _("Service"), 45, _("Devices"), 10, _("UUID"), 38, _("Name"), 0, NULL);
+
+ if (active_cons && active_cons->len) {
+ g_ptr_array_foreach ((GPtrArray *) active_cons, show_active_connection, (gpointer) nmc->system_connections);
+ g_ptr_array_foreach ((GPtrArray *) active_cons, show_active_connection, (gpointer) nmc->user_connections);
+ }
+
+ return NMC_RESULT_SUCCESS;
+}
+
+/* --------------------
+ * These function should be moved to libnm-glib in the end.
+ */
+static gboolean
+check_ethernet_compatible (NMDeviceEthernet *device, NMConnection *connection, GError **error)
+{
+ NMSettingConnection *s_con;
+ NMSettingWired *s_wired;
+ const char *connection_type;
+ gboolean is_pppoe = FALSE;
+
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+ g_assert (s_con);
+
+ connection_type = nm_setting_connection_get_connection_type (s_con);
+ if ( strcmp (connection_type, NM_SETTING_WIRED_SETTING_NAME)
+ && strcmp (connection_type, NM_SETTING_PPPOE_SETTING_NAME)) {
+ g_set_error (error, 0, 0,
+ "The connection was not a wired or PPPoE connection.");
+ return FALSE;
+ }
+
+ if (!strcmp (connection_type, NM_SETTING_PPPOE_SETTING_NAME))
+ is_pppoe = TRUE;
+
+ s_wired = (NMSettingWired *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED);
+ /* Wired setting is optional for PPPoE */
+ if (!is_pppoe && !s_wired) {
+ g_set_error (error, 0, 0,
+ "The connection was not a valid wired connection.");
+ return FALSE;
+ }
+
+ if (s_wired) {
+ const GByteArray *mac;
+ const char *device_mac_str;
+ struct ether_addr *device_mac;
+
+ device_mac_str = nm_device_ethernet_get_hw_address (device);
+ device_mac = ether_aton (device_mac_str);
+ if (!device_mac) {
+ g_set_error (error, 0, 0, "Invalid device MAC address.");
+ return FALSE;
+ }
+
+ mac = nm_setting_wired_get_mac_address (s_wired);
+ if (mac && memcmp (mac->data, device_mac->ether_addr_octet, ETH_ALEN)) {
+ g_set_error (error, 0, 0,
+ "The connection's MAC address did not match this device.");
+ return FALSE;
+ }
+ }
+
+ // FIXME: check bitrate against device capabilities
+
+ return TRUE;
+}
+
+static gboolean
+check_wifi_compatible (NMDeviceWifi *device, NMConnection *connection, GError **error)
+{
+ NMSettingConnection *s_con;
+ NMSettingWireless *s_wireless;
+
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+ g_assert (s_con);
+
+ if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_WIRELESS_SETTING_NAME)) {
+ g_set_error (error, 0, 0,
+ "The connection was not a WiFi connection.");
+ return FALSE;
+ }
+
+ s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
+ if (!s_wireless) {
+ g_set_error (error, 0, 0,
+ "The connection was not a valid WiFi connection.");
+ return FALSE;
+ }
+
+ if (s_wireless) {
+ const GByteArray *mac;
+ const char *device_mac_str;
+ struct ether_addr *device_mac;
+
+ device_mac_str = nm_device_wifi_get_hw_address (device);
+ device_mac = ether_aton (device_mac_str);
+ if (!device_mac) {
+ g_set_error (error, 0, 0, "Invalid device MAC address.");
+ return FALSE;
+ }
+
+ mac = nm_setting_wireless_get_mac_address (s_wireless);
+ if (mac && memcmp (mac->data, device_mac->ether_addr_octet, ETH_ALEN)) {
+ g_set_error (error, 0, 0,
+ "The connection's MAC address did not match this device.");
+ return FALSE;
+ }
+ }
+
+ // FIXME: check channel/freq/band against bands the hardware supports
+ // FIXME: check encryption against device capabilities
+ // FIXME: check bitrate against device capabilities
+
+ return TRUE;
+}
+
+static gboolean
+check_bt_compatible (NMDeviceBt *device, NMConnection *connection, GError **error)
+{
+ NMSettingConnection *s_con;
+ NMSettingBluetooth *s_bt;
+ const GByteArray *array;
+ char *str;
+ const char *device_hw_str;
+ int addr_match = FALSE;
+ const char *bt_type_str;
+ guint32 bt_type, bt_capab;
+
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+ g_assert (s_con);
+
+ if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_BLUETOOTH_SETTING_NAME)) {
+ g_set_error (error, 0, 0,
+ "The connection was not a Bluetooth connection.");
+ return FALSE;
+ }
+
+ s_bt = NM_SETTING_BLUETOOTH (nm_connection_get_setting (connection, NM_TYPE_SETTING_BLUETOOTH));
+ if (!s_bt) {
+ g_set_error (error, 0, 0,
+ "The connection was not a valid Bluetooth connection.");
+ return FALSE;
+ }
+
+ array = nm_setting_bluetooth_get_bdaddr (s_bt);
+ if (!array || (array->len != ETH_ALEN)) {
+ g_set_error (error, 0, 0,
+ "The connection did not contain a valid Bluetooth address.");
+ return FALSE;
+ }
+
+ bt_type_str = nm_setting_bluetooth_get_connection_type (s_bt);
+ g_assert (bt_type_str);
+
+ bt_type = NM_BT_CAPABILITY_NONE;
+ if (!strcmp (bt_type_str, NM_SETTING_BLUETOOTH_TYPE_DUN))
+ bt_type = NM_BT_CAPABILITY_DUN;
+ else if (!strcmp (bt_type_str, NM_SETTING_BLUETOOTH_TYPE_PANU))
+ bt_type = NM_BT_CAPABILITY_NAP;
+
+ bt_capab = nm_device_bt_get_capabilities (device);
+ if (!(bt_type & bt_capab)) {
+ g_set_error (error, 0, 0,
+ "The connection was not compatible with the device's capabilities.");
+ return FALSE;
+ }
+
+ device_hw_str = nm_device_bt_get_hw_address (device);
+
+ str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
+ array->data[0], array->data[1], array->data[2],
+ array->data[3], array->data[4], array->data[5]);
+ addr_match = !strcmp (device_hw_str, str);
+ g_free (str);
+
+ return addr_match;
+}
+
+#if 0
+static gboolean
+check_olpc_mesh_compatible (NMDeviceOlpcMesh *device, NMConnection *connection, GError **error)
+{
+ NMSettingConnection *s_con;
+ NMSettingOlpcMesh *s_mesh;
+
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+ g_assert (s_con);
+
+ if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_OLPC_MESH_SETTING_NAME)) {
+ g_set_error (error, 0, 0,
+ "The connection was not a Mesh connection.");
+ return FALSE;
+ }
+
+ s_mesh = NM_SETTING_OLPC_MESH (nm_connection_get_setting (connection, NM_TYPE_SETTING_OLPC_MESH));
+ if (!s_mesh) {
+ g_set_error (error, 0, 0,
+ "The connection was not a valid Mesh connection.");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+#endif
+
+static gboolean
+nm_device_is_connection_compatible (NMDevice *device, NMConnection *connection, GError **error)
+{
+ g_return_val_if_fail (NM_IS_DEVICE (device), FALSE);
+ g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
+
+ if (NM_IS_DEVICE_ETHERNET (device))
+ return check_ethernet_compatible (NM_DEVICE_ETHERNET (device), connection, error);
+ else if (NM_IS_DEVICE_WIFI (device))
+ return check_wifi_compatible (NM_DEVICE_WIFI (device), connection, error);
+ else if (NM_IS_DEVICE_BT (device))
+ return check_bt_compatible (NM_DEVICE_BT (device), connection, error);
+// else if (NM_IS_DEVICE_OLPC_MESH (device))
+// return check_olpc_mesh_compatible (NM_DEVICE_OLPC_MESH (device), connection, error);
+
+ g_set_error (error, 0, 0, "unhandled device type '%s'", G_OBJECT_TYPE_NAME (device));
+ return FALSE;
+}
+
+
+/**
+ * nm_client_get_active_connection_by_path:
+ * @client: a #NMClient
+ * @object_path: the object path to search for
+ *
+ * Gets a #NMActiveConnection from a #NMClient.
+ *
+ * Returns: the #NMActiveConnection for the given @object_path or %NULL if none is found.
+ **/
+static NMActiveConnection *
+nm_client_get_active_connection_by_path (NMClient *client, const char *object_path)
+{
+ const GPtrArray *actives;
+ int i;
+ NMActiveConnection *active = NULL;
+
+ g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
+ g_return_val_if_fail (object_path, NULL);
+
+ actives = nm_client_get_active_connections (client);
+ if (!actives)
+ return NULL;
+
+ for (i = 0; i < actives->len; i++) {
+ NMActiveConnection *candidate = g_ptr_array_index (actives, i);
+ if (!strcmp (nm_object_get_path (NM_OBJECT (candidate)), object_path)) {
+ active = candidate;
+ break;
+ }
+ }
+
+ return active;
+}
+/* -------------------- */
+
+static NMActiveConnection *
+get_default_active_connection (NmCli *nmc, NMDevice **device)
+{
+ NMActiveConnection *default_ac = NULL;
+ NMDevice *non_default_device = NULL;
+ NMActiveConnection *non_default_ac = NULL;
+ const GPtrArray *connections;
+ int i;
+
+ g_return_val_if_fail (nmc != NULL, NULL);
+ g_return_val_if_fail (device != NULL, NULL);
+ g_return_val_if_fail (*device == NULL, NULL);
+
+ connections = nm_client_get_active_connections (nmc->client);
+ for (i = 0; connections && (i < connections->len); i++) {
+ NMActiveConnection *candidate = g_ptr_array_index (connections, i);
+ const GPtrArray *devices;
+
+ devices = nm_active_connection_get_devices (candidate);
+ if (!devices || !devices->len)
+ continue;
+
+ if (nm_active_connection_get_default (candidate)) {
+ if (!default_ac) {
+ *device = g_ptr_array_index (devices, 0);
+ default_ac = candidate;
+ }
+ } else {
+ if (!non_default_ac) {
+ non_default_device = g_ptr_array_index (devices, 0);
+ non_default_ac = candidate;
+ }
+ }
+ }
+
+ /* Prefer the default connection if one exists, otherwise return the first
+ * non-default connection.
+ */
+ if (!default_ac && non_default_ac) {
+ default_ac = non_default_ac;
+ *device = non_default_device;
+ }
+ return default_ac;
+}
+
+/* Find a device to activate the connection on.
+ * IN: connection: connection to activate
+ * iface: device interface name to use (optional)
+ * ap: access point to use (optional; valid just for 802-11-wireless)
+ * OUT: device: found device
+ * spec_object: specific_object path of NMAccessPoint
+ * RETURNS: TRUE when a device is found, FALSE otherwise.
+ */
+static gboolean
+find_device_for_connection (NmCli *nmc, NMConnection *connection, const char *iface, const char *ap,
+ NMDevice **device, const char **spec_object, GError **error)
+{
+ NMSettingConnection *s_con;
+ const char *con_type;
+ int i, j;
+
+ g_return_val_if_fail (nmc != NULL, FALSE);
+ g_return_val_if_fail (device != NULL && *device == NULL, FALSE);
+ g_return_val_if_fail (spec_object != NULL && *spec_object == NULL, FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
+ g_assert (s_con);
+ con_type = nm_setting_connection_get_connection_type (s_con);
+
+ if (strcmp (con_type, "vpn") == 0) {
+ /* VPN connections */
+ NMActiveConnection *active = NULL;
+ if (iface) {
+ const GPtrArray *connections = nm_client_get_active_connections (nmc->client);
+ for (i = 0; connections && (i < connections->len) && !active; i++) {
+ NMActiveConnection *candidate = g_ptr_array_index (connections, i);
+ const GPtrArray *devices = nm_active_connection_get_devices (candidate);
+ if (!devices || !devices->len)
+ continue;
+
+ for (j = 0; devices && (j < devices->len); j++) {
+ NMDevice *dev = g_ptr_array_index (devices, j);
+ if (!strcmp (iface, nm_device_get_iface (dev))) {
+ active = candidate;
+ *device = dev;
+ break;
+ }
+ }
+ }
+ if (!active) {
+ g_set_error (error, 0, 0, _("no active connection on device '%s'"), iface);
+ return FALSE;
+ }
+ *spec_object = nm_object_get_path (NM_OBJECT (active));
+ return TRUE;
+ } else {
+ active = get_default_active_connection (nmc, device);
+ if (!active) {
+ g_set_error (error, 0, 0, _("no active connection or device"));
+ return FALSE;
+ }
+ *spec_object = nm_object_get_path (NM_OBJECT (active));
+ return TRUE;
+ }
+ } else {
+ /* Other connections */
+ NMDevice *found_device = NULL;
+ const GPtrArray *devices = nm_client_get_devices (nmc->client);
+
+ for (i = 0; devices && (i < devices->len) && !found_device; i++) {
+ NMDevice *dev = g_ptr_array_index (devices, i);
+
+ if (iface) {
+ const char *dev_iface = nm_device_get_iface (dev);
+ if ( !strcmp (dev_iface, iface)
+ && nm_device_is_connection_compatible (dev, connection, NULL)) {
+ found_device = dev;
+ }
+ } else {
+ if (nm_device_is_connection_compatible (dev, connection, NULL)) {
+ found_device = dev;
+ }
+ }
+
+ if (found_device && ap && !strcmp (con_type, "802-11-wireless") && NM_IS_DEVICE_WIFI (dev)) {
+ char *hwaddr_up = g_ascii_strup (ap, -1);
+ const GPtrArray *aps = nm_device_wifi_get_access_points (NM_DEVICE_WIFI (dev));
+ found_device = NULL; /* Mark as not found; set to the device again later, only if AP matches */
+
+ for (j = 0; aps && (j < aps->len); j++) {
+ NMAccessPoint *candidate_ap = g_ptr_array_index (aps, j);
+ const char *candidate_hwaddr = nm_access_point_get_hw_address (candidate_ap);
+
+ if (!strcmp (hwaddr_up, candidate_hwaddr)) {
+ found_device = dev;
+ *spec_object = nm_object_get_path (NM_OBJECT (candidate_ap));
+ break;
+ }
+ }
+ g_free (hwaddr_up);
+ }
+ }
+
+ if (found_device) {
+ *device = found_device;
+ return TRUE;
+ } else {
+ if (iface)
+ g_set_error (error, 0, 0, "device '%s' not compatible with connection '%s'", iface, nm_setting_connection_get_id (s_con));
+ else
+ g_set_error (error, 0, 0, "no device found for connection '%s'", nm_setting_connection_get_id (s_con));
+ return FALSE;
+ }
+ }
+}
+
+static const char *
+active_connection_state_to_string (NMActiveConnectionState state)
+{
+ switch (state) {
+ case NM_ACTIVE_CONNECTION_STATE_ACTIVATING:
+ return _("activating");
+ case NM_ACTIVE_CONNECTION_STATE_ACTIVATED:
+ return _("activated");
+ case NM_ACTIVE_CONNECTION_STATE_UNKNOWN:
+ default:
+ return _("unknown");
+ }
+}
+
+static const char *
+vpn_connection_state_to_string (NMVPNConnectionState state)
+{
+ switch (state) {
+ case NM_VPN_CONNECTION_STATE_PREPARE:
+ return _("VPN connecting (prepare)");
+ case NM_VPN_CONNECTION_STATE_NEED_AUTH:
+ return _("VPN connecting (need authentication)");
+ case NM_VPN_CONNECTION_STATE_CONNECT:
+ return _("VPN connecting");
+ case NM_VPN_CONNECTION_STATE_IP_CONFIG_GET:
+ return _("VPN connecting (getting IP configuration)");
+ case NM_VPN_CONNECTION_STATE_ACTIVATED:
+ return _("VPN connected");
+ case NM_VPN_CONNECTION_STATE_FAILED:
+ return _("VPN connection failed");
+ case NM_VPN_CONNECTION_STATE_DISCONNECTED:
+ return _("VPN disconnected");
+ default:
+ return _("unknown");
+ }
+}
+
+static const char *
+vpn_connection_state_reason_to_string (NMVPNConnectionStateReason reason)
+{
+ switch (reason) {
+ case NM_VPN_CONNECTION_STATE_REASON_UNKNOWN:
+ return _("unknown reason");
+ case NM_VPN_CONNECTION_STATE_REASON_NONE:
+ return _("none");
+ case NM_VPN_CONNECTION_STATE_REASON_USER_DISCONNECTED:
+ return _("the user was disconnected");
+ case NM_VPN_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED:
+ return _("the base network connection was interrupted");
+ case NM_VPN_CONNECTION_STATE_REASON_SERVICE_STOPPED:
+ return _("the VPN service stopped unexpectedly");
+ case NM_VPN_CONNECTION_STATE_REASON_IP_CONFIG_INVALID:
+ return _("the VPN service returned invalid configuration");
+ case NM_VPN_CONNECTION_STATE_REASON_CONNECT_TIMEOUT:
+ return _("the connection attempt timed out");
+ case NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_TIMEOUT:
+ return _("the VPN service did not start in time");
+ case NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_FAILED:
+ return _("the VPN service failed to start");
+ case NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS:
+ return _("no valid VPN secrets");
+ case NM_VPN_CONNECTION_STATE_REASON_LOGIN_FAILED:
+ return _("invalid VPN secrets");
+ case NM_VPN_CONNECTION_STATE_REASON_CONNECTION_REMOVED:
+ return _("the connection was removed");
+ default:
+ return _("unknown");
+ }
+}
+
+static void
+active_connection_state_cb (NMActiveConnection *active, GParamSpec *pspec, gpointer user_data)
+{
+ NmCli *nmc = (NmCli *) user_data;
+ NMActiveConnectionState state;
+
+ state = nm_active_connection_get_state (active);
+
+ printf (_("state: %s\n"), active_connection_state_to_string (state));
+
+ if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
+ printf (_("Connection activated\n"));
+ quit ();
+ } else if (state == NM_ACTIVE_CONNECTION_STATE_UNKNOWN) {
+ g_string_printf (nmc->return_text, _("Error: Connection activation failed."));
+ nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
+ quit ();
+ }
+}
+
+static void
+vpn_connection_state_cb (NMVPNConnection *vpn,
+ NMVPNConnectionState state,
+ NMVPNConnectionStateReason reason,
+ gpointer user_data)
+{
+ NmCli *nmc = (NmCli *) user_data;
+
+ switch (state) {
+ case NM_VPN_CONNECTION_STATE_PREPARE:
+ case NM_VPN_CONNECTION_STATE_NEED_AUTH:
+ case NM_VPN_CONNECTION_STATE_CONNECT:
+ case NM_VPN_CONNECTION_STATE_IP_CONFIG_GET:
+ printf (_("state: %s (%d)\n"), vpn_connection_state_to_string (state), state);
+ break;
+
+ case NM_VPN_CONNECTION_STATE_ACTIVATED:
+ printf (_("Connection activated\n"));
+ quit ();
+ break;
+
+ case NM_VPN_CONNECTION_STATE_FAILED:
+ case NM_VPN_CONNECTION_STATE_DISCONNECTED:
+ g_string_printf (nmc->return_text, _("Error: Connection activation failed: %s."), vpn_connection_state_reason_to_string (reason));
+ nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
+ quit ();
+ break;
+
+ default:
+ break;
+ }
+}
+
+static gboolean
+timeout_cb (gpointer user_data)
+{
+ /* Time expired -> exit nmcli */
+
+ NmCli *nmc = (NmCli *) user_data;
+
+ g_string_printf (nmc->return_text, _("Error: Timeout %d sec expired."), nmc->timeout);
+ nmc->return_value = NMC_RESULT_ERROR_TIMEOUT_EXPIRED;
+ quit ();
+ return FALSE;
+}
+
+static void
+foo_active_connections_changed_cb (NMClient *client,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ /* Call again activate_connection_cb with dummy arguments;
+ * the correct ones are taken from its first call.
+ */
+ activate_connection_cb (NULL, NULL, NULL);
+}
+
+static void
+activate_connection_cb (gpointer user_data, const char *path, GError *error)
+{
+ NmCli *nmc = (NmCli *) user_data;
+ NMActiveConnection *active;
+ NMActiveConnectionState state;
+ static gulong handler_id = 0;
+ static NmCli *orig_nmc;
+ static const char *orig_path;
+ static GError *orig_error;
+
+ if (nmc)
+ {
+ /* Called first time; store actual arguments */
+ orig_nmc = nmc;
+ orig_path = path;
+ orig_error = error;
+ }
+
+ /* Disconnect the handler not to be run any more */
+ if (handler_id != 0) {
+ g_signal_handler_disconnect (orig_nmc->client, handler_id);
+ handler_id = 0;
+ }
+
+ if (orig_error) {
+ g_string_printf (orig_nmc->return_text, _("Error: Connection activation failed: %s"), orig_error->message);
+ orig_nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
+ quit ();
+ } else {
+ active = nm_client_get_active_connection_by_path (orig_nmc->client, orig_path);
+ if (!active) {
+ /* The active connection path is not in active connections list yet; wait for active-connections signal. */
+ /* This is basically the case for VPN connections. */
+ if (nmc) {
+ /* Called first time, i.e. by nm_client_activate_connection() */
+ handler_id = g_signal_connect (orig_nmc->client, "notify::active-connections",
+ G_CALLBACK (foo_active_connections_changed_cb), NULL);
+ return;
+ } else {
+ g_string_printf (orig_nmc->return_text, _("Error: Obtaining active connection for '%s' failed."), orig_path);
+ orig_nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
+ quit ();
+ return;
+ }
+ }
+
+ state = nm_active_connection_get_state (active);
+
+ printf (_("Active connection state: %s\n"), active_connection_state_to_string (state));
+ printf (_("Active connection path: %s\n"), orig_path);
+
+ if (!orig_nmc->should_wait || state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
+ /* don't want to wait or already activated */
+ quit ();
+ } else {
+ if (NM_IS_VPN_CONNECTION (active))
+ g_signal_connect (NM_VPN_CONNECTION (active), "vpn-state-changed", G_CALLBACK (vpn_connection_state_cb), orig_nmc);
+ else
+ g_signal_connect (active, "notify::state", G_CALLBACK (active_connection_state_cb), orig_nmc);
+
+ /* Start timer not to loop forever when signals are not emitted */
+ g_timeout_add_seconds (orig_nmc->timeout, timeout_cb, orig_nmc);
+ }
+ }
+}
+
+static NMCResultCode
+do_connection_up (NmCli *nmc, int argc, char **argv)
+{
+ NMDevice *device = NULL;
+ const char *spec_object = NULL;
+ gboolean device_found;
+ NMConnection *connection = NULL;
+ NMSettingConnection *s_con;
+ gboolean is_system;
+ const char *con_path;
+ const char *con_type;
+ const char *iface = NULL;
+ const char *ap = NULL;
+ gboolean id_specified = FALSE;
+ gboolean wait = TRUE;
+ GError *error = NULL;
+
+ /* Set default timeout for connection activation. It can take quite a long time.
+ * Using 90 seconds.
+ */
+ nmc->timeout = 90;
+
+ while (argc > 0) {
+ if (strcmp (*argv, "id") == 0 || strcmp (*argv, "uuid") == 0) {
+ const char *selector = *argv;
+ id_specified = TRUE;
+
+ if (next_arg (&argc, &argv) != 0) {
+ g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *argv);
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ goto error;
+ }
+
+ if ((connection = find_connection (nmc->system_connections, selector, *argv)) == NULL)
+ connection = find_connection (nmc->user_connections, selector, *argv);
+
+ if (!connection) {
+ g_string_printf (nmc->return_text, _("Error: Unknown connection: %s."), *argv);
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ goto error;
+ }
+ }
+ else if (strcmp (*argv, "iface") == 0) {
+ if (next_arg (&argc, &argv) != 0) {
+ g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *argv);
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ goto error;
+ }
+
+ iface = *argv;
+ }
+ else if (strcmp (*argv, "ap") == 0) {
+ if (next_arg (&argc, &argv) != 0) {
+ g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *argv);
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ goto error;
+ }
+
+ ap = *argv;
+ }
+ else if (strcmp (*argv, "--nowait") == 0) {
+ wait = FALSE;
+ } else if (strcmp (*argv, "--timeout") == 0) {
+ if (next_arg (&argc, &argv) != 0) {
+ g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *argv);
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ goto error;
+ }
+
+ errno = 0;
+ nmc->timeout = strtol (*argv, NULL, 10);
+ if (errno || nmc->timeout < 0) {
+ g_string_printf (nmc->return_text, _("Error: timeout value '%s' is not valid."), *argv);
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ goto error;
+ }
+ } else {
+ fprintf (stderr, _("Unknown parameter: %s\n"), *argv);
+ }
+
+ argc--;
+ argv++;
+ }
+
+ if (!id_specified) {
+ g_string_printf (nmc->return_text, _("Error: id or uuid has to be specified."));
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ goto error;
+ }
+
+ /* create NMClient */
+ if (!nmc->get_client (nmc))
+ goto error;
+
+ is_system = (nm_connection_get_scope (connection) == NM_CONNECTION_SCOPE_SYSTEM) ? TRUE : FALSE;
+ con_path = nm_connection_get_path (connection);
+
+ s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
+ g_assert (s_con);
+ con_type = nm_setting_connection_get_connection_type (s_con);
+
+ device_found = find_device_for_connection (nmc, connection, iface, ap, &device, &spec_object, &error);
+
+ if (!device_found) {
+ if (error)
+ g_string_printf (nmc->return_text, _("Error: No suitable device found: %s."), error->message);
+ else
+ g_string_printf (nmc->return_text, _("Error: No suitable device found."));
+ nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
+ goto error;
+ }
+
+ nmc->should_wait = wait;
+ nm_client_activate_connection (nmc->client,
+ is_system ? NM_DBUS_SERVICE_SYSTEM_SETTINGS : NM_DBUS_SERVICE_USER_SETTINGS,
+ con_path,
+ device,
+ spec_object,
+ activate_connection_cb,
+ nmc);
+
+ return nmc->return_value;
+error:
+ nmc->should_wait = FALSE;
+ return nmc->return_value;
+}
+
+static NMCResultCode
+do_connection_down (NmCli *nmc, int argc, char **argv)
+{
+ NMConnection *connection = NULL;
+ NMActiveConnection *active = NULL;
+ const GPtrArray *active_cons;
+ const char *con_path;
+ const char *active_path;
+ NMConnectionScope active_service_scope, con_scope;
+ gboolean id_specified = FALSE;
+ gboolean wait = TRUE;
+ int i;
+
+ while (argc > 0) {
+ if (strcmp (*argv, "id") == 0 || strcmp (*argv, "uuid") == 0) {
+ const char *selector = *argv;
+ id_specified = TRUE;
+
+ if (next_arg (&argc, &argv) != 0) {
+ g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *argv);
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ goto error;
+ }
+
+ if ((connection = find_connection (nmc->system_connections, selector, *argv)) == NULL)
+ connection = find_connection (nmc->user_connections, selector, *argv);
+
+ if (!connection) {
+ g_string_printf (nmc->return_text, _("Error: Unknown connection: %s."), *argv);
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ goto error;
+ }
+ }
+ else if (strcmp (*argv, "--nowait") == 0) {
+ wait = FALSE;
+ }
+ else {
+ fprintf (stderr, _("Unknown parameter: %s\n"), *argv);
+ }
+
+ argc--;
+ argv++;
+ }
+
+ if (!id_specified) {
+ g_string_printf (nmc->return_text, _("Error: id or uuid has to be specified."));
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ goto error;
+ }
+
+ /* create NMClient */
+ if (!nmc->get_client (nmc))
+ goto error;
+
+ con_path = nm_connection_get_path (connection);
+ con_scope = nm_connection_get_scope (connection);
+
+ active_cons = nm_client_get_active_connections (nmc->client);
+ for (i = 0; active_cons && (i < active_cons->len); i++) {
+ NMActiveConnection *candidate = g_ptr_array_index (active_cons, i);
+
+ active_path = nm_active_connection_get_connection (candidate);
+ active_service_scope = nm_active_connection_get_scope (candidate);
+ if (!strcmp (active_path, con_path) && active_service_scope == con_scope) {
+ active = candidate;
+ break;
+ }
+ }
+
+ if (active)
+ nm_client_deactivate_connection (nmc->client, active);
+ else {
+ fprintf (stderr, _("Warning: Connection not active\n"));
+ }
+
+error:
+ nmc->should_wait = FALSE;
+ return nmc->return_value;
+}
+
+/* callback called when connections are obtained from the settings service */
+static void
+get_connections_cb (NMSettingsInterface *settings, gpointer user_data)
+{
+ ArgsInfo *args = (ArgsInfo *) user_data;
+ static gboolean system_cb_called = FALSE;
+ static gboolean user_cb_called = FALSE;
+
+ if (NM_IS_REMOTE_SETTINGS_SYSTEM (settings)) {
+ system_cb_called = TRUE;
+ args->nmc->system_connections = nm_settings_interface_list_connections (settings);
+ }
+ else {
+ user_cb_called = TRUE;
+ args->nmc->user_connections = nm_settings_interface_list_connections (settings);
+ }
+
+ /* return and wait for the callback of the second settings is called */
+ if ((args->nmc->system_settings_running && !system_cb_called) ||
+ (args->nmc->user_settings_running && !user_cb_called))
+ return;
+
+ if (args->argc == 0) {
+ args->nmc->return_value = do_connections_list (args->nmc, args->argc, args->argv);
+ } else {
+
+ if (matches (*args->argv, "list") == 0) {
+ args->nmc->return_value = do_connections_list (args->nmc, args->argc-1, args->argv+1);
+ }
+ else if (matches(*args->argv, "status") == 0) {
+ args->nmc->return_value = do_connections_status (args->nmc, args->argc-1, args->argv+1);
+ }
+ else if (matches(*args->argv, "up") == 0) {
+ args->nmc->return_value = do_connection_up (args->nmc, args->argc-1, args->argv+1);
+ }
+ else if (matches(*args->argv, "down") == 0) {
+ args->nmc->return_value = do_connection_down (args->nmc, args->argc-1, args->argv+1);
+ }
+ else if (matches (*args->argv, "help") == 0) {
+ usage ();
+ args->nmc->should_wait = FALSE;
+ } else {
+ usage ();
+ g_string_printf (args->nmc->return_text, _("Error: 'con' command '%s' is not valid."), *args->argv);
+ args->nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ args->nmc->should_wait = FALSE;
+ }
+ }
+
+ if (!args->nmc->should_wait)
+ quit ();
+}
+
+
+/* Entry point function for connections-related commands: 'nmcli con' */
+NMCResultCode
+do_connections (NmCli *nmc, int argc, char **argv)
+{
+ DBusGConnection *bus;
+ GError *error = NULL;
+
+ nmc->should_wait = TRUE;
+
+ args_info.nmc = nmc;
+ args_info.argc = argc;
+ args_info.argv = argv;
+
+ /* connect to DBus' system bus */
+ bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
+ if (error || !bus) {
+ g_string_printf (nmc->return_text, _("Error: could not connect to D-Bus."));
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ return nmc->return_value;
+ }
+
+ /* get system settings */
+ if (!(nmc->system_settings = nm_remote_settings_system_new (bus))) {
+ g_string_printf (nmc->return_text, _("Error: Could not get system settings."));
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ return nmc->return_value;
+
+ }
+
+ /* get user settings */
+ if (!(nmc->user_settings = nm_remote_settings_new (bus, NM_CONNECTION_SCOPE_USER))) {
+ g_string_printf (nmc->return_text, _("Error: Could not get user settings."));
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ return nmc->return_value;
+ }
+
+ /* find out whether setting services are running */
+ g_object_get (nmc->system_settings, NM_REMOTE_SETTINGS_SERVICE_RUNNING, &nmc->system_settings_running, NULL);
+ g_object_get (nmc->user_settings, NM_REMOTE_SETTINGS_SERVICE_RUNNING, &nmc->user_settings_running, NULL);
+
+ if (!nmc->system_settings_running && !nmc->user_settings_running) {
+ g_string_printf (nmc->return_text, _("Error: Can't obtain connections: settings services are not running."));
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ return nmc->return_value;
+ }
+
+ /* connect to signal "connections-read" - emitted when connections are fetched and ready */
+ if (nmc->system_settings_running)
+ g_signal_connect (nmc->system_settings, NM_SETTINGS_INTERFACE_CONNECTIONS_READ,
+ G_CALLBACK (get_connections_cb), &args_info);
+
+ if (nmc->user_settings_running)
+ g_signal_connect (nmc->user_settings, NM_SETTINGS_INTERFACE_CONNECTIONS_READ,
+ G_CALLBACK (get_connections_cb), &args_info);
+
+ dbus_g_connection_unref (bus);
+
+ /* The rest will be done in get_connection_cb() callback.
+ * We need to wait for signals that connections are read.
+ */
+ return NMC_RESULT_SUCCESS;
+}
diff --git a/cli/src/connections.h b/cli/src/connections.h
new file mode 100644
index 0000000..a1ed1c1
--- a/dev/null
+++ b/cli/src/connections.h
@@ -0,0 +1,27 @@
+/* nmcli - command-line tool to control NetworkManager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2010 Red Hat, Inc.
+ */
+
+#ifndef NMC_CONNECTIONS_H
+#define NMC_CONNECTIONS_H
+
+#include "nmcli.h"
+
+NMCResultCode do_connections (NmCli *nmc, int argc, char **argv);
+
+#endif /* NMC_CONNECTIONS_H */
diff --git a/cli/src/devices.c b/cli/src/devices.c
new file mode 100644
index 0000000..d6c0b43
--- a/dev/null
+++ b/cli/src/devices.c
@@ -0,0 +1,950 @@
+/* nmcli - command-line tool to control NetworkManager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2010 Red Hat, Inc.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <nm-client.h>
+#include <nm-device-wifi.h>
+
+#include <nm-client.h>
+#include <nm-device.h>
+#include <nm-device-ethernet.h>
+#include <nm-device-wifi.h>
+#include <nm-gsm-device.h>
+#include <nm-cdma-device.h>
+#include <nm-device-bt.h>
+//#include <nm-device-olpc-mesh.h>
+#include <nm-utils.h>
+#include <nm-setting-ip4-config.h>
+#include <nm-vpn-connection.h>
+#include <nm-setting-connection.h>
+#include <nm-setting-wired.h>
+#include <nm-setting-pppoe.h>
+#include <nm-setting-wireless.h>
+#include <nm-setting-gsm.h>
+#include <nm-setting-cdma.h>
+#include <nm-setting-bluetooth.h>
+#include <nm-setting-olpc-mesh.h>
+
+#include "utils.h"
+#include "devices.h"
+
+
+/* static function prototypes */
+static void usage (void);
+static const char *device_state_to_string (NMDeviceState state);
+static NMCResultCode do_devices_status (NmCli *nmc, int argc, char **argv);
+static NMCResultCode do_devices_list (NmCli *nmc, int argc, char **argv);
+static NMCResultCode do_device_disconnect (NmCli *nmc, int argc, char **argv);
+static NMCResultCode do_device_wifi (NmCli *nmc, int argc, char **argv);
+
+
+extern GMainLoop *loop; /* glib main loop variable */
+
+static void
+usage (void)
+{
+ fprintf (stderr,
+ _("Usage: nmcli dev { COMMAND | help }\n\n"
+ " COMMAND := { status | list | disconnect | wifi }\n\n"
+ " status\n"
+ " list [iface <iface>]\n"
+ " disconnect iface <iface> [--nowait] [--timeout <timeout>]\n"
+ " wifi [list [iface <iface>] | apinfo iface <iface> hwaddr <hwaddr>]\n\n"));
+}
+
+/* quit main loop */
+static void
+quit (void)
+{
+ g_main_loop_quit (loop); /* quit main loop */
+}
+
+static const char *
+device_state_to_string (NMDeviceState state)
+{
+ switch (state) {
+ case NM_DEVICE_STATE_UNMANAGED:
+ return _("unmanaged");
+ case NM_DEVICE_STATE_UNAVAILABLE:
+ return _("unavailable");
+ case NM_DEVICE_STATE_DISCONNECTED:
+ return _("disconnected");
+ case NM_DEVICE_STATE_PREPARE:
+ return _("connecting (prepare)");
+ case NM_DEVICE_STATE_CONFIG:
+ return _("connecting (configuring)");
+ case NM_DEVICE_STATE_NEED_AUTH:
+ return _("connecting (need authentication)");
+ case NM_DEVICE_STATE_IP_CONFIG:
+ return _("connecting (getting IP configuration)");
+ case NM_DEVICE_STATE_ACTIVATED:
+ return _("connected");
+ case NM_DEVICE_STATE_FAILED:
+ return _("connection failed");
+ default:
+ return _("unknown");
+ }
+}
+
+/* Return device type - use setting names to match with connection types */
+static const char *
+get_device_type (NMDevice * device)
+{
+ if (NM_IS_DEVICE_ETHERNET (device))
+ return NM_SETTING_WIRED_SETTING_NAME;
+ else if (NM_IS_DEVICE_WIFI (device))
+ return NM_SETTING_WIRELESS_SETTING_NAME;
+ else if (NM_IS_GSM_DEVICE (device))
+ return NM_SETTING_GSM_SETTING_NAME;
+ else if (NM_IS_CDMA_DEVICE (device))
+ return NM_SETTING_CDMA_SETTING_NAME;
+ else if (NM_IS_DEVICE_BT (device))
+ return NM_SETTING_BLUETOOTH_SETTING_NAME;
+// else if (NM_IS_DEVICE_OLPC_MESH (device))
+// return NM_SETTING_OLPC_MESH_SETTING_NAME;
+ else
+ return _("Unknown");
+}
+
+static char *
+ap_wpa_rsn_flags_to_string (guint32 flags)
+{
+ char *flags_str[16]; /* Enough space for flags and terminating NULL */
+ char *ret_str;
+ int i = 0;
+
+ if (flags & NM_802_11_AP_SEC_PAIR_WEP40)
+ flags_str[i++] = g_strdup ("pair_wpe40");
+ if (flags & NM_802_11_AP_SEC_PAIR_WEP104)
+ flags_str[i++] = g_strdup ("pair_wpe104");
+ if (flags & NM_802_11_AP_SEC_PAIR_TKIP)
+ flags_str[i++] = g_strdup ("pair_tkip");
+ if (flags & NM_802_11_AP_SEC_PAIR_CCMP)
+ flags_str[i++] = g_strdup ("pair_ccmp");
+ if (flags & NM_802_11_AP_SEC_GROUP_WEP40)
+ flags_str[i++] = g_strdup ("group_wpe40");
+ if (flags & NM_802_11_AP_SEC_GROUP_WEP104)
+ flags_str[i++] = g_strdup ("group_wpe104");
+ if (flags & NM_802_11_AP_SEC_GROUP_TKIP)
+ flags_str[i++] = g_strdup ("group_tkip");
+ if (flags & NM_802_11_AP_SEC_GROUP_CCMP)
+ flags_str[i++] = g_strdup ("group_ccmp");
+ if (flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)
+ flags_str[i++] = g_strdup ("psk");
+ if (flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)
+ flags_str[i++] = g_strdup ("802.1X");
+
+ if (i == 0)
+ flags_str[i++] = g_strdup (_("(none)"));
+
+ flags_str[i] = NULL;
+
+ ret_str = g_strjoinv (" ", flags_str);
+
+ i = 0;
+ while (flags_str[i])
+ g_free (flags_str[i++]);
+
+ return ret_str;
+}
+
+static void
+print_header (const char *label, const char *iface, const char *connection)
+{
+ GString *string;
+
+ string = g_string_sized_new (79);
+ g_string_append_printf (string, "- %s: ", label);
+ if (iface)
+ g_string_append_printf (string, "%s ", iface);
+ if (connection)
+ g_string_append_printf (string, " [%s] ", connection);
+
+ while (string->len < 80)
+ g_string_append_c (string, '-');
+
+ printf ("%s\n", string->str);
+
+ g_string_free (string, TRUE);
+}
+
+static gchar *
+ip4_address_as_string (guint32 ip)
+{
+ struct in_addr tmp_addr;
+ char buf[INET_ADDRSTRLEN+1];
+
+ memset (&buf, '\0', sizeof (buf));
+ tmp_addr.s_addr = ip;
+
+ if (inet_ntop (AF_INET, &tmp_addr, buf, INET_ADDRSTRLEN)) {
+ return g_strdup (buf);
+ } else {
+ g_warning (_("%s: error converting IP4 address 0x%X"),
+ __func__, ntohl (tmp_addr.s_addr));
+ return NULL;
+ }
+}
+
+static void
+detail_access_point (gpointer data, gpointer user_data)
+{
+ NMAccessPoint *ap = NM_ACCESS_POINT (data);
+ const char *active_bssid = (const char *) user_data;
+ GString *str;
+ gboolean active = FALSE;
+ guint32 flags, wpa_flags, rsn_flags;
+ const GByteArray * ssid;
+ char *tmp;
+
+ flags = nm_access_point_get_flags (ap);
+ wpa_flags = nm_access_point_get_wpa_flags (ap);
+ rsn_flags = nm_access_point_get_rsn_flags (ap);
+
+ if (active_bssid) {
+ const char *current_bssid = nm_access_point_get_hw_address (ap);
+ if (current_bssid && !strcmp (current_bssid, active_bssid))
+ active = TRUE;
+ }
+
+ str = g_string_new (NULL);
+ g_string_append_printf (str,
+ _("%s, %s, Freq %d MHz, Rate %d Mb/s, Strength %d"),
+ (nm_access_point_get_mode (ap) == NM_802_11_MODE_INFRA) ? ("Infra") : _("Ad-Hoc"),
+ nm_access_point_get_hw_address (ap),
+ nm_access_point_get_frequency (ap),
+ nm_access_point_get_max_bitrate (ap) / 1000,
+ nm_access_point_get_strength (ap));
+
+ if ( !(flags & NM_802_11_AP_FLAGS_PRIVACY)
+ && (wpa_flags != NM_802_11_AP_SEC_NONE)
+ && (rsn_flags != NM_802_11_AP_SEC_NONE))
+ g_string_append (str, _(", Encrypted: "));
+
+ if ( (flags & NM_802_11_AP_FLAGS_PRIVACY)
+ && (wpa_flags == NM_802_11_AP_SEC_NONE)
+ && (rsn_flags == NM_802_11_AP_SEC_NONE))
+ g_string_append (str, _(" WEP"));
+ if (wpa_flags != NM_802_11_AP_SEC_NONE)
+ g_string_append (str, _(" WPA"));
+ if (rsn_flags != NM_802_11_AP_SEC_NONE)
+ g_string_append (str, _(" WPA2"));
+ if ( (wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)
+ || (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X))
+ g_string_append (str, _(" Enterprise"));
+
+ /* FIXME: broadcast/hidden */
+
+ ssid = nm_access_point_get_ssid (ap);
+ tmp = g_strdup_printf (" %s%s", active ? "*" : "",
+ ssid ? nm_utils_escape_ssid (ssid->data, ssid->len) : _("(none)"));
+
+ print_table_line (0, tmp, 25, str->str, 0, NULL);
+
+ g_string_free (str, TRUE);
+ g_free (tmp);
+}
+
+struct cb_info {
+ NMClient *client;
+ const GPtrArray *active;
+};
+
+static void
+show_device_info (gpointer data, gpointer user_data)
+{
+ NMDevice *device = NM_DEVICE (data);
+// struct cb_info *info = user_data;
+ char *tmp;
+ NMDeviceState state;
+ const char *dev_type;
+ guint32 caps;
+ guint32 speed;
+ const GArray *array;
+ gboolean is_default = FALSE;
+ const char *id = NULL;
+
+ state = nm_device_get_state (device);
+ print_header (_("Device"), nm_device_get_iface (device), id);
+
+ /* General information */
+ dev_type = get_device_type (device);
+ print_table_line (0, _("Type"), 25, dev_type, 0, NULL);
+ print_table_line (0, _("Driver"), 25, nm_device_get_driver (device) ? nm_device_get_driver (device) : _("(unknown)"), 0, NULL);
+ print_table_line (0, _("State"), 25, device_state_to_string (state), 0, NULL);
+ if (is_default)
+ print_table_line (0, _("Default"), 25, _("yes"), 0, NULL);
+ else
+ print_table_line (0, _("Default"), 25, _("no"), 0, NULL);
+
+ tmp = NULL;
+ if (NM_IS_DEVICE_ETHERNET (device))
+ tmp = g_strdup (nm_device_ethernet_get_hw_address (NM_DEVICE_ETHERNET (device)));
+ else if (NM_IS_DEVICE_WIFI (device))
+ tmp = g_strdup (nm_device_wifi_get_hw_address (NM_DEVICE_WIFI (device)));
+
+ if (tmp) {
+ print_table_line (0, _("HW Address"), 25, tmp, 0, NULL);
+ g_free (tmp);
+ }
+
+ /* Capabilities */
+ caps = nm_device_get_capabilities (device);
+ printf (_("\n Capabilities:\n"));
+ if (caps & NM_DEVICE_CAP_CARRIER_DETECT)
+ print_table_line (2, _("Carrier Detect"), 23, _("yes"), 0, NULL);
+
+ speed = 0;
+ if (NM_IS_DEVICE_ETHERNET (device)) {
+ /* Speed in Mb/s */
+ speed = nm_device_ethernet_get_speed (NM_DEVICE_ETHERNET (device));
+ } else if (NM_IS_DEVICE_WIFI (device)) {
+ /* Speed in b/s */
+ speed = nm_device_wifi_get_bitrate (NM_DEVICE_WIFI (device));
+ speed /= 1000;
+ }
+
+ if (speed) {
+ char *speed_string;
+
+ speed_string = g_strdup_printf (_("%u Mb/s"), speed);
+ print_table_line (2, _("Speed"), 23, speed_string, 0, NULL);
+ g_free (speed_string);
+ }
+
+ /* Wireless specific information */
+ if ((NM_IS_DEVICE_WIFI (device))) {
+ guint32 wcaps;
+ NMAccessPoint *active_ap = NULL;
+ const char *active_bssid = NULL;
+ const GPtrArray *aps;
+
+ printf (_("\n Wireless Properties\n"));
+
+ wcaps = nm_device_wifi_get_capabilities (NM_DEVICE_WIFI (device));
+
+ if (wcaps & (NM_WIFI_DEVICE_CAP_CIPHER_WEP40 | NM_WIFI_DEVICE_CAP_CIPHER_WEP104))
+ print_table_line (2, _("WEP Encryption"), 23, _("yes"), 0, NULL);
+ if (wcaps & NM_WIFI_DEVICE_CAP_WPA)
+ print_table_line (2, _("WPA Encryption"), 23, _("yes"), 0, NULL);
+ if (wcaps & NM_WIFI_DEVICE_CAP_RSN)
+ print_table_line (2, _("WPA2 Encryption"), 23, _("yes"), 0, NULL);
+ if (wcaps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP)
+ print_table_line (2, _("TKIP cipher"), 23, _("yes"), 0, NULL);
+ if (wcaps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP)
+ print_table_line (2, _("CCMP cipher"), 23, _("yes"), 0, NULL);
+
+ if (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED) {
+ active_ap = nm_device_wifi_get_active_access_point (NM_DEVICE_WIFI (device));
+ active_bssid = active_ap ? nm_access_point_get_hw_address (active_ap) : NULL;
+ }
+
+ printf (_("\n Wireless Access Points %s\n"), active_ap ? _("(* = current AP)") : "");
+
+ aps = nm_device_wifi_get_access_points (NM_DEVICE_WIFI (device));
+ if (aps && aps->len)
+ g_ptr_array_foreach ((GPtrArray *) aps, detail_access_point, (gpointer) active_bssid);
+ } else if (NM_IS_DEVICE_ETHERNET (device)) {
+ printf (_("\n Wired Properties\n"));
+
+ if (nm_device_ethernet_get_carrier (NM_DEVICE_ETHERNET (device)))
+ print_table_line (2, _("Carrier"), 23, _("on"), 0, NULL);
+ else
+ print_table_line (2, _("Carrier"), 23, _("off"), 0, NULL);
+ }
+
+ /* IP Setup info */
+ if (state == NM_DEVICE_STATE_ACTIVATED) {
+ NMIP4Config *cfg = nm_device_get_ip4_config (device);
+ GSList *iter;
+
+ printf (_("\n IPv4 Settings:\n"));
+
+ for (iter = (GSList *) nm_ip4_config_get_addresses (cfg); iter; iter = g_slist_next (iter)) {
+ NMIP4Address *addr = (NMIP4Address *) iter->data;
+ guint32 prefix = nm_ip4_address_get_prefix (addr);
+ char *tmp2;
+
+ tmp = ip4_address_as_string (nm_ip4_address_get_address (addr));
+ print_table_line (2, _("Address"), 23, tmp, 0, NULL);
+ g_free (tmp);
+
+ tmp2 = ip4_address_as_string (nm_utils_ip4_prefix_to_netmask (prefix));
+ tmp = g_strdup_printf ("%d (%s)", prefix, tmp2);
+ g_free (tmp2);
+ print_table_line (2, _("Prefix"), 23, tmp, 0, NULL);
+ g_free (tmp);
+
+ tmp = ip4_address_as_string (nm_ip4_address_get_gateway (addr));
+ print_table_line (2, _("Gateway"), 23, tmp, 0, NULL);
+ g_free (tmp);
+ printf ("\n");
+ }
+
+ array = nm_ip4_config_get_nameservers (cfg);
+ if (array) {
+ int i;
+
+ for (i = 0; i < array->len; i++) {
+ tmp = ip4_address_as_string (g_array_index (array, guint32, i));
+ print_table_line (2, _("DNS"), 23, tmp, 0, NULL);
+ g_free (tmp);
+ }
+ }
+ }
+
+ printf ("\n\n");
+}
+
+static void
+show_device_status (NMDevice *device, NmCli *nmc)
+{
+ const char *iface;
+ const char *type;
+ const char *state;
+
+ iface = nm_device_get_iface (device);
+ type = get_device_type (device);
+ state = device_state_to_string (nm_device_get_state (device));
+
+ print_table_line (0, iface, 10, type, 17, state, 0, NULL);
+}
+
+static NMCResultCode
+do_devices_status (NmCli *nmc, int argc, char **argv)
+{
+ const GPtrArray *devices;
+ int i;
+
+ while (argc > 0) {
+ fprintf (stderr, _("Unknown parameter: %s\n"), *argv);
+ argc--;
+ argv++;
+ }
+
+ /* create NMClient */
+ if (!nmc->get_client (nmc))
+ goto error;
+
+ devices = nm_client_get_devices (nmc->client);
+
+ if (nmc->print_output == NMC_PRINT_PRETTY)
+ print_table_header (_("Status of devices"), _("Device"), 10, _("Type"), 17, _("State"), 12, NULL);
+ else if (nmc->print_output == NMC_PRINT_NORMAL)
+ print_table_line (0, _("Device"), 10, _("Type"), 17, _("State"), 0, NULL);
+
+ for (i = 0; devices && (i < devices->len); i++) {
+ NMDevice *device = g_ptr_array_index (devices, i);
+ show_device_status (device, nmc);
+ }
+
+ return NMC_RESULT_SUCCESS;
+
+error:
+ return nmc->return_value;
+}
+
+static NMCResultCode
+do_devices_list (NmCli *nmc, int argc, char **argv)
+{
+ const GPtrArray *devices;
+ NMDevice *device = NULL;
+ const char *iface = NULL;
+ gboolean iface_specified = FALSE;
+ int i;
+
+ while (argc > 0) {
+ if (strcmp (*argv, "iface") == 0) {
+ iface_specified = TRUE;
+
+ if (next_arg (&argc, &argv) != 0) {
+ g_string_printf (nmc->return_text, _("Error: '%s' argument is missing."), *argv);
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ goto error;
+ }
+
+ iface = *argv;
+ } else {
+ fprintf (stderr, _("Unknown parameter: %s\n"), *argv);
+ }
+
+ argc--;
+ argv++;
+ }
+
+ /* create NMClient */
+ if (!nmc->get_client (nmc))
+ goto error;
+
+ devices = nm_client_get_devices (nmc->client);
+
+ if (iface_specified) {
+ for (i = 0; devices && (i < devices->len); i++) {
+ NMDevice *candidate = g_ptr_array_index (devices, i);
+ const char *dev_iface = nm_device_get_iface (candidate);
+
+ if (!strcmp (dev_iface, iface))
+ device = candidate;
+ }
+ if (!device) {
+ g_string_printf (nmc->return_text, _("Error: Device '%s' not found."), iface);
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ goto error;
+ }
+ show_device_info (device, nmc->client);
+ } else {
+ if (devices)
+ g_ptr_array_foreach ((GPtrArray *) devices, show_device_info, nmc->client);
+ }
+
+error:
+ return nmc->return_value;
+}
+
+static void
+device_state_cb (NMDevice *device, GParamSpec *pspec, gpointer user_data)
+{
+ NmCli *nmc = (NmCli *) user_data;
+ NMDeviceState state;
+
+ state = nm_device_get_state (device);
+
+ if (state == NM_DEVICE_STATE_DISCONNECTED) {
+ g_string_printf (nmc->return_text, _("Success: Device '%s' successfully disconnected."), nm_device_get_iface (device));
+ quit ();
+ }
+}
+
+static gboolean
+timeout_cb (gpointer user_data)
+{
+ /* Time expired -> exit nmcli */
+
+ NmCli *nmc = (NmCli *) user_data;
+
+ g_string_printf (nmc->return_text, _("Error: Timeout %d sec expired."), nmc->timeout);
+ nmc->return_value = NMC_RESULT_ERROR_TIMEOUT_EXPIRED;
+ quit ();
+ return FALSE;
+}
+
+static void
+disconnect_device_cb (NMDevice *device, GError *error, gpointer user_data)
+{
+ NmCli *nmc = (NmCli *) user_data;
+ NMDeviceState state;
+
+ if (error) {
+ g_string_printf (nmc->return_text, _("Error: Device '%s' (%s) disconnecting failed: %s"),
+ nm_device_get_iface (device),
+ nm_object_get_path (NM_OBJECT (device)),
+ error->message ? error->message : _("(unknown)"));
+ nmc->return_value = NMC_RESULT_ERROR_DEV_DISCONNECT;
+ quit ();
+ } else {
+ state = nm_device_get_state (device);
+ printf (_("Device state: %d (%s)\n"), state, device_state_to_string (state));
+
+ if (!nmc->should_wait || state == NM_DEVICE_STATE_DISCONNECTED) {
+ /* Don't want to wait or device already disconnected */
+ quit ();
+ } else {
+ g_signal_connect (device, "notify::state", G_CALLBACK (device_state_cb), nmc);
+ /* Start timer not to loop forever if "notify::state" signal is not issued */
+ g_timeout_add_seconds (nmc->timeout, timeout_cb, nmc);
+ }
+
+ }
+}
+
+static NMCResultCode
+do_device_disconnect (NmCli *nmc, int argc, char **argv)
+{
+ const GPtrArray *devices;
+ NMDevice *device = NULL;
+ const char *iface = NULL;
+ gboolean iface_specified = FALSE;
+ gboolean wait = TRUE;
+ int i;
+
+ /* Set default timeout for disconnect operation */
+ nmc->timeout = 10;
+
+ while (argc > 0) {
+ if (strcmp (*argv, "iface") == 0) {
+ iface_specified = TRUE;
+
+ if (next_arg (&argc, &argv) != 0) {
+ g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *argv);
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ goto error;
+ }
+
+ iface = *argv;
+ } else if (strcmp (*argv, "--nowait") == 0) {
+ wait = FALSE;
+ } else if (strcmp (*argv, "--timeout") == 0) {
+ if (next_arg (&argc, &argv) != 0) {
+ g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *argv);
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ goto error;
+ }
+
+ errno = 0;
+ nmc->timeout = strtol (*argv, NULL, 10);
+ if (errno || nmc->timeout < 0) {
+ g_string_printf (nmc->return_text, _("Error: timeout value '%s' is not valid."), *argv);
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ goto error;
+ }
+
+ } else {
+ fprintf (stderr, _("Unknown parameter: %s\n"), *argv);
+ }
+
+ argc--;
+ argv++;
+ }
+
+ if (!iface_specified) {
+ g_string_printf (nmc->return_text, _("Error: iface has to be specified."));
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ goto error;
+ }
+
+ /* create NMClient */
+ if (!nmc->get_client (nmc))
+ goto error;
+
+ devices = nm_client_get_devices (nmc->client);
+ for (i = 0; devices && (i < devices->len); i++) {
+ NMDevice *candidate = g_ptr_array_index (devices, i);
+ const char *dev_iface = nm_device_get_iface (candidate);
+
+ if (!strcmp (dev_iface, iface))
+ device = candidate;
+ }
+
+ if (!device) {
+ g_string_printf (nmc->return_text, _("Error: Device '%s' not found."), iface);
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ goto error;
+ }
+
+ nmc->should_wait = wait;
+ nm_device_disconnect (device, disconnect_device_cb, nmc);
+
+error:
+ return nmc->return_value;
+}
+
+static void
+show_acces_point_info (NMDevice *device)
+{
+ NMAccessPoint *active_ap = NULL;
+ const char *active_bssid = NULL;
+ const GPtrArray *aps;
+
+ if (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED) {
+ active_ap = nm_device_wifi_get_active_access_point (NM_DEVICE_WIFI (device));
+ active_bssid = active_ap ? nm_access_point_get_hw_address (active_ap) : NULL;
+ }
+
+ aps = nm_device_wifi_get_access_points (NM_DEVICE_WIFI (device));
+ if (aps && aps->len)
+ g_ptr_array_foreach ((GPtrArray *) aps, detail_access_point, (gpointer) active_bssid);
+}
+
+static NMCResultCode
+do_device_wifi_list (NmCli *nmc, int argc, char **argv)
+{
+ //TODO: cleanup
+ const GPtrArray *devices;
+ NMDevice *device = NULL;
+ const char *iface = NULL;
+ gboolean iface_specified = FALSE;
+ int i;
+
+ while (argc > 0) {
+ if (strcmp (*argv, "iface") == 0) {
+ iface_specified = TRUE;
+
+ if (next_arg (&argc, &argv) != 0) {
+ g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *argv);
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ goto error;
+ }
+
+ iface = *argv;
+ } else {
+ fprintf (stderr, _("Unknown parameter: %s\n"), *argv);
+ }
+
+ argc--;
+ argv++;
+ }
+
+ /* create NMClient */
+ if (!nmc->get_client (nmc))
+ goto error;
+
+ devices = nm_client_get_devices (nmc->client);
+
+ if (iface_specified) {
+ for (i = 0; devices && (i < devices->len); i++) {
+ NMDevice *candidate = g_ptr_array_index (devices, i);
+ const char *dev_iface = nm_device_get_iface (candidate);
+
+ if (!strcmp (dev_iface, iface))
+ device = candidate;
+ }
+
+ if (!device) {
+ g_string_printf (nmc->return_text, _("Error: Device '%s' not found."), iface);
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ goto error;
+ }
+
+ if ((NM_IS_DEVICE_WIFI (device))) {
+ if (nmc->print_output == NMC_PRINT_PRETTY)
+ print_table_header (_("WiFi scan list"), NULL);
+
+ show_acces_point_info (device);
+ } else {
+ g_string_printf (nmc->return_text, _("Error: Device '%s' is not a WiFi device."), iface);
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ goto error;
+ }
+ } else {
+ if (nmc->print_output == NMC_PRINT_PRETTY)
+ print_table_header (_("WiFi scan list"), NULL);
+
+ for (i = 0; devices && (i < devices->len); i++) {
+ NMDevice *dev = g_ptr_array_index (devices, i);
+ const char *dev_iface = nm_device_get_iface (dev);
+
+ if ((NM_IS_DEVICE_WIFI (dev))) {
+ if (nmc->print_output > NMC_PRINT_TERSE)
+ print_table_line (0, _("Device:"), 0, dev_iface, 0, NULL);
+
+ show_acces_point_info (dev);
+ }
+ }
+ }
+
+error:
+ return nmc->return_value;
+}
+
+static NMCResultCode
+do_device_wifi_apinfo (NmCli *nmc, int argc, char **argv)
+{
+ const GPtrArray *devices;
+ const GPtrArray *aps;
+ NMAccessPoint *ap = NULL;
+ const char *iface = NULL;
+ const char *hwaddr_user = NULL;
+ const char *hwaddr;
+ gboolean stop = FALSE;
+ guint32 flags, wpa_flags, rsn_flags, freq, bitrate;
+ guint8 strength;
+ const GByteArray *ssid;
+ NM80211Mode mode;
+ char *freq_str, *ssid_str, *bitrate_str, *strength_str, *wpa_flags_str, *rsn_flags_str;
+ int i, j;
+
+ while (argc > 0) {
+ if (strcmp (*argv, "iface") == 0) {
+ if (next_arg (&argc, &argv) != 0) {
+ g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *argv);
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ goto error;
+ }
+ iface = *argv;
+ } else if (strcmp (*argv, "hwaddr") == 0) {
+ if (next_arg (&argc, &argv) != 0) {
+ g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *argv);
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ goto error;
+ }
+ hwaddr_user = *argv;
+ } else {
+ fprintf (stderr, _("Unknown parameter: %s\n"), *argv);
+ }
+
+ argc--;
+ argv++;
+ }
+
+ if (!hwaddr_user) {
+ g_string_printf (nmc->return_text, _("Error: hwaddr has to be specified."));
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ goto error;
+ }
+
+ /* create NMClient */
+ if (!nmc->get_client (nmc))
+ goto error;
+
+ devices = nm_client_get_devices (nmc->client);
+
+ for (i = 0; !stop && devices && (i < devices->len); i++) {
+ NMDevice *device = g_ptr_array_index (devices, i);
+ const char *dev_iface = nm_device_get_iface (device);
+
+ if (iface) {
+ if (!strcmp (iface, dev_iface))
+ stop = TRUE;
+ else
+ continue;
+ }
+
+ aps = NULL;
+ if ((NM_IS_DEVICE_WIFI (device)))
+ aps = nm_device_wifi_get_access_points (NM_DEVICE_WIFI (device));
+ for (j = 0; aps && (j < aps->len); j++) {
+ char *hwaddr_up;
+ NMAccessPoint *candidate_ap = g_ptr_array_index (aps, j);
+ const char *candidate_hwaddr = nm_access_point_get_hw_address (candidate_ap);
+
+ hwaddr_up = g_ascii_strup (hwaddr_user, -1);
+ if (!strcmp (hwaddr_up, candidate_hwaddr))
+ ap = candidate_ap;
+ g_free (hwaddr_up);
+ }
+ }
+
+ if (!ap) {
+ g_string_printf (nmc->return_text, _("Error: Access point with hwaddr '%s' not found."), hwaddr_user);
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ goto error;
+ }
+
+ /* get AP properties */
+ flags = nm_access_point_get_flags (ap);
+ wpa_flags = nm_access_point_get_wpa_flags (ap);
+ rsn_flags = nm_access_point_get_rsn_flags (ap);
+ ssid = nm_access_point_get_ssid (ap);
+ hwaddr = nm_access_point_get_hw_address (ap);
+ freq = nm_access_point_get_frequency (ap);
+ mode = nm_access_point_get_mode (ap);
+ bitrate = nm_access_point_get_max_bitrate (ap);
+ strength = nm_access_point_get_strength (ap);
+
+ /* print them */
+ ssid_str = g_strdup_printf ("%s", ssid ? nm_utils_escape_ssid (ssid->data, ssid->len) : _("(none)"));
+ freq_str = g_strdup_printf (_("%u MHz"), freq);
+ bitrate_str = g_strdup_printf (_("%u MB/s"), bitrate/1000);
+ strength_str = g_strdup_printf ("%u", strength);
+ wpa_flags_str = ap_wpa_rsn_flags_to_string (wpa_flags);
+ rsn_flags_str = ap_wpa_rsn_flags_to_string (rsn_flags);
+
+ if (nmc->print_output == NMC_PRINT_PRETTY)
+ print_table_header (_("AP parameters"), NULL);
+ else if (nmc->print_output == NMC_PRINT_NORMAL)
+ print_table_line (0, _("AP parameters"), 0, NULL);
+
+ print_table_line (0, _("SSID:"), 25, ssid_str, 0, NULL);
+ print_table_line (0, _("BSSID:"), 25, hwaddr, 0, NULL);
+ print_table_line (0, _("Frequency:"), 25, freq_str, 0, NULL);
+ print_table_line (0, _("Mode:"), 25, mode == NM_802_11_MODE_ADHOC ? _("Ad-hoc") : mode == NM_802_11_MODE_INFRA ? _("Infrastructure") : _("Unknown"), 0, NULL);
+ print_table_line (0, _("Maximal bitrate:"), 25, bitrate_str, 0, NULL);
+ print_table_line (0, _("Strength:"), 25, strength_str, 0, NULL);
+ print_table_line (0, _("Flags:"), 25, flags == NM_802_11_AP_FLAGS_PRIVACY ? _("privacy") : _("(none)"), 0, NULL);
+ print_table_line (0, _("WPA flags:"), 25, wpa_flags_str, 0, NULL);
+ print_table_line (0, _("RSN flags:"), 25, rsn_flags_str, 0, NULL);
+
+ g_free (ssid_str);
+ g_free (freq_str);
+ g_free (bitrate_str);
+ g_free (strength_str);
+ g_free (wpa_flags_str);
+ g_free (rsn_flags_str);
+
+error:
+ return nmc->return_value;
+}
+
+static NMCResultCode
+do_device_wifi (NmCli *nmc, int argc, char **argv)
+{
+ if (argc == 0)
+ nmc->return_value = do_device_wifi_list (nmc, argc-1, argv+1);
+ else if (argc > 0) {
+ if (matches (*argv, "list") == 0) {
+ nmc->return_value = do_device_wifi_list (nmc, argc-1, argv+1);
+ }
+ else if (matches (*argv, "apinfo") == 0) {
+ nmc->return_value = do_device_wifi_apinfo (nmc, argc-1, argv+1);
+ }
+ else {
+ g_string_printf (nmc->return_text, _("Error: 'dev wifi' command '%s' is not valid."), *argv);
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ }
+ }
+
+ return nmc->return_value;
+}
+
+
+NMCResultCode
+do_devices (NmCli *nmc, int argc, char **argv)
+{
+ /* create NMClient */
+ if (!nmc->get_client (nmc))
+ goto error;
+
+ if (argc == 0)
+ nmc->return_value = do_devices_status (nmc, argc-1, argv+1);
+
+ if (argc > 0) {
+ if (matches (*argv, "status") == 0) {
+ nmc->return_value = do_devices_status (nmc, argc-1, argv+1);
+ }
+ else if (matches (*argv, "list") == 0) {
+ nmc->return_value = do_devices_list (nmc, argc-1, argv+1);
+ }
+ else if (matches (*argv, "disconnect") == 0) {
+ nmc->return_value = do_device_disconnect (nmc, argc-1, argv+1);
+ }
+ else if (matches (*argv, "wifi") == 0) {
+ nmc->return_value = do_device_wifi (nmc, argc-1, argv+1);
+ }
+ else if (strcmp (*argv, "help") == 0) {
+ usage ();
+ }
+ else {
+ g_string_printf (nmc->return_text, _("Error: 'dev' command '%s' is not valid."), *argv);
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ }
+ }
+
+error:
+ return nmc->return_value;
+}
diff --git a/cli/src/devices.h b/cli/src/devices.h
new file mode 100644
index 0000000..152dd20
--- a/dev/null
+++ b/cli/src/devices.h
@@ -0,0 +1,27 @@
+/* nmcli - command-line tool to control NetworkManager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2010 Red Hat, Inc.
+ */
+
+#ifndef NMC_DEVICES_H
+#define NMC_DEVICES_H
+
+#include "nmcli.h"
+
+NMCResultCode do_devices (NmCli *nmc, int argc, char **argv);
+
+#endif /* NMC_DEVICES_H */
diff --git a/cli/src/network-manager.c b/cli/src/network-manager.c
new file mode 100644
index 0000000..b5c3bd5
--- a/dev/null
+++ b/cli/src/network-manager.c
@@ -0,0 +1,186 @@
+/* nmcli - command-line tool to control NetworkManager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2010 Red Hat, Inc.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <nm-client.h>
+#include <nm-setting-connection.h>
+
+#include "utils.h"
+#include "network-manager.h"
+
+
+extern GMainLoop *loop;
+
+/* static function prototypes */
+static void usage (void);
+static void quit (void);
+static const char *nm_state_to_string (NMState state);
+static NMCResultCode show_nm_status (NmCli *nmc);
+
+
+static void
+usage (void)
+{
+ fprintf (stderr,
+ _("Usage: nmcli nm { COMMAND | help }\n\n"
+ " COMMAND := { status | sleep | wakeup | wifi | wwan }\n\n"
+ " status\n"
+ " sleep\n"
+ " wakeup\n"
+ " wifi [on|off]\n"
+ " wwan [on|off]\n\n"));
+}
+
+/* quit main loop */
+static void
+quit (void)
+{
+ g_main_loop_quit (loop); /* quit main loop */
+}
+
+static const char *
+nm_state_to_string (NMState state)
+{
+ switch (state) {
+ case NM_STATE_ASLEEP:
+ return _("asleep");
+ case NM_STATE_CONNECTING:
+ return _("connecting");
+ case NM_STATE_CONNECTED:
+ return _("connected");
+ case NM_STATE_DISCONNECTED:
+ return _("disconnected");
+ case NM_STATE_UNKNOWN:
+ default:
+ return _("unknown");
+ }
+}
+
+static NMCResultCode
+show_nm_status (NmCli *nmc)
+{
+ gboolean nm_running;
+ NMState state;
+ const char *wireless_hw_enabled_str, *wireless_enabled_str;
+ const char *wwan_hw_enabled_str, *wwan_enabled_str;
+
+ g_return_val_if_fail (nmc->client != NULL, NMC_RESULT_ERROR_UNKNOWN);
+
+ nm_running = nm_client_get_manager_running (nmc->client);
+ state = nm_client_get_state (nmc->client);
+ if (nm_running) {
+ wireless_hw_enabled_str = nm_client_wireless_hardware_get_enabled (nmc->client) ? _("enabled") : _("disabled");
+ wireless_enabled_str = nm_client_wireless_get_enabled (nmc->client) ? _("enabled") : _("disabled");
+ wwan_hw_enabled_str = nm_client_wwan_hardware_get_enabled (nmc->client) ? _("enabled") : _("disabled");
+ wwan_enabled_str = nm_client_wwan_get_enabled (nmc->client) ? _("enabled") : _("disabled");
+ } else {
+ wireless_hw_enabled_str = wireless_enabled_str = wwan_hw_enabled_str = wwan_enabled_str = _("unknown");
+ }
+
+ if (nmc->print_output == NMC_PRINT_PRETTY)
+ print_table_header (_("NetworkManager status"), NULL);
+
+ print_table_line (0, _("NM running:"), 25, nm_running ? _("running") : _("not running"), 0, NULL);
+ print_table_line (0, _("NM state:"), 25, nm_state_to_string (state), 0, NULL);
+ print_table_line (0, _("NM wireless hardware:"), 25, wireless_hw_enabled_str, 0, NULL);
+ print_table_line (0, _("NM wireless:"), 25, wireless_enabled_str, 0, NULL);
+ print_table_line (0, _("NM WWAN hardware:"), 25, wwan_hw_enabled_str, 0, NULL);
+ print_table_line (0, _("NM WWAN:"), 25, wwan_enabled_str, 0, NULL);
+
+ return NMC_RESULT_SUCCESS;
+}
+
+
+/* entry point function for global network manager related commands 'nmcli nm' */
+NMCResultCode
+do_network_manager (NmCli *nmc, int argc, char **argv)
+{
+ gboolean enable_wifi;
+ gboolean enable_wwan;
+
+ /* create NMClient */
+ if (!nmc->get_client (nmc))
+ goto end;
+
+ if (argc == 0) {
+ nmc->return_value = show_nm_status (nmc);
+ }
+
+ if (argc > 0) {
+ if (matches (*argv, "status") == 0) {
+ nmc->return_value = show_nm_status (nmc);
+ }
+ else if (matches (*argv, "sleep") == 0) {
+ nm_client_sleep (nmc->client, TRUE);
+ }
+ else if (matches (*argv, "wakeup") == 0) {
+ nm_client_sleep (nmc->client, FALSE);
+ }
+ else if (matches (*argv, "wifi") == 0) {
+ if (next_arg (&argc, &argv) != 0) {
+ /* no argument, show current state */
+ print_table_line (0, _("NM wireless:"), 25, nm_client_wireless_get_enabled (nmc->client) ? _("enabled") : _("disabled"), 0, NULL);
+ } else {
+ if (!strcmp (*argv, "on"))
+ enable_wifi = TRUE;
+ else if (!strcmp (*argv, "off"))
+ enable_wifi = FALSE;
+ else {
+ g_string_printf (nmc->return_text, _("Error: invalid 'wifi' parameter: '%s'."), *argv);
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ goto end;
+ }
+ nm_client_wireless_set_enabled (nmc->client, enable_wifi);
+ }
+ }
+ else if (matches (*argv, "wwan") == 0) {
+ if (next_arg (&argc, &argv) != 0) {
+ /* no argument, show current state */
+ print_table_line (0, _("NM WWAN:"), 25, nm_client_wwan_get_enabled (nmc->client) ? _("enabled") : _("disabled"), 0, NULL);
+ } else {
+ if (!strcmp (*argv, "on"))
+ enable_wwan = TRUE;
+ else if (!strcmp (*argv, "off"))
+ enable_wwan = FALSE;
+ else {
+ g_string_printf (nmc->return_text, _("Error: invalid 'wwan' parameter: '%s'."), *argv);
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ goto end;
+ }
+ nm_client_wwan_set_enabled (nmc->client, enable_wwan);
+ }
+ }
+ else if (strcmp (*argv, "help") == 0) {
+ usage ();
+ }
+ else {
+ g_string_printf (nmc->return_text, _("Error: 'nm' command '%s' is not valid."), *argv);
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ }
+ }
+
+end:
+ quit ();
+ return nmc->return_value;
+}
diff --git a/cli/src/network-manager.h b/cli/src/network-manager.h
new file mode 100644
index 0000000..93cc1b0
--- a/dev/null
+++ b/cli/src/network-manager.h
@@ -0,0 +1,27 @@
+/* nmcli - command-line tool to control NetworkManager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2010 Red Hat, Inc.
+ */
+
+#ifndef NMC_NETWORK_MANAGER_H
+#define NMC_NETWORK_MANAGER_H
+
+#include "nmcli.h"
+
+NMCResultCode do_network_manager (NmCli *nmc, int argc, char **argv);
+
+#endif /* NMC_NETWORK_MANAGER_H */
diff --git a/cli/src/nmcli.c b/cli/src/nmcli.c
new file mode 100644
index 0000000..f2ed715
--- a/dev/null
+++ b/cli/src/nmcli.c
@@ -0,0 +1,283 @@
+/* nmcli - command-line tool to control NetworkManager
+ *
+ * Jiri Klimes <jklimes@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2010 Red Hat, Inc.
+ */
+
+/* Generated configuration file */
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <locale.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+#include <nm-client.h>
+#include <nm-setting-connection.h>
+#include <nm-remote-settings.h>
+#include <nm-remote-settings-system.h>
+#include <nm-settings-interface.h>
+#include <nm-settings-connection-interface.h>
+
+#include "nmcli.h"
+#include "utils.h"
+#include "connections.h"
+#include "devices.h"
+#include "network-manager.h"
+
+#define NMCLI_VERSION "0.1"
+
+
+typedef struct {
+ NmCli *nmc;
+ int argc;
+ char **argv;
+} ArgsInfo;
+
+/* --- Global variables --- */
+GMainLoop *loop = NULL;
+
+
+static void
+usage (const char *prog_name)
+{
+ fprintf (stderr,
+ _("Usage: %s [OPTIONS] OBJECT { COMMAND | help }\n\n"
+ "OPTIONS\n"
+ " -t[erse] terse output\n"
+ " -p[retty] pretty output\n"
+ " -v[ersion] show program version\n"
+ " -h[elp] print this help\n\n"
+ "OBJECT\n"
+ " nm NetworkManager status\n"
+ " con NetworkManager connections\n"
+ " dev devices managed by NetworkManager\n\n"),
+ prog_name);
+}
+
+static NMCResultCode
+do_help (NmCli *nmc, int argc, char **argv)
+{
+ usage ("nmcli");
+ return NMC_RESULT_SUCCESS;
+}
+
+static const struct cmd {
+ const char *cmd;
+ NMCResultCode (*func) (NmCli *nmc, int argc, char **argv);
+} nmcli_cmds[] = {
+ { "nm", do_network_manager },
+ { "con", do_connections },
+ { "dev", do_devices },
+ { "help", do_help },
+ { 0 }
+};
+
+static NMCResultCode
+do_cmd (NmCli *nmc, const char *argv0, int argc, char **argv)
+{
+ const struct cmd *c;
+
+ for (c = nmcli_cmds; c->cmd; ++c) {
+ if (matches (argv0, c->cmd) == 0)
+ return c->func (nmc, argc-1, argv+1);
+ }
+
+ g_string_printf (nmc->return_text, _("Object '%s' is unknown, try 'nmcli help'."), argv0);
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ return nmc->return_value;
+}
+
+static NMCResultCode
+parse_command_line (NmCli *nmc, int argc, char **argv)
+{
+ char *base;
+
+ base = strrchr (argv[0], '/');
+ if (base == NULL)
+ base = argv[0];
+ else
+ base++;
+
+ /* parse options */
+ while (argc > 1) {
+ char *opt = argv[1];
+ /* '--' ends options */
+ if (strcmp (opt, "--") == 0) {
+ argc--; argv++;
+ break;
+ }
+ if (opt[0] != '-')
+ break;
+ if (opt[1] == '-')
+ opt++;
+ if (matches (opt, "-terse") == 0) {
+ nmc->print_output = NMC_PRINT_TERSE;
+ } else if (matches (opt, "-pretty") == 0) {
+ nmc->print_output = NMC_PRINT_PRETTY;
+ } else if (matches (opt, "-version") == 0) {
+ printf (_("nmcli tool, version %s\n"), NMCLI_VERSION);
+ return NMC_RESULT_SUCCESS;
+ } else if (matches (opt, "-help") == 0) {
+ usage (base);
+ return NMC_RESULT_SUCCESS;
+ } else {
+ g_string_printf (nmc->return_text, _("Option '%s' is unknown, try 'nmcli -help'."), opt);
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ return nmc->return_value;
+ }
+ argc--;
+ argv++;
+ }
+
+ if (argc > 1)
+ return do_cmd (nmc, argv[1], argc-1, argv+1);
+
+ usage (base);
+ return nmc->return_value;
+}
+
+static void
+signal_handler (int signo)
+{
+ if (signo == SIGINT || signo == SIGTERM) {
+ g_message (_("Caught signal %d, shutting down..."), signo);
+ g_main_loop_quit (loop);
+ }
+}
+
+static void
+setup_signals (void)
+{
+ struct sigaction action;
+ sigset_t mask;
+
+ sigemptyset (&mask);
+ action.sa_handler = signal_handler;
+ action.sa_mask = mask;
+ action.sa_flags = 0;
+ sigaction (SIGTERM, &action, NULL);
+ sigaction (SIGINT, &action, NULL);
+}
+
+static NMClient *
+nmc_get_client (NmCli *nmc)
+{
+ if (!nmc->client) {
+ nmc->client = nm_client_new ();
+ if (!nmc->client) {
+ g_string_printf (nmc->return_text, _("Error: Could not connect to NetworkManager."));
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ }
+ }
+
+ return nmc->client;
+}
+
+/* Initialize NmCli structure - set default values */
+static void
+nmc_init (NmCli *nmc)
+{
+ nmc->client = NULL;
+ nmc->get_client = &nmc_get_client;
+
+ nmc->return_value = NMC_RESULT_SUCCESS;
+ nmc->return_text = g_string_new (_("Success"));
+
+ nmc->timeout = 10;
+
+ nmc->system_settings = NULL;
+ nmc->user_settings = NULL;
+
+ nmc->system_settings_running = FALSE;
+ nmc->user_settings_running = FALSE;
+
+ nmc->system_connections = NULL;
+ nmc->user_connections = NULL;
+
+ nmc->should_wait = FALSE;
+ nmc->print_output = NMC_PRINT_NORMAL;
+}
+
+static void
+nmc_cleanup (NmCli *nmc)
+{
+ if (nmc->client) g_object_unref (nmc->client);
+
+ g_string_free (nmc->return_text, TRUE);
+
+ if (nmc->system_settings) g_object_unref (nmc->system_settings);
+ if (nmc->user_settings) g_object_unref (nmc->user_settings);
+
+ g_slist_free (nmc->system_connections);
+ g_slist_free (nmc->user_connections);
+}
+
+static gboolean
+start (gpointer data)
+{
+ ArgsInfo *info = (ArgsInfo *) data;
+ info->nmc->return_value = parse_command_line (info->nmc, info->argc, info->argv);
+
+ if (!info->nmc->should_wait)
+ g_main_loop_quit (loop);
+
+ return FALSE;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+ NmCli nmc;
+ ArgsInfo args_info = { &nmc, argc, argv };
+
+ /* Set locale to use environment variables */
+ setlocale (LC_ALL, "");
+
+#ifdef GETTEXT_PACKAGE
+ /* Set i18n stuff */
+ bindtextdomain (GETTEXT_PACKAGE, NMCLI_LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+#endif
+
+ g_type_init ();
+
+ nmc_init (&nmc);
+ g_idle_add (start, &args_info);
+
+ loop = g_main_loop_new (NULL, FALSE); /* create main loop */
+ setup_signals (); /* setup UNIX signals */
+ g_main_loop_run (loop); /* run main loop */
+
+ /* Print result descripting text */
+ if (nmc.return_value != NMC_RESULT_SUCCESS) {
+ fprintf (stderr, "%s\n", nmc.return_text->str);
+ }
+
+ g_main_loop_unref (loop);
+ nmc_cleanup (&nmc);
+
+ return nmc.return_value;
+}
diff --git a/cli/src/nmcli.h b/cli/src/nmcli.h
new file mode 100644
index 0000000..2daa415
--- a/dev/null
+++ b/cli/src/nmcli.h
@@ -0,0 +1,77 @@
+/* nmcli - command-line tool to control NetworkManager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2010 Red Hat, Inc.
+ */
+
+#ifndef NMC_NMCLI_H
+#define NMC_NMCLI_H
+
+#include <nm-remote-settings.h>
+#include <nm-remote-settings-system.h>
+
+
+/* nmcli exit codes */
+typedef enum {
+ /* Indicates successful execution */
+ NMC_RESULT_SUCCESS = 0,
+
+ /* Unknown / unspecified error */
+ NMC_RESULT_ERROR_UNKNOWN,
+
+ /* A timeout expired */
+ NMC_RESULT_ERROR_TIMEOUT_EXPIRED,
+
+ /* Error in connection activation */
+ NMC_RESULT_ERROR_CON_ACTIVATION,
+
+ /* Error in connection deactivation */
+ NMC_RESULT_ERROR_CON_DEACTIVATION,
+
+ /* Error in device disconnect */
+ NMC_RESULT_ERROR_DEV_DISCONNECT
+} NMCResultCode;
+
+typedef enum {
+ NMC_PRINT_TERSE = 0,
+ NMC_PRINT_NORMAL,
+ NMC_PRINT_PRETTY
+} NMCPrintOutput;
+
+/* NmCli - main structure */
+typedef struct _NmCli {
+ NMClient *client;
+ NMClient *(*get_client) (struct _NmCli *nmc);
+
+ NMCResultCode return_value;
+ GString *return_text;
+
+ int timeout;
+
+ NMRemoteSettingsSystem *system_settings;
+ NMRemoteSettings *user_settings;
+
+ gboolean system_settings_running;
+ gboolean user_settings_running;
+
+ GSList *system_connections;
+ GSList *user_connections;
+
+ gboolean should_wait;
+ NMCPrintOutput print_output;
+} NmCli;
+
+#endif /* NMC_NMCLI_H */
diff --git a/cli/src/utils.c b/cli/src/utils.c
new file mode 100644
index 0000000..cd99b10
--- a/dev/null
+++ b/cli/src/utils.c
@@ -0,0 +1,126 @@
+/* nmcli - command-line tool to control NetworkManager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2010 Red Hat, Inc.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include "utils.h"
+
+int
+matches (const char *cmd, const char *pattern)
+{
+ int len = strlen (cmd);
+ if (len > strlen (pattern))
+ return -1;
+ return memcmp (pattern, cmd, len);
+}
+
+int
+next_arg (int *argc, char ***argv)
+{
+ if (*argc <= 1) {
+ return -1;
+ }
+ else {
+ (*argc)--;
+ (*argv)++;
+ }
+ return 0;
+}
+
+void
+print_table_header (const char *name, ...)
+{
+ va_list ap;
+ GString *str;
+ char *col, *line = NULL;
+ int col_width, width1, width2, table_width = 0;
+
+ str = g_string_new (NULL);
+
+ va_start (ap, name);
+ while ((col = va_arg (ap, char *)) != NULL) {
+ col_width = va_arg (ap, int);
+ width1 = strlen (col);
+ width2 = g_utf8_strlen (col, -1); /* Width of the string (in screen colums) */
+ g_string_append_printf (str, "%-*s", col_width + width1 - width2, col);
+ g_string_append_c (str, ' '); /* Column separator */
+ table_width += col_width + width1 - width2 + 1;
+ }
+ va_end (ap);
+
+ if (table_width <= 0)
+ table_width = g_utf8_strlen (name, -1) + 4;
+
+ /* Print the table header */
+ line = g_strnfill (table_width, '=');
+ printf ("%s\n", line);
+ width1 = strlen (name);
+ width2 = g_utf8_strlen (name, -1);
+ printf ("%*s\n", (table_width + width2)/2 + width1 - width2, name);
+ printf ("%s\n", line);
+ if (str->len > 0) {
+ g_string_truncate (str, str->len-1); /* Chop off last column separator */
+ printf ("%s\n", str->str);
+ g_free (line);
+ line = g_strnfill (table_width, '-');
+ printf ("%s\n", line);
+ }
+
+ g_free (line);
+ g_string_free (str, TRUE);
+}
+
+void
+print_table_line (int indent, ...)
+{
+ va_list ap;
+ GString *str;
+ char *col, *indent_str;
+ int col_width, width1, width2;
+
+ str = g_string_new (NULL);
+
+ va_start (ap, indent);
+ while ((col = va_arg (ap, char *)) != NULL) {
+ col_width = va_arg (ap, int);
+ width1 = strlen (col);
+ width2 = g_utf8_strlen (col, -1); /* Width of the string (in screen colums) */
+ g_string_append_printf (str, "%-*s", col_width + width1 - width2, col);
+ g_string_append_c (str, ' '); /* Column separator */
+ }
+ va_end (ap);
+
+ /* Print the line */
+ if (str->len > 0)
+ {
+ g_string_truncate (str, str->len-1); /* Chop off last column separator */
+ if (indent > 0) {
+ indent_str = g_strnfill (indent, ' ');
+ g_string_prepend (str, indent_str);
+ g_free (indent_str);
+ }
+ printf ("%s\n", str->str);
+ }
+
+ g_string_free (str, TRUE);
+}
+
diff --git a/cli/src/utils.h b/cli/src/utils.h
new file mode 100644
index 0000000..468550e
--- a/dev/null
+++ b/cli/src/utils.h
@@ -0,0 +1,28 @@
+/* nmcli - command-line tool to control NetworkManager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2010 Red Hat, Inc.
+ */
+
+#ifndef NMC_UTILS_H
+#define NMC_UTILS_H
+
+int matches (const char *cmd, const char *pattern);
+int next_arg (int *argc, char ***argv);
+void print_table_header (const char *name, ...);
+void print_table_line (int indent, ...);
+
+#endif /* NMC_UTILS_H */
diff --git a/configure.ac b/configure.ac
index ecd7085..a31c6c4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -472,6 +472,8 @@ system-settings/plugins/keyfile/Makefile
system-settings/plugins/keyfile/io/Makefile
system-settings/plugins/keyfile/tests/Makefile
system-settings/plugins/keyfile/tests/keyfiles/Makefile
+cli/Makefile
+cli/src/Makefile
test/Makefile
initscript/Makefile
initscript/RedHat/Makefile
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 44235ea..701dc79 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -1,6 +1,11 @@
[encoding: UTF-8]
# List of source files containing translatable strings.
# Please keep this file sorted alphabetically.
+cli/src/connections.c
+cli/src/devices.c
+cli/src/network-manager.c
+cli/src/nmcli.c
+cli/src/utils.c
libnm-util/crypto.c
libnm-util/crypto_gnutls.c
libnm-util/crypto_nss.c