summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavier Claessens <xclaesse@gmail.com>2010-08-04 12:33:51 (GMT)
committerXavier Claessens <xclaesse@gmail.com>2010-08-10 10:07:53 (GMT)
commit2c2dfdcc5449dedcd8529e3d9d42ddd417cc42bb (patch)
tree6c5e1a55c12ca1946eb9a5c37aa19c902ad928e8
parent758a2df6236d4851c3f03ea4071ec704e3d82302 (diff)
downloadtelepathy-ssh-contact-2c2dfdcc5449dedcd8529e3d9d42ddd417cc42bb.tar.gz
telepathy-ssh-contact-2c2dfdcc5449dedcd8529e3d9d42ddd417cc42bb.tar.xz
Add initial vinagre plugin
-rw-r--r--.gitignore4
-rw-r--r--configure.ac28
-rw-r--r--po/POTFILES.in4
-rw-r--r--src/Makefile.am4
-rw-r--r--src/vinagre/Makefile.am37
-rw-r--r--src/vinagre/connection.c223
-rw-r--r--src/vinagre/connection.h65
-rw-r--r--src/vinagre/plugin.c244
-rw-r--r--src/vinagre/plugin.h58
-rw-r--r--src/vinagre/ssh-contact.vinagre-plugin.desktop.in11
-rw-r--r--src/vinagre/tab.c274
-rw-r--r--src/vinagre/tab.h56
-rw-r--r--src/vinagre/tree-view.c328
-rw-r--r--src/vinagre/tree-view.h61
14 files changed, 1397 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index e19d104..0dd61eb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -39,6 +39,7 @@ m4/ltsugar.m4
m4/ltversion.m4
m4/lt~obsolete.m4
+po/.intltool-merge-cache
po/POTFILES
po/ssh-contact.pot
po/stamp-it
@@ -46,3 +47,6 @@ po/stamp-it
src/ssh-contact
src/ssh-contact-service
src/org.freedesktop.Telepathy.Client.SSHContact.service
+
+src/vinagre/ssh-contact.vinagre-plugin
+
diff --git a/configure.ac b/configure.ac
index 0b20aec..081e94b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -81,9 +81,37 @@ AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE",[Gettext package name])
AM_GLIB_GNU_GETTEXT
# -----------------------------------------------------------
+# Vinagre plugin
+# -----------------------------------------------------------
+AC_ARG_ENABLE(vinagre,
+ AS_HELP_STRING([--enable-vinagre=@<:@no/yes/auto@:>@],
+ [build with vinagre plugin]), ,
+ enable_vinagre=auto)
+
+if test "x$enable_vinagre" != "xno"; then
+ PKG_CHECK_MODULES(VINAGRE,
+ [
+ vinagre-1.0
+ vte
+ ], have_vinagre="yes", have_vinagre="no")
+
+ if test "x$have_vinagre" = "xyes"; then
+ AC_DEFINE(HAVE_VINAGRE, 1, [Define if you have libvinagre])
+ fi
+else
+ have_vinagre=no
+fi
+
+if test "x$enable_vinagre" = "xyes" -a "x$have_vinagre" != "xyes"; then
+ AC_MSG_ERROR([Could not find vinagre dependencies.])
+fi
+AM_CONDITIONAL(HAVE_VINAGRE, test "x$have_vinagre" = "xyes")
+
+# -----------------------------------------------------------
AC_OUTPUT([
Makefile
po/Makefile.in
src/Makefile
+src/vinagre/Makefile
])
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 1cbe438..a3f3fb2 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -1,3 +1,7 @@
# List of source files containing translatable strings.
# Please keep this file sorted alphabetically.
+src/vinagre/plugin.c
+src/vinagre/ssh-contact.vinagre-plugin.desktop.in
+src/vinagre/tab.c
+
diff --git a/src/Makefile.am b/src/Makefile.am
index b3194b0..3492352 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,3 +1,7 @@
+if HAVE_VINAGRE
+SUBDIRS = vinagre
+endif
+
AM_CPPFLAGS = \
$(ERROR_CFLAGS) \
$(SSH_CONTACT_CFLAGS) \
diff --git a/src/vinagre/Makefile.am b/src/vinagre/Makefile.am
new file mode 100644
index 0000000..5845572
--- /dev/null
+++ b/src/vinagre/Makefile.am
@@ -0,0 +1,37 @@
+# ssh plugin
+plugindir = $(libdir)/vinagre-1/plugins
+
+AM_CPPFLAGS = \
+ $(ERROR_CFLAGS) \
+ $(SSH_CONTACT_CFLAGS) \
+ $(VINAGRE_CFLAGS) \
+ $(NULL)
+
+plugin_LTLIBRARIES = libssh-contact.la
+
+libssh_contact_la_LIBADD = \
+ $(SSH_CONTACT_LIBS) \
+ $(VINAGRE_LIBS) \
+ $(NULL)
+
+libssh_contact_la_SOURCES = \
+ plugin.h plugin.c \
+ connection.h connection.c \
+ tab.h tab.c \
+ tree-view.h tree-view.c \
+ ../client-helpers.h ../client-helpers.c \
+ ../common.h ../common.c \
+ $(NULL)
+
+plugin_in_files = ssh-contact.vinagre-plugin.desktop.in
+
+ssh-contact.vinagre-plugin: ssh-contact.vinagre-plugin.desktop.in
+ $(AM_V_GEN) $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c \
+ $(top_builddir)/po/.intltool-merge-cache
+
+plugin_DATA = $(plugin_in_files:.vinagre-plugin.desktop.in=.vinagre-plugin)
+
+EXTRA_DIST = $(plugin_in_files)
+CLEANFILES = $(plugin_DATA)
+DISTCLEANFILES = $(plugin_DATA)
+
diff --git a/src/vinagre/connection.c b/src/vinagre/connection.c
new file mode 100644
index 0000000..05b950c
--- /dev/null
+++ b/src/vinagre/connection.c
@@ -0,0 +1,223 @@
+/*
+ * 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 <vinagre/vinagre-utils.h>
+#include <vinagre/vinagre-cache-prefs.h>
+
+#include <telepathy-glib/telepathy-glib.h>
+
+#include "connection.h"
+#include "tree-view.h"
+
+struct _SshContactConnectionPrivate
+{
+ gchar *account_path;
+ gchar *contact_id;
+};
+
+G_DEFINE_TYPE (SshContactConnection, ssh_contact_connection,
+ VINAGRE_TYPE_CONNECTION);
+
+static void
+impl_fill_writer (VinagreConnection *conn, xmlTextWriter *writer)
+{
+ SshContactConnection *self = SSH_CONTACT_CONNECTION (conn);
+
+ xmlTextWriterWriteElement (writer, (const xmlChar *) "account",
+ (const xmlChar *) (self->priv->account_path ? self->priv->account_path : ""));
+ xmlTextWriterWriteElement (writer, (const xmlChar *) "contact",
+ (const xmlChar *) (self->priv->contact_id ? self->priv->contact_id : ""));
+
+ VINAGRE_CONNECTION_CLASS (ssh_contact_connection_parent_class)->impl_fill_writer (conn, writer);
+}
+
+static void
+impl_parse_item (VinagreConnection *conn, xmlNode *root)
+{
+ SshContactConnection *self = SSH_CONTACT_CONNECTION (conn);
+ xmlNode *curr;
+ xmlChar *s_value;
+
+ for (curr = root->children; curr; curr = curr->next)
+ {
+ s_value = xmlNodeGetContent (curr);
+
+ if (!xmlStrcmp(curr->name, (const xmlChar *)"account"))
+ ssh_contact_connection_set_account_path (self, (gchar *) s_value);
+ else if (!xmlStrcmp(curr->name, (const xmlChar *)"contact"))
+ ssh_contact_connection_set_contact_id (self, (gchar *) s_value);
+
+ xmlFree (s_value);
+ }
+
+ VINAGRE_CONNECTION_CLASS (ssh_contact_connection_parent_class)->impl_parse_item (conn, root);
+}
+
+static void
+impl_parse_options_widget (VinagreConnection *conn,
+ GtkWidget *widget)
+{
+ GtkWidget *entry;
+ const gchar *username;
+
+ entry = g_object_get_data (G_OBJECT (widget), "username_entry");
+ if (entry == NULL)
+ {
+ g_warning ("Wrong widget passed to impl_parse_options_widget()");
+ return;
+ }
+
+ username = gtk_entry_get_text (GTK_ENTRY (entry));
+ vinagre_cache_prefs_set_string ("ssh-contact-connection", "username",
+ username);
+ vinagre_connection_set_username (conn, username);
+
+ VINAGRE_CONNECTION_CLASS (ssh_contact_connection_parent_class)->impl_parse_options_widget (conn, widget);
+}
+
+static void
+impl_parse_host_widget (VinagreConnection *conn,
+ GtkWidget *widget)
+{
+ SshContactConnection *self = SSH_CONTACT_CONNECTION (conn);
+ SshContactTreeView *view;
+ TpAccount *account;
+ TpContact *contact;
+
+ /* widget is a GtkScrolledWindow containing an SshContactTreeView */
+ view = SSH_CONTACT_TREE_VIEW (gtk_bin_get_child (GTK_BIN (widget)));
+
+ account = ssh_contact_tree_view_get_selected_account (view);
+ ssh_contact_connection_set_account_path (self,
+ tp_proxy_get_object_path (account));
+
+ contact = ssh_contact_tree_view_get_selected_contact (view);
+ ssh_contact_connection_set_contact_id (self,
+ tp_contact_get_identifier (contact));
+
+ VINAGRE_CONNECTION_CLASS (ssh_contact_connection_parent_class)->impl_parse_host_widget (conn, widget);
+}
+
+static gchar *
+impl_get_string_rep (VinagreConnection *conn,
+ gboolean has_protocol)
+{
+ SshContactConnection *self = SSH_CONTACT_CONNECTION (conn);
+ GString *uri;
+
+ if (has_protocol)
+ {
+ uri = g_string_new (vinagre_connection_get_protocol (conn));
+ g_string_append (uri, "://");
+ }
+ else
+ {
+ uri = g_string_new (NULL);
+ }
+
+ g_string_append (uri, self->priv->account_path);
+ g_string_append_c (uri, '/');
+ g_string_append (uri, self->priv->contact_id);
+
+ return g_string_free (uri, FALSE);
+}
+
+static void
+finalize (GObject *object)
+{
+ SshContactConnection *self = SSH_CONTACT_CONNECTION (object);
+
+ g_free (self->priv->contact_id);
+ g_free (self->priv->account_path);
+
+ G_OBJECT_CLASS (ssh_contact_connection_parent_class)->finalize (object);
+}
+
+static void
+ssh_contact_connection_init (SshContactConnection *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, SSH_CONTACT_TYPE_CONNECTION,
+ SshContactConnectionPrivate);
+}
+
+static void
+ssh_contact_connection_class_init (SshContactConnectionClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ VinagreConnectionClass* vinagre_class = VINAGRE_CONNECTION_CLASS (klass);
+
+ object_class->finalize = finalize;
+
+ vinagre_class->impl_fill_writer = impl_fill_writer;
+ vinagre_class->impl_parse_item = impl_parse_item;
+ vinagre_class->impl_parse_options_widget = impl_parse_options_widget;
+ vinagre_class->impl_parse_host_widget = impl_parse_host_widget;
+ vinagre_class->impl_get_string_rep = impl_get_string_rep;
+
+ g_type_class_add_private (klass, sizeof (SshContactConnectionPrivate));
+}
+
+VinagreConnection *
+ssh_contact_connection_new (void)
+{
+ return g_object_new (SSH_CONTACT_TYPE_CONNECTION,
+ "protocol", "ssh-contact",
+ NULL);
+}
+
+const gchar *
+ssh_contact_connection_get_account_path (SshContactConnection *self)
+{
+ g_return_val_if_fail (SSH_CONTACT_IS_CONNECTION (self), NULL);
+
+ return self->priv->account_path;
+}
+
+void
+ssh_contact_connection_set_account_path (SshContactConnection *self,
+ const gchar *account_path)
+{
+ g_return_if_fail (SSH_CONTACT_IS_CONNECTION (self));
+
+ g_free (self->priv->account_path);
+ self->priv->account_path = g_strdup (account_path);
+}
+
+const gchar *
+ssh_contact_connection_get_contact_id (SshContactConnection *self)
+{
+ g_return_val_if_fail (SSH_CONTACT_IS_CONNECTION (self), NULL);
+
+ return self->priv->contact_id;
+}
+
+void
+ssh_contact_connection_set_contact_id (SshContactConnection *self,
+ const gchar *contact_id)
+{
+ g_return_if_fail (SSH_CONTACT_IS_CONNECTION (self));
+
+ g_free (self->priv->contact_id);
+ self->priv->contact_id = g_strdup (contact_id);
+}
+
+/* vim: set ts=8: */
diff --git a/src/vinagre/connection.h b/src/vinagre/connection.h
new file mode 100644
index 0000000..7a56947
--- /dev/null
+++ b/src/vinagre/connection.h
@@ -0,0 +1,65 @@
+/*
+ * 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
+ */
+
+#ifndef __SSH_CONTACT_CONNECTION_H__
+#define __SSH_CONTACT_CONNECTION_H__
+
+#include <vinagre/vinagre-connection.h>
+
+G_BEGIN_DECLS
+
+#define SSH_CONTACT_TYPE_CONNECTION (ssh_contact_connection_get_type ())
+#define SSH_CONTACT_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SSH_CONTACT_TYPE_CONNECTION, SshContactConnection))
+#define SSH_CONTACT_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SSH_CONTACT_TYPE_CONNECTION, SshContactConnectionClass))
+#define SSH_CONTACT_IS_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SSH_CONTACT_TYPE_CONNECTION))
+#define SSH_CONTACT_IS_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SSH_CONTACT_TYPE_CONNECTION))
+#define SSH_CONTACT_CONNECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SSH_CONTACT_TYPE_CONNECTION, SshContactConnectionClass))
+
+typedef struct _SshContactConnectionPrivate SshContactConnectionPrivate;
+
+typedef struct
+{
+ VinagreConnection parent_instance;
+ SshContactConnectionPrivate *priv;
+} SshContactConnection;
+
+typedef struct
+{
+ VinagreConnectionClass parent_class;
+} SshContactConnectionClass;
+
+GType ssh_contact_connection_get_type (void) G_GNUC_CONST;
+
+VinagreConnection *ssh_contact_connection_new (void);
+
+const gchar *ssh_contact_connection_get_account_path (SshContactConnection *self);
+
+void ssh_contact_connection_set_account_path (SshContactConnection *self,
+ const gchar *account_path);
+
+const gchar *ssh_contact_connection_get_contact_id (SshContactConnection *self);
+
+void ssh_contact_connection_set_contact_id (SshContactConnection *self,
+ const gchar *contact_id);
+
+G_END_DECLS
+
+#endif /* __SSH_CONTACT_CONNECTION_H__ */
+/* vim: set ts=8: */
diff --git a/src/vinagre/plugin.c b/src/vinagre/plugin.c
new file mode 100644
index 0000000..33be5c9
--- /dev/null
+++ b/src/vinagre/plugin.c
@@ -0,0 +1,244 @@
+/*
+ * 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 "config.h"
+
+#include <glib/gi18n-lib.h>
+#include <gmodule.h>
+
+#include <vinagre/vinagre-debug.h>
+#include <vinagre/vinagre-cache-prefs.h>
+
+#include "plugin.h"
+#include "connection.h"
+#include "tab.h"
+#include "tree-view.h"
+
+VINAGRE_PLUGIN_REGISTER_TYPE (SshContactPlugin, ssh_contact_plugin)
+
+static void
+impl_activate (VinagrePlugin *plugin,
+ VinagreWindow *window)
+{
+ vinagre_debug_message (DEBUG_PLUGINS, "SshContactPlugin Activate");
+}
+
+static void
+impl_deactivate (VinagrePlugin *plugin,
+ VinagreWindow *window)
+{
+ vinagre_debug_message (DEBUG_PLUGINS, "SshContactPlugin Deactivate");
+}
+
+static void
+impl_update_ui (VinagrePlugin *plugin,
+ VinagreWindow *window)
+{
+ vinagre_debug_message (DEBUG_PLUGINS, "SshContactPlugin Update UI");
+}
+
+static const gchar *
+impl_get_protocol (VinagrePlugin *plugin)
+{
+ return "ssh-contact";
+}
+
+static gchar **
+impl_get_public_description (VinagrePlugin *plugin)
+{
+ gchar **result = g_new (gchar *, 3);
+
+ result[0] = g_strdup (_("SSH-Contact"));
+ /* Translators: This is a description of the SSH protocol. It appears at
+ * Connect dialog. */
+ result[1] = g_strdup (_("Access Unix/Linux terminals using a Telepathy Tube"));
+ result[2] = NULL;
+
+ return result;
+}
+
+static const gchar *
+impl_get_mdns_service (VinagrePlugin *plugin)
+{
+ return NULL;
+}
+
+static VinagreConnection *
+impl_new_connection (VinagrePlugin *plugin)
+{
+ return ssh_contact_connection_new ();
+}
+
+static VinagreConnection *
+impl_new_connection_from_string (VinagrePlugin *plugin,
+ const gchar *uri,
+ gchar **error_msg,
+ gboolean use_bookmarks)
+{
+ VinagreConnection *conn = NULL;
+ const gchar *p1 = uri;
+ const gchar *p2;
+ gchar *account_path;
+ gchar *contact_id;
+
+ /* FIXME: Search in bookmarks */
+
+ /* URI is in the form "ssh-contact://<account path>/<contact id>". */
+
+ /* Skip the scheme part */
+ if (!g_str_has_prefix (p1, vinagre_plugin_get_protocol (plugin)))
+ goto OUT;
+ p1 += strlen (vinagre_plugin_get_protocol (plugin));
+ if (!g_str_has_prefix (p1, "://"))
+ goto OUT;
+ p1 += strlen ("://");
+
+ /* Search delimiter between account path and contact id */
+ p2 = g_strrstr (p1, "/");
+ if (p2 == NULL)
+ goto OUT;
+
+ account_path = g_strndup (p1, p2 - p1);
+ contact_id = g_strdup (p2 + 1);
+
+ conn = ssh_contact_connection_new ();
+ ssh_contact_connection_set_account_path (SSH_CONTACT_CONNECTION (conn),
+ account_path);
+ ssh_contact_connection_set_contact_id (SSH_CONTACT_CONNECTION (conn),
+ contact_id);
+
+ g_free (account_path);
+ g_free (contact_id);
+
+OUT:
+
+ if (conn == NULL)
+ *error_msg = g_strdup ("URI format not recognized");
+
+ return conn;
+}
+
+static GtkWidget *
+impl_new_tab (VinagrePlugin *plugin,
+ VinagreConnection *conn,
+ VinagreWindow *window)
+{
+ return ssh_contact_tab_new (conn, window);
+}
+
+static gint
+impl_get_default_port (VinagrePlugin *plugin)
+{
+ return 0;
+}
+
+static GtkWidget *
+impl_get_connect_widget (VinagrePlugin *plugin,
+ VinagreConnection *conn)
+{
+ GtkWidget *box, *label, *u_box, *u_entry;
+ gchar *str;
+
+ box = gtk_vbox_new (FALSE, 0);
+
+ str = g_strdup_printf ("<b>%s</b>", _("SSH Options"));
+ label = gtk_label_new (str);
+ g_free (str);
+ gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
+ gtk_misc_set_padding (GTK_MISC (label), 0, 6);
+ gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
+
+ u_box = gtk_hbox_new (FALSE, 4);
+ label = gtk_label_new (" ");
+ gtk_box_pack_start (GTK_BOX (u_box), label, FALSE, FALSE, 0);
+
+ label = gtk_label_new_with_mnemonic (_("_Username:"));
+ gtk_box_pack_start (GTK_BOX (u_box), label, FALSE, FALSE, 0);
+
+ u_entry = gtk_entry_new ();
+ /* Translators: This is the tooltip for the username field in a SSH
+ * connection */
+ gtk_widget_set_tooltip_text (u_entry,
+ _("Optional. If blank, your username will be used."));
+ g_object_set_data (G_OBJECT (box), "username_entry", u_entry);
+ gtk_box_pack_start (GTK_BOX (u_box), u_entry, TRUE, TRUE, 5);
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), u_entry);
+ str = g_strdup (VINAGRE_IS_CONNECTION (conn) ?
+ vinagre_connection_get_username (conn) :
+ vinagre_cache_prefs_get_string ("ssh-contact-connection", "username", ""));
+ gtk_entry_set_text (GTK_ENTRY (u_entry), str);
+ gtk_entry_set_activates_default (GTK_ENTRY (u_entry), TRUE);
+ g_free (str);
+
+ gtk_box_pack_start (GTK_BOX (box), u_box, TRUE, TRUE, 0);
+
+ return box;
+}
+
+static GtkWidget *
+impl_get_connect_host_widget (VinagrePlugin *plugin,
+ VinagreConnection *conn)
+{
+ GtkWidget *sw;
+ GtkWidget *view;
+
+ view = ssh_contact_tree_view_new ();
+ gtk_widget_show (view);
+
+ sw = gtk_scrolled_window_new (NULL, NULL);
+ gtk_container_add (GTK_CONTAINER (sw), view);
+ gtk_widget_set_size_request (GTK_WIDGET (sw), -1, 150);
+
+ return sw;
+}
+
+static void
+impl_parse_mdns_dialog (VinagrePlugin *plugin,
+ GtkWidget *connect_widget,
+ GtkWidget *dialog)
+{
+}
+
+static void
+ssh_contact_plugin_init (SshContactPlugin *self)
+{
+}
+
+static void
+ssh_contact_plugin_class_init (SshContactPluginClass *klass)
+{
+ VinagrePluginClass *plugin_class = VINAGRE_PLUGIN_CLASS (klass);
+
+ plugin_class->activate = impl_activate;
+ plugin_class->deactivate = impl_deactivate;
+ plugin_class->update_ui = impl_update_ui;
+ plugin_class->get_protocol = impl_get_protocol;
+ plugin_class->get_public_description = impl_get_public_description;
+ plugin_class->new_connection = impl_new_connection;
+ plugin_class->new_connection_from_string = impl_new_connection_from_string;
+ plugin_class->get_mdns_service = impl_get_mdns_service;
+ plugin_class->new_tab = impl_new_tab;
+ plugin_class->get_default_port = impl_get_default_port;
+ plugin_class->get_connect_widget = impl_get_connect_widget;
+ plugin_class->get_connect_host_widget = impl_get_connect_host_widget;
+ plugin_class->parse_mdns_dialog = impl_parse_mdns_dialog;
+}
+/* vim: set ts=8: */
diff --git a/src/vinagre/plugin.h b/src/vinagre/plugin.h
new file mode 100644
index 0000000..50e10b9
--- /dev/null
+++ b/src/vinagre/plugin.h
@@ -0,0 +1,58 @@
+/*
+ * 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
+ */
+
+#ifndef __SSH_CONTACT_PLUGIN_H__
+#define __SSH_CONTACT_PLUGIN_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <vinagre/vinagre-plugin.h>
+
+G_BEGIN_DECLS
+
+#define SSH_CONTACT_TYPE_PLUGIN (ssh_contact_plugin_get_type ())
+#define SSH_CONTACT_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SSH_CONTACT_TYPE_PLUGIN, SshContactPlugin))
+#define SSH_CONTACT_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SSH_CONTACT_TYPE_PLUGIN, SshContactPluginClass))
+#define SSH_CONTACT_IS_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SSH_CONTACT_TYPE_PLUGIN))
+#define SSH_CONTACT_IS_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SSH_CONTACT_TYPE_PLUGIN))
+#define SSH_CONTACT_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), SSH_CONTACT_TYPE_PLUGIN, SshContactPluginClass))
+
+typedef struct _SshContactPluginPrivate SshContactPluginPrivate;
+
+typedef struct
+{
+ VinagrePlugin parent_instance;
+ SshContactPluginPrivate *priv;
+} SshContactPlugin;
+
+typedef struct
+{
+ VinagrePluginClass parent_class;
+} SshContactPluginClass;
+
+GType ssh_contact_plugin_get_type (void) G_GNUC_CONST;
+
+/* All the plugins must implement this function */
+G_MODULE_EXPORT GType register_vinagre_plugin (GTypeModule *module);
+
+G_END_DECLS
+
+#endif /* __SSH_CONTACT_PLUGIN_H__ */
+/* vim: set ts=8: */
diff --git a/src/vinagre/ssh-contact.vinagre-plugin.desktop.in b/src/vinagre/ssh-contact.vinagre-plugin.desktop.in
new file mode 100644
index 0000000..db50f0f
--- /dev/null
+++ b/src/vinagre/ssh-contact.vinagre-plugin.desktop.in
@@ -0,0 +1,11 @@
+[Vinagre Plugin]
+Module=ssh-contact
+IAge=1
+_Name=SSH-Contact
+_Description=SSH-Contact support
+Authors=Xavier Claessens
+Copyright=Copyright © 2010 Collabora Ltd.
+Website=http://telepathy.freedesktop.org/wiki/SSH-Contact
+Version=1.0
+Engine=1
+Icon=utilities-terminal
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: */
diff --git a/src/vinagre/tab.h b/src/vinagre/tab.h
new file mode 100644
index 0000000..8dd889a
--- /dev/null
+++ b/src/vinagre/tab.h
@@ -0,0 +1,56 @@
+/*
+ * 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
+ */
+
+#ifndef __SSH_CONTACT_TAB_H__
+#define __SSH_CONTACT_TAB_H__
+
+#include <vinagre/vinagre-tab.h>
+
+G_BEGIN_DECLS
+
+#define SSH_CONTACT_TYPE_TAB (ssh_contact_tab_get_type())
+#define SSH_CONTACT_TAB(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SSH_CONTACT_TYPE_TAB, SshContactTab))
+#define SSH_CONTACT_TAB_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SSH_CONTACT_TYPE_TAB, SshContactTab const))
+#define SSH_CONTACT_TAB_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SSH_CONTACT_TYPE_TAB, SshContactTabClass))
+#define SSH_CONTACT_IS_TAB(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SSH_CONTACT_TYPE_TAB))
+#define SSH_CONTACT_IS_TAB_CLASS(klass)...(G_TYPE_CHECK_CLASS_TYPE ((klass), SSH_CONTACT_TYPE_TAB))
+#define SSH_CONTACT_TAB_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), SSH_CONTACT_TYPE_TAB, SshContactTabClass))
+
+typedef struct _SshContactTabPrivate SshContactTabPrivate;
+
+typedef struct
+{
+ VinagreTab tab;
+ SshContactTabPrivate *priv;
+} SshContactTab;
+
+typedef struct
+{
+ VinagreTabClass parent_class;
+} SshContactTabClass;
+
+GType ssh_contact_tab_get_type (void) G_GNUC_CONST;
+
+GtkWidget *ssh_contact_tab_new (VinagreConnection *conn, VinagreWindow *window);
+
+G_END_DECLS
+
+#endif /* __VINAGRE_SSH_TAB_H__ */
+/* vim: set ts=8: */
diff --git a/src/vinagre/tree-view.c b/src/vinagre/tree-view.c
new file mode 100644
index 0000000..6ddc91c
--- /dev/null
+++ b/src/vinagre/tree-view.c
@@ -0,0 +1,328 @@
+/*
+ * 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 <gtk/gtk.h>
+
+#include <telepathy-glib/telepathy-glib.h>
+
+#include "tree-view.h"
+#include "../client-helpers.h"
+
+enum
+{
+ COL_ACCOUNT,
+ COL_CONTACT,
+ COL_TEXT,
+ N_COL
+};
+
+struct _SshContactTreeViewPrivate
+{
+ GtkListStore *store;
+ TpAccountManager *account_manager;
+};
+
+G_DEFINE_TYPE (SshContactTreeView, ssh_contact_tree_view,
+ GTK_TYPE_TREE_VIEW);
+
+static TpAccount *
+find_account_for_contact (SshContactTreeView *self,
+ TpContact *contact)
+{
+ TpAccount *account = NULL;
+ TpConnection *connection;
+ GList *list;
+
+ connection = tp_contact_get_connection (contact);
+ list = tp_account_manager_get_valid_accounts (self->priv->account_manager);
+ while (list)
+ {
+ if (tp_account_get_connection (list->data) == connection)
+ {
+ account = list->data;
+ break;
+ }
+
+ list = g_list_delete_link (list, list);
+ }
+ g_list_free (list);
+
+ return account;
+}
+
+static void
+got_contacts_cb (TpConnection *connection,
+ guint n_contacts,
+ TpContact * const *contacts,
+ guint n_failed,
+ const TpHandle *failed,
+ const GError *error,
+ gpointer user_data,
+ GObject *weak_object)
+{
+ SshContactTreeView *self = user_data;
+ guint i;
+
+ if (error != NULL)
+ {
+ g_debug ("%s", error->message);
+ return;
+ }
+
+ for (i = 0; i < n_contacts; i++)
+ {
+ TpAccount *account;
+
+ if (!_capabilities_has_stream_tube (tp_contact_get_capabilities (contacts[i])))
+ continue;
+
+ account = find_account_for_contact (self, contacts[i]);
+ gtk_list_store_insert_with_values (self->priv->store, NULL, -1,
+ COL_ACCOUNT, account,
+ COL_CONTACT, contacts[i],
+ COL_TEXT, tp_contact_get_alias (contacts[i]),
+ -1);
+ }
+}
+
+static void
+stored_channel_prepare_cb (GObject *object,
+ GAsyncResult *res,
+ gpointer self)
+{
+ TpChannel *channel = TP_CHANNEL (object);
+ TpConnection *connection;
+ TpContactFeature features[] = { TP_CONTACT_FEATURE_ALIAS,
+ TP_CONTACT_FEATURE_CAPABILITIES };
+ const TpIntSet *set;
+ GArray *handles;
+ GError *error = NULL;
+
+ if (!tp_proxy_prepare_finish (channel, res, &error))
+ {
+ g_debug ("%s", error->message);
+ g_clear_error (&error);
+ return;
+ }
+
+ connection = tp_channel_borrow_connection (channel);
+ set = tp_channel_group_get_members (channel);
+ handles = tp_intset_to_array (set);
+
+ tp_connection_get_contacts_by_handle (connection, handles->len,
+ (TpHandle *) handles->data, G_N_ELEMENTS (features), features,
+ got_contacts_cb, self, NULL, NULL);
+
+ g_array_unref (handles);
+}
+
+static void
+ensure_stored_channel_cb (TpConnection *connection,
+ gboolean yours,
+ const gchar *channel_path,
+ GHashTable *properties,
+ const GError *error,
+ gpointer self,
+ GObject *weak_object)
+{
+ TpChannel *channel;
+ GQuark features[] = { TP_CHANNEL_FEATURE_GROUP, 0 };
+ GError *err = NULL;
+
+ if (error != NULL)
+ {
+ g_debug ("%s", error->message);
+ return;
+ }
+
+ channel = tp_channel_new_from_properties (connection, channel_path,
+ properties, &err);
+ if (channel == NULL)
+ {
+ g_debug ("%s", err->message);
+ g_clear_error (&err);
+ return;
+ }
+
+ tp_proxy_prepare_async (TP_PROXY (channel), features,
+ stored_channel_prepare_cb, self);
+
+ g_object_unref (channel);
+}
+
+static void
+connection_prepare_cb (GObject *object,
+ GAsyncResult *res,
+ gpointer self)
+{
+ TpConnection *connection = TP_CONNECTION (object);
+ GError *error = NULL;
+ GHashTable *request;
+
+ if (!tp_proxy_prepare_finish (TP_PROXY (connection), res, &error))
+ {
+ g_debug ("%s", error->message);
+ g_clear_error (&error);
+ return;
+ }
+
+ if (!_capabilities_has_stream_tube (tp_connection_get_capabilities (connection)))
+ return;
+
+ request = tp_asv_new (
+ TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
+ TP_IFACE_CHANNEL_TYPE_CONTACT_LIST,
+ TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT,
+ TP_HANDLE_TYPE_LIST,
+ TP_PROP_CHANNEL_TARGET_ID, G_TYPE_STRING,
+ "stored",
+ NULL);
+
+ tp_cli_connection_interface_requests_call_ensure_channel (connection, -1,
+ request, ensure_stored_channel_cb, self, NULL, NULL);
+
+ g_hash_table_unref (request);
+}
+
+static void
+account_manager_prepare_cb (GObject *object,
+ GAsyncResult *res,
+ gpointer self)
+{
+ TpAccountManager *manager = TP_ACCOUNT_MANAGER (object);
+ GList *accounts, *l;
+ GError *error = NULL;
+
+ if (!tp_proxy_prepare_finish (TP_PROXY (manager), res, &error))
+ {
+ g_debug ("%s", error->message);
+ g_clear_error (&error);
+ return;
+ }
+
+ accounts = tp_account_manager_get_valid_accounts (manager);
+ for (l = accounts; l != NULL; l = l->next)
+ {
+ GQuark features[] = { TP_CONNECTION_FEATURE_CAPABILITIES, 0 };
+ TpAccount *account = l->data;
+ TpConnection *connection;
+
+ connection = tp_account_get_connection (account);
+ if (connection != NULL)
+ tp_proxy_prepare_async (TP_PROXY (connection), features,
+ connection_prepare_cb, self);
+ }
+ g_list_free (accounts);
+}
+
+static void
+dispose (GObject *object)
+{
+ SshContactTreeView *self = SSH_CONTACT_TREE_VIEW (object);
+
+ tp_clear_object (&self->priv->store);
+ tp_clear_object (&self->priv->account_manager);
+
+ G_OBJECT_CLASS (ssh_contact_tree_view_parent_class)->dispose (object);
+}
+
+static void
+ssh_contact_tree_view_init (SshContactTreeView *self)
+{
+ GtkTreeView *view = GTK_TREE_VIEW (self);
+ GtkCellRenderer *renderer;
+ GtkTreeViewColumn *column;
+
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, SSH_CONTACT_TYPE_TREE_VIEW,
+ SshContactTreeViewPrivate);
+
+ self->priv->store = gtk_list_store_new (N_COL,
+ G_TYPE_OBJECT, /* ACCOUNT */
+ G_TYPE_OBJECT, /* CONTACT */
+ G_TYPE_STRING); /* TEXT */
+
+ renderer = gtk_cell_renderer_text_new ();
+ column = gtk_tree_view_column_new_with_attributes ("Contacts",
+ renderer, "text", COL_TEXT, NULL);
+
+ gtk_tree_view_append_column (view, column);
+ gtk_tree_view_set_headers_visible (view, FALSE);
+ gtk_tree_view_set_model (view, GTK_TREE_MODEL (self->priv->store));
+
+ self->priv->account_manager = tp_account_manager_dup ();
+ tp_proxy_prepare_async (TP_PROXY (self->priv->account_manager), NULL,
+ account_manager_prepare_cb, self);
+}
+
+static void
+ssh_contact_tree_view_class_init (SshContactTreeViewClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = dispose;
+
+ g_type_class_add_private (klass, sizeof (SshContactTreeViewPrivate));
+}
+
+GtkWidget *
+ssh_contact_tree_view_new (void)
+{
+ return g_object_new (SSH_CONTACT_TYPE_TREE_VIEW, NULL);
+}
+
+TpAccount *
+ssh_contact_tree_view_get_selected_account (SshContactTreeView *self)
+{
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ TpAccount *account = NULL;
+
+ g_return_val_if_fail (SSH_CONTACT_IS_TREE_VIEW (self), NULL);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
+ if (!gtk_tree_selection_get_selected (selection, &model, &iter))
+ return NULL;
+
+ gtk_tree_model_get (model, &iter, COL_ACCOUNT, &account, -1);
+ g_object_unref (account);
+
+ return account;
+}
+
+TpContact *
+ssh_contact_tree_view_get_selected_contact (SshContactTreeView *self)
+{
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ TpContact *contact;
+
+ g_return_val_if_fail (SSH_CONTACT_IS_TREE_VIEW (self), NULL);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
+ if (!gtk_tree_selection_get_selected (selection, &model, &iter))
+ return NULL;
+
+ gtk_tree_model_get (model, &iter, COL_CONTACT, &contact, -1);
+ g_object_unref (contact);
+
+ return contact;
+}
+
+/* vim: set ts=8: */
diff --git a/src/vinagre/tree-view.h b/src/vinagre/tree-view.h
new file mode 100644
index 0000000..bd93d26
--- /dev/null
+++ b/src/vinagre/tree-view.h
@@ -0,0 +1,61 @@
+/*
+ * 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
+ */
+
+#ifndef __SSH_CONTACT_TREE_VIEW_H__
+#define __SSH_CONTACT_TREE_VIEW_H__
+
+#include <gtk/gtk.h>
+
+#include <telepathy-glib/telepathy-glib.h>
+
+G_BEGIN_DECLS
+
+#define SSH_CONTACT_TYPE_TREE_VIEW (ssh_contact_tree_view_get_type ())
+#define SSH_CONTACT_TREE_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SSH_CONTACT_TYPE_TREE_VIEW, SshContactTreeView))
+#define SSH_CONTACT_TREE_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SSH_CONTACT_TYPE_TREE_VIEW, SshContactTreeViewClass))
+#define SSH_CONTACT_IS_TREE_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SSH_CONTACT_TYPE_TREE_VIEW))
+#define SSH_CONTACT_IS_TREE_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SSH_CONTACT_TYPE_TREE_VIEW))
+#define SSH_CONTACT_TREE_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SSH_CONTACT_TYPE_TREE_VIEW, SshContactTreeViewClass))
+
+typedef struct _SshContactTreeViewPrivate SshContactTreeViewPrivate;
+
+typedef struct
+{
+ GtkTreeView parent_instance;
+ SshContactTreeViewPrivate *priv;
+} SshContactTreeView;
+
+typedef struct
+{
+ GtkTreeViewClass parent_class;
+} SshContactTreeViewClass;
+
+GType ssh_contact_tree_view_get_type (void) G_GNUC_CONST;
+
+GtkWidget *ssh_contact_tree_view_new (void);
+
+TpAccount *ssh_contact_tree_view_get_selected_account (SshContactTreeView *self);
+
+TpContact *ssh_contact_tree_view_get_selected_contact (SshContactTreeView *self);
+
+
+G_END_DECLS
+
+#endif /* __SSH_CONTACT_TREE_VIEW_H__ */
+/* vim: set ts=8: */