diff options
Diffstat (limited to 'clients/tui/nmtui-connect.c')
| -rw-r--r-- | clients/tui/nmtui-connect.c | 365 |
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 (); +} |