summaryrefslogtreecommitdiff
path: root/src/vinagre/tab.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vinagre/tab.c')
-rw-r--r--src/vinagre/tab.c274
1 files changed, 274 insertions, 0 deletions
diff --git a/src/vinagre/tab.c b/src/vinagre/tab.c
new file mode 100644
index 0000000..ef4e559
--- /dev/null
+++ b/src/vinagre/tab.c
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2009 Jonh Wendell <wendell@bani.com.br>
+ * Copyright (C) 2010 Collabora Ltd.
+ *
+ * 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 St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#include <glib/gi18n.h>
+#include <vte/vte.h>
+#include <gdk/gdkkeysyms.h>
+
+#include <vinagre/vinagre-utils.h>
+#include <vinagre/vinagre-prefs.h>
+
+#include "tab.h"
+#include "connection.h"
+#include "../client-helpers.h"
+#include "../common.h"
+
+struct _SshContactTabPrivate
+{
+ GtkWidget *vte;
+ GSocketConnection *tube_connection;
+ GSocketConnection *ssh_connection;
+};
+
+G_DEFINE_TYPE (SshContactTab, ssh_contact_tab, VINAGRE_TYPE_TAB)
+
+static void
+ssh_disconnected_cb (VteTerminal *ssh,
+ SshContactTab *self)
+{
+ g_signal_emit_by_name (self, "tab-disconnected");
+}
+
+static void
+get_connection_info (SshContactTab *self,
+ const gchar **account_path,
+ const gchar **contact_id,
+ const gchar **username)
+{
+ VinagreConnection *conn;
+
+ conn = vinagre_tab_get_conn (VINAGRE_TAB (self));
+ if (account_path != NULL)
+ *account_path = ssh_contact_connection_get_account_path (SSH_CONTACT_CONNECTION (conn));
+ if (contact_id != NULL)
+ *contact_id = ssh_contact_connection_get_contact_id (SSH_CONTACT_CONNECTION (conn));
+ if (username != NULL)
+ *username = vinagre_connection_get_username (conn);
+}
+
+static gchar *
+impl_get_tooltip (VinagreTab *tab)
+{
+ SshContactTab *self = SSH_CONTACT_TAB (tab);
+ const gchar *account_path;
+ const gchar *contact_id;
+
+ get_connection_info (self, &account_path, &contact_id, NULL);
+
+ return g_markup_printf_escaped (
+ "<b>%s</b> %s\n"
+ "<b>%s</b> %s",
+ _("Account:"), account_path + strlen (TP_ACCOUNT_OBJECT_PATH_BASE),
+ _("Contact:"), contact_id);
+}
+
+static GdkPixbuf *
+impl_get_screenshot (VinagreTab *tab)
+{
+ SshContactTab *self = SSH_CONTACT_TAB (tab);
+ GdkPixbuf *pixbuf;
+ GdkPixmap *pixmap;
+
+ pixmap = gtk_widget_get_snapshot (self->priv->vte, NULL);
+ pixbuf = gdk_pixbuf_get_from_drawable (NULL, GDK_DRAWABLE (pixmap),
+ gdk_colormap_get_system (), 0, 0, 0, 0, -1, -1);
+
+ g_object_unref (pixmap);
+
+ return pixbuf;
+}
+
+static void
+throw_error (SshContactTab *self,
+ const GError *error)
+{
+ g_debug ("ERROR: %s", error->message);
+ g_signal_emit_by_name (self, "tab-auth-failed", error->message);
+}
+
+static void
+splice_cb (GIOStream *stream1,
+ GIOStream *stream2,
+ const GError *error,
+ gpointer user_data)
+{
+ SshContactTab *self = user_data;
+
+ if (error != NULL)
+ throw_error (self, error);
+ else
+ g_signal_emit_by_name (self, "tab-disconnected");
+}
+
+static void
+maybe_start_splice (SshContactTab *self)
+{
+ if (self->priv->tube_connection != NULL && self->priv->ssh_connection != NULL)
+ {
+ g_signal_emit_by_name (self, "tab-connected");
+
+ /* Splice tube and ssh connections */
+ _g_io_stream_splice (G_IO_STREAM (self->priv->tube_connection),
+ G_IO_STREAM (self->priv->ssh_connection), splice_cb, self);
+ }
+}
+
+static void
+ssh_socket_connected_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ SshContactTab *self = user_data;
+ GSocketListener *listener = G_SOCKET_LISTENER (source_object);
+ GError *error = NULL;
+
+ self->priv->ssh_connection = g_socket_listener_accept_finish (listener, res,
+ NULL, &error);
+ if (error != NULL)
+ {
+ throw_error (self, error);
+ g_clear_error (&error);
+ return;
+ }
+
+ maybe_start_splice (self);
+}
+
+static void
+create_tube_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ SshContactTab *self = user_data;
+ GError *error = NULL;
+
+ self->priv->tube_connection = _client_create_tube_finish (res, &error);
+ if (error != NULL)
+ {
+ throw_error (self, error);
+ g_clear_error (&error);
+ return;
+ }
+
+ maybe_start_splice (self);
+}
+
+static gboolean
+start_tube (gpointer user_data)
+{
+ SshContactTab *self = user_data;
+ const gchar *username;
+ const gchar *account_path;
+ const gchar *contact_id;
+ GSocketListener *listener;
+ GSocket *socket;
+ GError *error = NULL;
+ GStrv args = NULL;
+
+ g_signal_emit_by_name (self, "tab-initialized");
+
+ get_connection_info (self, &account_path, &contact_id, &username);
+
+ listener = g_socket_listener_new ();
+ socket = _client_create_local_socket (&error);
+ if (socket == NULL)
+ goto OUT;
+ if (!g_socket_listen (socket, &error))
+ goto OUT;
+ if (!g_socket_listener_add_socket (listener, socket, NULL, &error))
+ goto OUT;
+
+ g_socket_listener_accept_async (listener, NULL,
+ ssh_socket_connected_cb, self);
+
+ args = _client_create_exec_args (socket, contact_id, username);
+ vte_terminal_fork_command (VTE_TERMINAL (self->priv->vte), "ssh", args,
+ NULL, NULL, FALSE, FALSE, FALSE);
+
+ _client_create_tube_async (account_path, contact_id, create_tube_cb, self);
+
+OUT:
+
+ if (error != NULL)
+ throw_error (self, error);
+
+ g_clear_error (&error);
+ tp_clear_object (&listener);
+ tp_clear_object (&socket);
+ g_strfreev (args);
+
+ return FALSE;
+}
+
+static void
+constructed (GObject *object)
+{
+ SshContactTab *self = SSH_CONTACT_TAB (object);
+
+ g_idle_add (start_tube, self);
+
+ vinagre_tab_add_recent_used (VINAGRE_TAB (self));
+ vinagre_tab_set_state (VINAGRE_TAB (self), VINAGRE_TAB_STATE_CONNECTED);
+
+ gtk_widget_show (GTK_WIDGET (self));
+
+ if (G_OBJECT_CLASS (ssh_contact_tab_parent_class)->constructed)
+ G_OBJECT_CLASS (ssh_contact_tab_parent_class)->constructed (object);
+}
+
+static void
+ssh_contact_tab_class_init (SshContactTabClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ VinagreTabClass* tab_class = VINAGRE_TAB_CLASS (klass);
+
+ object_class->constructed = constructed;
+
+ tab_class->impl_get_tooltip = impl_get_tooltip;
+ tab_class->impl_get_screenshot = impl_get_screenshot;
+
+ g_type_class_add_private (klass, sizeof (SshContactTabPrivate));
+
+}
+
+static void
+ssh_contact_tab_init (SshContactTab *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, SSH_CONTACT_TYPE_TAB,
+ SshContactTabPrivate);
+
+ /* Create the ssh widget */
+ self->priv->vte = vte_terminal_new ();
+ vinagre_tab_add_view (VINAGRE_TAB (self), self->priv->vte);
+ gtk_widget_show (self->priv->vte);
+
+ g_signal_connect (self->priv->vte, "child-exited",
+ G_CALLBACK (ssh_disconnected_cb), self);
+}
+
+GtkWidget *
+ssh_contact_tab_new (VinagreConnection *conn,
+ VinagreWindow *window)
+{
+ return g_object_new (SSH_CONTACT_TYPE_TAB, "conn", conn, "window", window,
+ NULL);
+}
+
+/* vim: set ts=8: */