cli: add initial pieces of nmcli
authorJirka Klimes <jklimes@redhat.com>
Thu, 25 Feb 2010 17:52:30 +0000 (09:52 -0800)
committerDan Williams <dcbw@redhat.com>
Thu, 25 Feb 2010 17:52:30 +0000 (09:52 -0800)
16 files changed:
.gitignore
Makefile.am
cli/Makefile.am [new file with mode: 0644]
cli/src/Makefile.am [new file with mode: 0644]
cli/src/connections.c [new file with mode: 0644]
cli/src/connections.h [new file with mode: 0644]
cli/src/devices.c [new file with mode: 0644]
cli/src/devices.h [new file with mode: 0644]
cli/src/network-manager.c [new file with mode: 0644]
cli/src/network-manager.h [new file with mode: 0644]
cli/src/nmcli.c [new file with mode: 0644]
cli/src/nmcli.h [new file with mode: 0644]
cli/src/utils.c [new file with mode: 0644]
cli/src/utils.h [new file with mode: 0644]
configure.ac
po/POTFILES.in

index 6a9d0a6..b4652f6 100644 (file)
@@ -72,3 +72,4 @@ m4/lt*.m4
 
 policy/org.freedesktop.network-manager-settings.system.policy
 
+cli/src/nmcli
index ca819b4..7e34571 100644 (file)
@@ -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 (file)
index 0000000..f268924
--- /dev/null
@@ -0,0 +1,2 @@
+SUBDIRS = src
+
diff --git a/cli/src/Makefile.am b/cli/src/Makefile.am
new file mode 100644 (file)
index 0000000..2a1bd12
--- /dev/null
@@ -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 (file)
index 0000000..ae09fe0
--- /dev/null
@@ -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 (file)
index 0000000..a1ed1c1
--- /dev/null
@@ -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 (file)
index 0000000..d6c0b43
--- /dev/null
@@ -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 (file)
index 0000000..152dd20
--- /dev/null
@@ -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 (file)
index 0000000..b5c3bd5
--- /dev/null
@@ -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 (file)
index 0000000..93cc1b0
--- /dev/null
@@ -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 (file)
index 0000000..f2ed715
--- /dev/null
@@ -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 (file)
index 0000000..2daa415
--- /dev/null
@@ -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 (file)
index 0000000..cd99b10
--- /dev/null
@@ -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 (file)
index 0000000..468550e
--- /dev/null
@@ -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 */
index ecd7085..a31c6c4 100644 (file)
@@ -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
index 44235ea..701dc79 100644 (file)
@@ -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