about summary refs log tree commit diff
path: root/clients/tui/nmtui-connect.c
diff options
context:
space:
mode:
Diffstat (limited to 'clients/tui/nmtui-connect.c')
-rw-r--r--clients/tui/nmtui-connect.c365
1 files changed, 365 insertions, 0 deletions
diff --git a/clients/tui/nmtui-connect.c b/clients/tui/nmtui-connect.c
new file mode 100644
index 00000000..438915d2
--- /dev/null
+++ b/clients/tui/nmtui-connect.c
@@ -0,0 +1,365 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+/**
+ * SECTION:nmtui-connect
+ * @short_description: nm-applet-like functionality
+ *
+ * nmtui-connect implements activating and deactivating #NMConnections,
+ * including presenting a password dialog if necessary.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+
+#include <glib/gi18n-lib.h>
+
+#include "nmt-newt.h"
+
+#include "nmtui.h"
+#include "nmtui-connect.h"
+#include "nmt-connect-connection-list.h"
+#include "nmt-password-dialog.h"
+#include "nm-secret-agent-simple.h"
+#include "nmt-utils.h"
+
+static void
+secrets_requested (NMSecretAgentSimple *agent,
+                   const char          *request_id,
+                   const char          *title,
+                   const char          *msg,
+                   GPtrArray           *secrets,
+                   gpointer             user_data)
+{
+	NmtNewtForm *form;
+
+	form = nmt_password_dialog_new (request_id, title, msg, secrets);
+	nmt_newt_form_run_sync (form);
+
+	if (nmt_password_dialog_succeeded (NMT_PASSWORD_DIALOG (form)))
+		nm_secret_agent_simple_response (agent, request_id, secrets);
+	else
+		nm_secret_agent_simple_response (agent, request_id, NULL);
+
+	g_object_unref (form);
+}
+
+static void
+connect_cancelled (NmtNewtForm *form,
+                   gpointer     user_data)
+{
+	NmtSyncOp *op = user_data;
+	GError *error = NULL;
+
+	error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED, "Cancelled");
+	nmt_sync_op_complete_boolean (op, FALSE, error);
+	g_clear_error (&error);
+}
+
+static void
+activate_ac_state_changed (GObject    *object,
+                           GParamSpec *pspec,
+                           gpointer    user_data)
+{
+	NmtSyncOp *op = user_data;
+	NMActiveConnectionState state;
+	GError *error = NULL;
+
+	state = nm_active_connection_get_state (NM_ACTIVE_CONNECTION (object));
+	if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATING)
+		return;
+
+	if (state != NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
+		error = g_error_new_literal (NM_CLIENT_ERROR, NM_CLIENT_ERROR_FAILED,
+		                             _("Activation failed"));
+	}
+
+	nmt_sync_op_complete_boolean (op, error == NULL, error);
+	g_clear_error (&error);
+}
+
+static void
+activate_callback (GObject      *client,
+                   GAsyncResult *result,
+                   gpointer      user_data)
+{
+	NmtSyncOp *op = user_data;
+	NMActiveConnection *ac;
+	GError *error = NULL;
+
+	ac = nm_client_activate_connection_finish (NM_CLIENT (client), result, &error);
+	if (error)
+		nmt_sync_op_complete_pointer (op, NULL, error);
+	else
+		nmt_sync_op_complete_pointer (op, ac, NULL);
+}
+
+static void
+add_and_activate_callback (GObject      *client,
+                           GAsyncResult *result,
+                           gpointer      user_data)
+{
+	NmtSyncOp *op = user_data;
+	NMActiveConnection *ac;
+	GError *error = NULL;
+
+	ac = nm_client_add_and_activate_connection_finish (NM_CLIENT (client), result, &error);
+	if (error)
+		nmt_sync_op_complete_pointer (op, NULL, error);
+	else
+		nmt_sync_op_complete_pointer (op, ac, NULL);
+}
+
+static void
+activate_connection (NMConnection *connection,
+                     NMDevice     *device,
+                     NMObject     *specific_object)
+{
+	NmtNewtForm *form;
+	NMSecretAgentOld *agent;
+	NmtNewtWidget *label;
+	NmtSyncOp op;
+	const char *specific_object_path;
+	NMActiveConnection *ac;
+	GError *error = NULL;
+
+	form = g_object_new (NMT_TYPE_NEWT_FORM,
+	                     "escape-exits", TRUE,
+	                     NULL);
+	label = nmt_newt_label_new (_("Connecting..."));
+	nmt_newt_form_set_content (form, label);
+
+	agent = nm_secret_agent_simple_new ("nmtui");
+	if (agent) {
+		if (connection) {
+			nm_secret_agent_simple_enable (NM_SECRET_AGENT_SIMPLE (agent),
+			                               nm_object_get_path (NM_OBJECT (connection)));
+		}
+		g_signal_connect (agent, "request-secrets", G_CALLBACK (secrets_requested), NULL);
+	}
+
+	specific_object_path = specific_object ? nm_object_get_path (specific_object) : NULL;
+
+	/* There's no way to cancel an nm_client_activate_connection() /
+	 * nm_client_add_and_activate_connection() call, so we always let them
+	 * complete, even if the user hits Esc; they shouldn't normally take long
+	 * to complete anyway.
+	 */
+
+	nmt_sync_op_init (&op);
+	if (connection) {
+		nm_client_activate_connection_async (nm_client,
+		                                     connection, device, specific_object_path,
+		                                     NULL, activate_callback, &op);
+	} else {
+		nm_client_add_and_activate_connection_async (nm_client,
+		                                             NULL, device, specific_object_path,
+		                                             NULL, add_and_activate_callback, &op);
+	}
+
+	nmt_newt_form_show (form);
+
+	ac = nmt_sync_op_wait_pointer (&op, &error);
+	if (!ac) {
+		nmt_newt_message_dialog (_("Could not activate connection: %s"), error->message);
+		g_clear_error (&error);
+		goto done;
+	} else if (nm_active_connection_get_state (ac) == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
+		/* Already active */
+		goto done;
+	} else if (!nmt_newt_widget_get_realized (NMT_NEWT_WIDGET (form))) {
+		/* User already hit Esc */
+		goto done;
+	}
+
+	if (!connection) {
+		connection = NM_CONNECTION (nm_active_connection_get_connection (ac));
+		if (connection) {
+			nm_secret_agent_simple_enable (NM_SECRET_AGENT_SIMPLE (agent),
+			                               nm_object_get_path (NM_OBJECT (connection)));
+		}
+	}
+
+	/* Now wait for the connection to actually reach the ACTIVATED state,
+	 * allowing the user to cancel if it takes too long.
+	 */
+
+	nmt_sync_op_init (&op);
+
+	g_signal_connect (form, "quit", G_CALLBACK (connect_cancelled), &op);
+	g_signal_connect (ac, "notify::" NM_ACTIVE_CONNECTION_STATE,
+	                  G_CALLBACK (activate_ac_state_changed), &op);
+
+	if (!nmt_sync_op_wait_boolean (&op, &error)) {
+		if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+			nmt_newt_message_dialog (_("Could not activate connection: %s"), error->message);
+		g_clear_error (&error);
+	}
+
+	g_signal_handlers_disconnect_by_func (form, G_CALLBACK (connect_cancelled), &op);
+	g_signal_handlers_disconnect_by_func (ac, G_CALLBACK (activate_ac_state_changed), &op);
+
+ done:
+	if (nmt_newt_widget_get_realized (NMT_NEWT_WIDGET (form)))
+		nmt_newt_form_quit (form);
+	g_object_unref (form);
+
+	nm_secret_agent_old_unregister (agent, NULL, NULL);
+	g_object_unref (agent);
+}
+
+static void
+listbox_activated (NmtNewtListbox *listbox,
+                   gpointer        user_data)
+{
+	NmtConnectConnectionList *list = NMT_CONNECT_CONNECTION_LIST (listbox);
+	NMConnection *connection;
+	NMDevice *device;
+	NMObject *specific_object;
+	NMActiveConnection *ac;
+
+	if (!nmt_connect_connection_list_get_selection (list,
+	                                                &connection,
+	                                                &device,
+	                                                &specific_object,
+	                                                &ac))
+		return;
+
+	if (ac)
+		nm_client_deactivate_connection (nm_client, ac, NULL, NULL);
+	else
+		activate_connection (connection, device, specific_object);
+}
+
+static void
+activate_clicked (NmtNewtButton *button,
+                  gpointer       listbox)
+{
+	listbox_activated (listbox, NULL);
+}
+
+static void
+listbox_active_changed (GObject    *object,
+                        GParamSpec *pspec,
+                        gpointer    button)
+{
+	NmtConnectConnectionList *list = NMT_CONNECT_CONNECTION_LIST (object);
+	static const char *activate, *deactivate;
+	static int deactivate_padding, activate_padding;
+	NMActiveConnection *ac;
+	gboolean has_selection;
+
+	if (G_UNLIKELY (activate == NULL)) {
+		int activate_width, deactivate_width;
+
+		activate = _("Activate");
+		activate_width = nmt_newt_text_width (activate);
+		deactivate = _("Deactivate");
+		deactivate_width = nmt_newt_text_width (deactivate);
+
+		activate_padding = MAX (0, deactivate_width - activate_width);
+		deactivate_padding = MAX (0, activate_width - deactivate_width);
+	}
+
+	has_selection = nmt_connect_connection_list_get_selection (list, NULL, NULL, NULL, &ac);
+
+	nmt_newt_component_set_sensitive (button, has_selection);
+	if (has_selection && ac) {
+		nmt_newt_button_set_label (button, deactivate);
+		nmt_newt_widget_set_padding (button, 0, 0, deactivate_padding, 0);
+	} else {
+		nmt_newt_button_set_label (button, activate);
+		nmt_newt_widget_set_padding (button, 0, 0, activate_padding, 0);
+	}
+}
+
+static NmtNewtForm *
+nmt_connect_connection_list (void)
+{
+	int screen_width, screen_height;
+	NmtNewtForm *form;
+	NmtNewtWidget *list, *activate, *quit, *bbox, *grid;
+
+	newtGetScreenSize (&screen_width, &screen_height);
+
+	form = g_object_new (NMT_TYPE_NEWT_FORM,
+	                     "y", 2,
+	                     "height", screen_height - 4,
+	                     "escape-exits", TRUE,
+	                     NULL);
+
+	grid = nmt_newt_grid_new ();
+
+	list = nmt_connect_connection_list_new ();
+	nmt_newt_grid_add (NMT_NEWT_GRID (grid), list, 0, 0);
+	nmt_newt_grid_set_flags (NMT_NEWT_GRID (grid), list,
+	                         NMT_NEWT_GRID_FILL_X | NMT_NEWT_GRID_FILL_Y |
+	                         NMT_NEWT_GRID_EXPAND_X | NMT_NEWT_GRID_EXPAND_Y);
+	g_signal_connect (list, "activated", G_CALLBACK (listbox_activated), NULL);
+
+	bbox = nmt_newt_button_box_new (NMT_NEWT_BUTTON_BOX_VERTICAL);
+	nmt_newt_grid_add (NMT_NEWT_GRID (grid), bbox, 1, 0);
+	nmt_newt_widget_set_padding (bbox, 1, 1, 0, 1);
+
+	activate = nmt_newt_button_box_add_start (NMT_NEWT_BUTTON_BOX (bbox), _("Activate"));
+	g_signal_connect (list, "notify::active", G_CALLBACK (listbox_active_changed), activate);
+	listbox_active_changed (G_OBJECT (list), NULL, activate);
+	g_signal_connect (activate, "clicked", G_CALLBACK (activate_clicked), list);
+
+	quit = nmt_newt_button_box_add_end (NMT_NEWT_BUTTON_BOX (bbox), _("Quit"));
+	nmt_newt_widget_set_exit_on_activate (quit, TRUE);
+
+	nmt_newt_form_set_content (form, grid);
+	return form;
+}
+
+static NmtNewtForm *
+nmt_connect_connection (const char *identifier)
+{
+	NmtNewtWidget *list;
+	NMConnection *connection;
+	NMDevice *device;
+	NMObject *specific_object;
+	NMActiveConnection *ac;
+
+	list = nmt_connect_connection_list_new ();
+	if (!nmt_connect_connection_list_get_connection (NMT_CONNECT_CONNECTION_LIST (list),
+	                                                 identifier,
+	                                                 &connection,
+	                                                 &device,
+	                                                 &specific_object,
+	                                                 &ac))
+		nmt_newt_message_dialog (_("No such connection '%s'"), identifier);
+	else if (ac)
+		nmt_newt_message_dialog (_("Connection is already active"));
+	else
+		activate_connection (connection, device, specific_object);
+	g_object_unref (list);
+
+	return NULL;
+}
+
+NmtNewtForm *
+nmtui_connect (int argc, char **argv)
+{
+	if (argc == 2)
+		return nmt_connect_connection (argv[1]);
+	else
+		return nmt_connect_connection_list ();
+}