[vinagre] Added VNC listen mode. Closes #578717.



commit 755cbe72145c3e0e95a139748bf3d059bde78831
Author: Jonh Wendell <jwendell gnome org>
Date:   Tue Sep 29 15:50:07 2009 -0300

    Added VNC listen mode. Closes #578717.

 plugins/vnc/Makefile.am                   |   11 +-
 plugins/vnc/vinagre-vnc-listener-dialog.c |  252 +++++++++++++++++++++++++++
 plugins/vnc/vinagre-vnc-listener-dialog.h |   34 ++++
 plugins/vnc/vinagre-vnc-listener.c        |  265 +++++++++++++++++++++++++++++
 plugins/vnc/vinagre-vnc-listener.h        |   62 +++++++
 plugins/vnc/vinagre-vnc-plugin.c          |  108 ++++++++++++-
 plugins/vnc/vnc.ui                        |  258 ++++++++++++++++++++++++++++
 7 files changed, 984 insertions(+), 6 deletions(-)
---
diff --git a/plugins/vnc/Makefile.am b/plugins/vnc/Makefile.am
index 682c0f0..3b2927c 100644
--- a/plugins/vnc/Makefile.am
+++ b/plugins/vnc/Makefile.am
@@ -12,13 +12,15 @@ plugin_LTLIBRARIES = libvnc.la
 libvnc_la_SOURCES = 						\
 	vinagre-vnc-plugin.h vinagre-vnc-plugin.c		\
 	vinagre-vnc-connection.h vinagre-vnc-connection.c	\
-	vinagre-vnc-tab.h vinagre-vnc-tab.c
+	vinagre-vnc-tab.h vinagre-vnc-tab.c			\
+	vinagre-vnc-listener.h vinagre-vnc-listener.c		\
+	vinagre-vnc-listener-dialog.h vinagre-vnc-listener-dialog.c
 
 libvnc_la_LDFLAGS = $(PLUGIN_LIBTOOL_FLAGS)
 libvnc_la_LIBADD  = $(VNC_LIBS)
 
-#uidir = $(VINAGRE_PLUGINS_DATA_DIR)/vnc
-#ui_DATA = vnc.ui
+uidir = $(VINAGRE_PLUGINS_DATA_DIR)/vnc
+ui_DATA = vnc.ui
 
 plugin_in_files = vnc.vinagre-plugin.desktop.in
 
@@ -26,8 +28,7 @@ vnc.vinagre-plugin: vnc.vinagre-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $
 
 plugin_DATA = $(plugin_in_files:.vinagre-plugin.desktop.in=.vinagre-plugin)
 
-#EXTRA_DIST = $(ui_DATA) $(plugin_in_files)
-EXTRA_DIST = $(plugin_in_files)
+EXTRA_DIST = $(ui_DATA) $(plugin_in_files)
 
 CLEANFILES = $(plugin_DATA)
 DISTCLEANFILES = $(plugin_DATA)
diff --git a/plugins/vnc/vinagre-vnc-listener-dialog.c b/plugins/vnc/vinagre-vnc-listener-dialog.c
new file mode 100644
index 0000000..15f4eb5
--- /dev/null
+++ b/plugins/vnc/vinagre-vnc-listener-dialog.c
@@ -0,0 +1,252 @@
+/*
+ * vinagre-vnc-listener-dialog.c
+ * This file is part of vinagre
+ *
+ * Copyright (C) 2009 Jonh Wendell <wendell bani com br>
+ *
+ * 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/>.
+ */
+
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <ifaddrs.h>
+#include <string.h>
+#include <glib/gi18n.h>
+
+#include <vinagre/vinagre-utils.h>
+#include <vinagre/vinagre-prefs.h>
+#include "vinagre-vnc-listener-dialog.h"
+#include "vinagre-vnc-listener.h"
+
+typedef struct
+{
+  GtkBuilder *xml;
+  GtkWidget *dialog;
+  GtkWidget *enable_reverse_check;
+  GtkWidget *always_enabled_check;
+  GtkWidget *port_label;
+  GtkWidget *connectivity_exp;
+  GtkTextBuffer *ip_buffer;
+} VncListenDialog;
+
+static void
+setup_ip_buffer (VncListenDialog *dialog)
+{
+  char            buf[INET6_ADDRSTRLEN], *dup;
+  struct ifaddrs  *myaddrs, *ifa;
+  void            *sin;
+  GArray          *ipv4, *ipv6;
+  GString         *str;
+  int             i;
+
+  ipv4 = g_array_new (FALSE, TRUE, sizeof (char *));
+  ipv6 = g_array_new (FALSE, TRUE, sizeof (char *));
+  str = g_string_new (NULL);
+
+  getifaddrs (&myaddrs);
+  for (ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next)
+    {
+      if (ifa->ifa_addr == NULL || ifa->ifa_name == NULL || (ifa->ifa_flags & IFF_UP) == 0 || strncmp (ifa->ifa_name, "lo", 2) == 0)
+	continue;
+
+      switch (ifa->ifa_addr->sa_family)
+	{
+	  case AF_INET:
+	    sin = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
+	    inet_ntop (AF_INET, sin, buf, INET6_ADDRSTRLEN);
+	    dup = g_strdup (buf);
+	    g_array_append_val (ipv4, dup);
+	    break;
+
+	  case AF_INET6:
+	    sin = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
+	    inet_ntop (AF_INET6, sin, buf, INET6_ADDRSTRLEN);
+	    dup = g_strdup (buf);
+	    g_array_append_val (ipv6, dup);
+	    break;
+	  default: continue;
+	}
+    }
+
+  if (ipv4->len > 0)
+    {
+      if (ipv6->len > 0)
+        g_string_append (str, _("IPv4:"));
+
+      for (i = 0; i < ipv4->len; i++)
+	{
+	  dup = g_array_index (ipv4, char *, i);
+	  g_string_append_printf (str, "\n%s", dup);
+	  g_free (dup);
+	}
+    }
+  if (ipv6->len > 0)
+    {
+      if (ipv4->len > 0)
+        g_string_append (str, _("\n\nIPv6:"));
+
+      for (i = 0; i < ipv6->len; i++)
+	{
+	  dup = g_array_index (ipv6, char *, i);
+	  g_string_append_printf (str, "\n%s", g_array_index (ipv6, char *, i));
+	  g_free (dup);
+	}
+    }
+
+  gtk_text_buffer_set_text (dialog->ip_buffer, str->str, -1);
+
+  freeifaddrs (myaddrs);
+  g_array_free (ipv4, TRUE);
+  g_array_free (ipv6, TRUE);
+  g_string_free (str, TRUE);
+}
+
+static void
+dialog_destroy (GtkObject *obj,
+		VncListenDialog *dialog)
+{
+  g_object_unref (dialog->xml);
+  g_slice_free (VncListenDialog, dialog);
+}
+
+static void
+dialog_response_handler (GtkDialog       *widget,
+			 gint            res_id,
+			 VncListenDialog *dialog)
+{
+  switch (res_id)
+    {
+      case GTK_RESPONSE_HELP:
+	// TODO: display the help
+	break;
+
+      default:
+	gtk_widget_destroy (dialog->dialog);
+	break;
+    }
+}
+
+static void
+update_ui_sensitivity (VncListenDialog *dialog)
+{
+  gboolean listening;
+  gchar *str;
+  VinagreVncListener *listener = vinagre_vnc_listener_get_default ();
+
+  listening = vinagre_vnc_listener_is_listening (listener);
+
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->enable_reverse_check),
+				listening);
+  gtk_widget_set_sensitive (dialog->always_enabled_check, listening);
+  gtk_widget_set_sensitive (dialog->connectivity_exp, listening);
+
+  if (listening)
+    {
+      str = g_strdup_printf (_("On the port %d"), vinagre_vnc_listener_get_port (listener));
+      gtk_label_set_label (GTK_LABEL (dialog->port_label), str);
+      g_free (str);
+    }
+  else
+    {
+      gtk_expander_set_expanded (GTK_EXPANDER (dialog->connectivity_exp), FALSE);
+    }
+}
+
+static void
+enable_reverse_toggled_cb (GtkToggleButton *button, VncListenDialog *dialog)
+{
+  VinagreVncListener *listener = vinagre_vnc_listener_get_default ();
+
+  if (gtk_toggle_button_get_active (button))
+    vinagre_vnc_listener_start (listener);
+  else
+    vinagre_vnc_listener_stop (listener);
+
+  update_ui_sensitivity (dialog);
+}
+
+static void
+always_enabled_toggled_cb (GtkToggleButton *button, VncListenDialog *dialog)
+{
+  g_object_set (vinagre_prefs_get_default (),
+		"always-enable-listening", gtk_toggle_button_get_active (button),
+		NULL);
+}
+
+void
+vinagre_vnc_listener_dialog_show (VinagreWindow *parent, VinagrePlugin *plugin)
+{
+  VncListenDialog *dialog;
+  GtkBuilder *xml;
+  gboolean always;
+
+  xml = vinagre_utils_get_builder (plugin, "vnc.ui");
+  if (!xml)
+    return;
+
+  dialog = g_slice_new (VncListenDialog);
+  dialog->xml = xml;
+
+  dialog->dialog = GTK_WIDGET (gtk_builder_get_object (xml, "listener_dialog"));
+  g_assert (dialog->dialog != NULL);
+
+  dialog->ip_buffer = GTK_TEXT_BUFFER (gtk_builder_get_object (xml, "ip_textbuffer"));
+  g_assert (dialog->ip_buffer != NULL);
+  setup_ip_buffer (dialog);
+
+  dialog->enable_reverse_check = GTK_WIDGET (gtk_builder_get_object (xml, "enable_reverse_check"));
+  g_assert (dialog->enable_reverse_check != NULL);
+  g_signal_connect (dialog->enable_reverse_check,
+		    "toggled",
+		    G_CALLBACK (enable_reverse_toggled_cb),
+		    dialog);
+
+  dialog->always_enabled_check = GTK_WIDGET (gtk_builder_get_object (xml, "always_enabled_check"));
+  g_assert (dialog->always_enabled_check != NULL);
+  g_object_get (vinagre_prefs_get_default (),
+		"always-enable-listening", &always,
+		NULL);
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->always_enabled_check),
+				always);
+  g_signal_connect (dialog->always_enabled_check,
+		    "toggled",
+		    G_CALLBACK (always_enabled_toggled_cb),
+		    dialog);
+
+  dialog->connectivity_exp = GTK_WIDGET (gtk_builder_get_object (xml, "connectivity_exp"));
+  g_assert (dialog->connectivity_exp != NULL);
+
+  dialog->port_label = GTK_WIDGET (gtk_builder_get_object (xml, "port_label"));
+  g_assert (dialog->port_label != NULL);
+
+  update_ui_sensitivity (dialog);
+
+  g_signal_connect (dialog->dialog,
+		    "destroy",
+		    G_CALLBACK (dialog_destroy),
+		    dialog);
+
+  g_signal_connect (dialog->dialog,
+		    "response",
+		    G_CALLBACK (dialog_response_handler),
+		    dialog);
+
+  if (GTK_IS_WINDOW (parent))
+    gtk_window_set_transient_for (GTK_WINDOW (dialog->dialog), GTK_WINDOW (parent));
+
+  gtk_widget_show_all (dialog->dialog);
+}
+
+/* vim: set ts=8: */
diff --git a/plugins/vnc/vinagre-vnc-listener-dialog.h b/plugins/vnc/vinagre-vnc-listener-dialog.h
new file mode 100644
index 0000000..8c6a8d2
--- /dev/null
+++ b/plugins/vnc/vinagre-vnc-listener-dialog.h
@@ -0,0 +1,34 @@
+/*
+ * vinagre-vnc-listener-dialog.h
+ * This file is part of vinagre
+ *
+ * Copyright (C) 2009 Jonh Wendell <wendell bani com br>
+ *
+ * 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/>.
+ */
+
+#ifndef __VINAGRE_VNC_LISTENER_DIALOG_H__
+#define __VINAGRE_VNC_LISTENER_DIALOG_H__
+
+#include <vinagre/vinagre-window.h>
+#include <vinagre/vinagre-plugin.h>
+
+G_BEGIN_DECLS
+
+void vinagre_vnc_listener_dialog_show (VinagreWindow *parent, VinagrePlugin *plugin);
+
+G_END_DECLS
+
+#endif /* __VINAGRE_VNC_LISTENER_DIALOG_H__ */
+/* vim: set ts=8: */
diff --git a/plugins/vnc/vinagre-vnc-listener.c b/plugins/vnc/vinagre-vnc-listener.c
new file mode 100644
index 0000000..b7c301e
--- /dev/null
+++ b/plugins/vnc/vinagre-vnc-listener.c
@@ -0,0 +1,265 @@
+/*
+ * vinagre-vnc-listener.c
+ * This file is part of vinagre
+ *
+ * Copyright (C) 2009 - Jonh Wendell <wendell bani com br>
+ *
+ * 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/>.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <glib/gi18n.h>
+#include <vinagre/vinagre-commands.h>
+#include <vinagre/vinagre-app.h>
+#include "vinagre-vnc-listener.h"
+#include "vinagre-vnc-connection.h"
+
+struct _VinagreVncListenerPrivate
+{
+  int server_sock;
+  GIOChannel *io;
+  gboolean listening;
+  guint io_uid;
+  gint port;
+};
+
+enum
+{
+  PROP_0,
+  PROP_LISTENING,
+  PROP_PORT
+};
+
+static VinagreVncListener *listener_singleton = NULL;
+
+#define VINAGRE_VNC_LISTENER_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), VINAGRE_TYPE_VNC_LISTENER, VinagreVncListenerPrivate))
+G_DEFINE_TYPE (VinagreVncListener, vinagre_vnc_listener, G_TYPE_OBJECT);
+
+static void
+vinagre_vnc_listener_init (VinagreVncListener *listener)
+{
+  listener->priv = G_TYPE_INSTANCE_GET_PRIVATE (listener, VINAGRE_TYPE_VNC_LISTENER, VinagreVncListenerPrivate);
+
+  listener->priv->io = NULL;
+  listener->priv->server_sock = 0;
+  listener->priv->listening = FALSE;
+  listener->priv->io_uid = 0;
+  listener->priv->port = 0;
+}
+
+static void
+vinagre_vnc_listener_dispose (GObject *object)
+{
+  VinagreVncListener *listener = VINAGRE_VNC_LISTENER (object);
+
+  vinagre_vnc_listener_stop (listener);
+
+  G_OBJECT_CLASS (vinagre_vnc_listener_parent_class)->dispose (object);
+}
+
+static void
+vinagre_vnc_listener_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+  VinagreVncListener *listener;
+
+  g_return_if_fail (VINAGRE_IS_VNC_LISTENER (object));
+
+  listener = VINAGRE_VNC_LISTENER (object);
+
+  switch (prop_id)
+    {
+      case PROP_LISTENING:
+	g_value_set_boolean (value, listener->priv->listening);
+	break;
+
+      case PROP_PORT:
+	g_value_set_int (value, vinagre_vnc_listener_get_port (listener));
+	break;
+
+      default:
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	break;
+    }
+}
+
+static void
+vinagre_vnc_listener_class_init (VinagreVncListenerClass *klass)
+{
+  GObjectClass* object_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (VinagreVncListenerPrivate));
+
+  object_class->dispose = vinagre_vnc_listener_dispose;
+  object_class->get_property = vinagre_vnc_listener_get_property;
+
+  g_object_class_install_property (object_class,
+                                   PROP_LISTENING,
+                                   g_param_spec_boolean ("listening",
+                                                        "Listening",
+	                                                "If we are listening for incoming (reverse) VNC connections",
+                                                        FALSE,
+	                                                G_PARAM_READABLE |
+                                                        G_PARAM_STATIC_NICK |
+                                                        G_PARAM_STATIC_NAME |
+                                                        G_PARAM_STATIC_BLURB));
+  g_object_class_install_property (object_class,
+                                   PROP_PORT,
+                                   g_param_spec_int ("port",
+                                                     "Port",
+	                                             "TCP port in which we are listening for reverse connections",
+                                                     5500,
+                                                     5600,
+                                                     5500,
+	                                             G_PARAM_READABLE |
+                                                     G_PARAM_STATIC_NICK |
+                                                     G_PARAM_STATIC_NAME |
+                                                     G_PARAM_STATIC_BLURB));
+
+}
+
+VinagreVncListener *
+vinagre_vnc_listener_get_default (void)
+{
+  if (G_UNLIKELY (!listener_singleton))
+    listener_singleton = VINAGRE_VNC_LISTENER (g_object_new (VINAGRE_TYPE_VNC_LISTENER, NULL));
+
+  return listener_singleton;
+}
+
+static gboolean
+incoming (GIOChannel *source, GIOCondition condition, VinagreVncListener *listener)
+{
+  VinagreConnection *conn;
+  VinagreWindow *window;
+  int cl_sock;
+  struct sockaddr_in6 client_addr;
+  char client_name[INET6_ADDRSTRLEN];
+  socklen_t client_addr_len = sizeof (client_addr);
+
+  cl_sock = accept (listener->priv->server_sock, (struct sockaddr *) &client_addr, &client_addr_len);
+  if (cl_sock < 0)
+    g_error ("accept() failed");
+
+  window = vinagre_app_get_active_window (vinagre_app_get_default ());
+  if (!window)
+    {
+      g_warning (_("Incoming VNC connection arrived but there is none active window"));
+      return TRUE;
+    }
+
+  conn = vinagre_vnc_connection_new ();
+  vinagre_vnc_connection_set_fd (VINAGRE_VNC_CONNECTION (conn), cl_sock);
+
+  if (inet_ntop (AF_INET6, &client_addr.sin6_addr.s6_addr, client_name, sizeof (client_name)) != NULL)
+    vinagre_connection_set_host (conn, client_name);
+  vinagre_connection_set_port (conn, ntohs (client_addr.sin6_port));
+
+  vinagre_cmd_direct_connect (conn, window);
+
+  return TRUE;
+}
+
+void
+vinagre_vnc_listener_start (VinagreVncListener *listener)
+{
+  struct sockaddr_in6 server_addr;
+  int port;
+
+  g_return_if_fail (VINAGRE_IS_VNC_LISTENER (listener));
+
+  if (listener->priv->listening)
+    return;
+
+  listener->priv->server_sock = socket (AF_INET6, SOCK_STREAM, IPPROTO_TCP);
+  if (listener->priv->server_sock < 0)
+    g_error ("socket() failed");
+
+  memset (&server_addr, 0, sizeof (server_addr));
+  server_addr.sin6_family = AF_INET6;
+  server_addr.sin6_addr = in6addr_any;
+
+  for (port=5500; port<=5600; port++)
+    {
+      server_addr.sin6_port = htons (port);
+
+      if (bind (listener->priv->server_sock, (struct sockaddr *) &server_addr, sizeof (server_addr)) == 0)
+	break;
+    }
+  if (port>5600)
+    g_error ("bind() failed");
+
+  if (listen (listener->priv->server_sock, 5) < 0)
+    g_error ("listen() failed");
+
+  listener->priv->io = g_io_channel_unix_new (listener->priv->server_sock);
+  listener->priv->io_uid = g_io_add_watch (listener->priv->io, G_IO_IN, (GIOFunc)incoming, listener);
+
+  listener->priv->port = port;
+  listener->priv->listening = TRUE;
+  g_object_notify (G_OBJECT (listener), "listening");
+}
+
+void
+vinagre_vnc_listener_stop (VinagreVncListener *listener)
+{
+  g_return_if_fail (VINAGRE_IS_VNC_LISTENER (listener));
+
+  if (!listener->priv->listening)
+    return;
+
+  if (listener->priv->io)
+    {
+      g_source_remove (listener->priv->io_uid);
+      g_io_channel_unref (listener->priv->io);
+      listener->priv->io = NULL;
+    }
+
+  if (listener->priv->server_sock > 0)
+    {
+      close (listener->priv->server_sock);
+      listener->priv->server_sock = 0;
+    }
+
+  listener->priv->listening = FALSE;
+  g_object_notify (G_OBJECT (listener), "listening");
+}
+
+gboolean
+vinagre_vnc_listener_is_listening (VinagreVncListener *listener)
+{
+  g_return_val_if_fail (VINAGRE_IS_VNC_LISTENER (listener), FALSE);
+
+  return listener->priv->listening;
+}
+
+gint
+vinagre_vnc_listener_get_port (VinagreVncListener *listener)
+{
+  g_return_val_if_fail (VINAGRE_IS_VNC_LISTENER (listener), 0);
+
+  return listener->priv->listening ? listener->priv->port : 0;
+}
+
+/* vim: set ts=8: */
diff --git a/plugins/vnc/vinagre-vnc-listener.h b/plugins/vnc/vinagre-vnc-listener.h
new file mode 100644
index 0000000..f68c4b0
--- /dev/null
+++ b/plugins/vnc/vinagre-vnc-listener.h
@@ -0,0 +1,62 @@
+/*
+ * vinagre-vnc-listener.h
+ * This file is part of vinagre
+ *
+ * Copyright (C) 2009 - Jonh Wendell <wendell bani com br>
+ *
+ * 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/>.
+ */
+
+#ifndef __VINAGRE_VNC_LISTENER_H__
+#define __VINAGRE_VNC_LISTENER_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define VINAGRE_TYPE_VNC_LISTENER             (vinagre_vnc_listener_get_type ())
+#define VINAGRE_VNC_LISTENER(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), VINAGRE_TYPE_VNC_LISTENER, VinagreVncListener))
+#define VINAGRE_VNC_LISTENER_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), VINAGRE_TYPE_VNC_LISTENER, VinagreVncListenerClass))
+#define VINAGRE_IS_VNC_LISTENER(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VINAGRE_TYPE_VNC_LISTENER))
+#define VINAGRE_IS_VNC_LISTENER_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), VINAGRE_TYPE_VNC_LISTENER))
+#define VINAGRE_VNC_LISTENER_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), VINAGRE_TYPE_VNC_LISTENER, VinagreVncListenerClass))
+
+typedef struct _VinagreVncListenerClass   VinagreVncListenerClass;
+typedef struct _VinagreVncListener        VinagreVncListener;
+typedef struct _VinagreVncListenerPrivate VinagreVncListenerPrivate;
+
+struct _VinagreVncListenerClass
+{
+  GObjectClass parent_class;
+};
+
+struct _VinagreVncListener
+{
+  GObject parent_instance;
+  VinagreVncListenerPrivate *priv;
+};
+
+
+GType vinagre_vnc_listener_get_type (void) G_GNUC_CONST;
+
+VinagreVncListener*	vinagre_vnc_listener_get_default (void);
+void			vinagre_vnc_listener_start (VinagreVncListener *listener);
+void			vinagre_vnc_listener_stop  (VinagreVncListener *listener);
+gboolean		vinagre_vnc_listener_is_listening (VinagreVncListener *listener);
+gint			vinagre_vnc_listener_get_port (VinagreVncListener *listener);
+
+G_END_DECLS
+
+#endif /* __VINAGRE_VNC_LISTENER_H__  */
+/* vim: set ts=8: */
diff --git a/plugins/vnc/vinagre-vnc-plugin.c b/plugins/vnc/vinagre-vnc-plugin.c
index 2a3c156..16646d8 100644
--- a/plugins/vnc/vinagre-vnc-plugin.c
+++ b/plugins/vnc/vinagre-vnc-plugin.c
@@ -28,28 +28,134 @@
 #include <vncdisplay.h>
 
 #include <vinagre/vinagre-debug.h>
-#include <vinagre/vinagre-utils.h>
+#include <vinagre/vinagre-prefs.h>
 
 #include "vinagre-vnc-plugin.h"
 #include "vinagre-vnc-connection.h"
 #include "vinagre-vnc-tab.h"
+#include "vinagre-vnc-listener-dialog.h"
+#include "vinagre-vnc-listener.h"
 
 #define VINAGRE_VNC_PLUGIN_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), VINAGRE_TYPE_VNC_PLUGIN, VinagreVncPluginPrivate))
+#define WINDOW_DATA_KEY "VinagreVNCPluginWindowData"
 
 VINAGRE_PLUGIN_REGISTER_TYPE(VinagreVncPlugin, vinagre_vnc_plugin)
 
+typedef struct
+{
+  GtkActionGroup *ui_action_group;
+  guint ui_id;
+} WindowData;
+
+typedef struct
+{
+  VinagrePlugin *plugin;
+  VinagreWindow *window;
+} ActionData;
+
+static void
+free_window_data (WindowData *data)
+{
+  g_return_if_fail (data != NULL);
+
+  g_object_unref (data->ui_action_group);
+  g_slice_free (WindowData, data);
+}
+
+static void
+free_action_data (ActionData *data)
+{
+  g_return_if_fail (data != NULL);
+
+  g_slice_free (ActionData, data);
+}
+
+static void
+listening_cb (GtkAction *action, ActionData *action_data)
+{
+  vinagre_vnc_listener_dialog_show (action_data->window, action_data->plugin);
+}
+
+static GtkActionEntry action_entries[] =
+{
+  { "VNCListener",
+    NULL,
+    N_("_Reverse Connections..."),
+    NULL,
+    N_("Configure incoming VNC connections"),
+    G_CALLBACK (listening_cb)
+  }
+};
+
 static void
 impl_activate (VinagrePlugin *plugin,
                VinagreWindow *window)
 {
+  GtkActionGroup *action_group;
+  GtkUIManager *manager;
+  WindowData *data;
+  ActionData *action_data;
+  gboolean always;
+
   vinagre_debug_message (DEBUG_PLUGINS, "VinagreVncPlugin Activate");
+
+  data = g_slice_new (WindowData);
+  action_data = g_slice_new (ActionData);
+  action_data->window = window;
+  action_data->plugin = plugin;
+
+  action_group = vinagre_window_get_always_sensitive_action (window);
+  manager = vinagre_window_get_ui_manager (window);
+
+  data->ui_action_group = gtk_action_group_new ("VinagreVNCPluginActions");
+  gtk_action_group_set_translation_domain (data->ui_action_group, GETTEXT_PACKAGE);
+  gtk_action_group_add_actions_full (data->ui_action_group,
+				     action_entries,
+				     G_N_ELEMENTS (action_entries),
+				     action_data,
+				     (GDestroyNotify) free_action_data);
+  gtk_ui_manager_insert_action_group (manager,
+				      data->ui_action_group,
+				      -1);
+
+  data->ui_id = gtk_ui_manager_new_merge_id (manager);
+  gtk_ui_manager_add_ui (manager,
+			 data->ui_id,
+			 "/MenuBar/MachineMenu/MachineOps_1",
+			 "VNCListener",
+			 "VNCListener",
+			 GTK_UI_MANAGER_AUTO,
+			 TRUE);
+
+  g_object_set_data_full (G_OBJECT (window),
+			  WINDOW_DATA_KEY,
+			  data,
+			  (GDestroyNotify) free_window_data);
+
+  g_object_get (vinagre_prefs_get_default (),
+		"always-enable-listening", &always,
+		NULL);
+  if (always)
+    vinagre_vnc_listener_start (vinagre_vnc_listener_get_default ());
 }
 
 static void
 impl_deactivate  (VinagrePlugin *plugin,
                   VinagreWindow *window)
 {
+  GtkUIManager *manager;
+  WindowData *data;
+
   vinagre_debug_message (DEBUG_PLUGINS, "VinagreVncPlugin Deactivate");
+
+  manager = vinagre_window_get_ui_manager (window);
+  data = (WindowData *) g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY);
+  g_return_if_fail (data != NULL);
+
+  gtk_ui_manager_remove_ui (manager, data->ui_id);
+  gtk_ui_manager_remove_action_group (manager, data->ui_action_group);
+
+  g_object_set_data (G_OBJECT (window), WINDOW_DATA_KEY, NULL);
 }
 
 static void
diff --git a/plugins/vnc/vnc.ui b/plugins/vnc/vnc.ui
new file mode 100644
index 0000000..31a3dab
--- /dev/null
+++ b/plugins/vnc/vnc.ui
@@ -0,0 +1,258 @@
+<?xml version="1.0"?>
+<interface>
+  <requires lib="gtk+" version="2.16"/>
+  <!-- interface-naming-policy project-wide -->
+  <object class="GtkDialog" id="listener_dialog">
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">Reverse Connections</property>
+    <property name="resizable">False</property>
+    <property name="modal">True</property>
+    <property name="window_position">center-on-parent</property>
+    <property name="destroy_with_parent">True</property>
+    <property name="type_hint">dialog</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <object class="GtkVBox" id="dialog-vbox1">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">6</property>
+        <child>
+          <object class="GtkVBox" id="vbox1">
+            <property name="visible">True</property>
+            <property name="orientation">vertical</property>
+            <property name="spacing">6</property>
+            <child>
+              <object class="GtkHBox" id="hbox1">
+                <property name="visible">True</property>
+                <property name="spacing">6</property>
+                <child>
+                  <object class="GtkImage" id="image1">
+                    <property name="visible">True</property>
+                    <property name="xpad">6</property>
+                    <property name="stock">gtk-dialog-info</property>
+                    <property name="icon-size">6</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label1">
+                    <property name="visible">True</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">By activating reverse connections you can access machines that are behind a firewall. The remote side is supposed to initiate the connection with you. For further information, checkout the help.</property>
+                    <property name="wrap">True</property>
+                    <attributes>
+                      <attribute name="style" value="italic"/>
+                    </attributes>
+                  </object>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkVBox" id="vbox2">
+                <property name="visible">True</property>
+                <property name="orientation">vertical</property>
+                <property name="spacing">4</property>
+                <child>
+                  <object class="GtkCheckButton" id="enable_reverse_check">
+                    <property name="label" translatable="yes">_Enable Reverse Connections</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">False</property>
+                    <property name="use_underline">True</property>
+                    <property name="draw_indicator">True</property>
+                  </object>
+                  <packing>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkHBox" id="hbox2">
+                    <property name="visible">True</property>
+                    <child>
+                      <object class="GtkLabel" id="label2">
+                        <property name="visible">True</property>
+                        <property name="label">    </property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkCheckButton" id="always_enabled_check">
+                        <property name="label" translatable="yes">_Always Enabled</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="use_underline">True</property>
+                        <property name="draw_indicator">True</property>
+                      </object>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkHBox" id="hbox3">
+                    <property name="visible">True</property>
+                    <child>
+                      <object class="GtkLabel" id="label3">
+                        <property name="visible">True</property>
+                        <property name="label">    </property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkExpander" id="connectivity_exp">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <child>
+                          <object class="GtkVBox" id="vbox3">
+                            <property name="visible">True</property>
+                            <property name="orientation">vertical</property>
+                            <child>
+                              <object class="GtkFrame" id="frame1">
+                                <property name="visible">True</property>
+                                <property name="label_xalign">0</property>
+                                <property name="label_yalign">0</property>
+                                <child>
+                                  <object class="GtkAlignment" id="alignment1">
+                                    <property name="visible">True</property>
+                                    <child>
+                                      <object class="GtkTextView" id="ip_textview">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="pixels_above_lines">3</property>
+                                        <property name="pixels_below_lines">3</property>
+                                        <property name="editable">False</property>
+                                        <property name="buffer">ip_textbuffer</property>
+                                      </object>
+                                    </child>
+                                  </object>
+                                </child>
+                                <child type="label">
+                                  <object class="GtkLabel" id="label6">
+                                    <property name="visible">True</property>
+                                    <property name="xalign">0</property>
+                                    <property name="label" translatable="yes">This machine is reachable through the following IP address(es):</property>
+                                    <attributes>
+                                      <attribute name="style" value="italic"/>
+                                    </attributes>
+                                  </object>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="port_label">
+                                <property name="visible">True</property>
+                                <property name="xalign">0</property>
+                                <property name="label">label</property>
+                                <attributes>
+                                  <attribute name="style" value="italic"/>
+                                  <attribute name="scale" value="1,000000"/>
+                                </attributes>
+                              </object>
+                              <packing>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </object>
+                        </child>
+                        <child type="label">
+                          <object class="GtkLabel" id="label4">
+                            <property name="visible">True</property>
+                            <property name="label" translatable="yes">Connectivity</property>
+                          </object>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="padding">6</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <object class="GtkHButtonBox" id="dialog-action_area1">
+            <property name="visible">True</property>
+            <property name="orientation">vertical</property>
+            <child>
+              <object class="GtkButton" id="button1">
+                <property name="label">gtk-help</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="button2">
+                <property name="label">gtk-close</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="-11">button1</action-widget>
+      <action-widget response="0">button2</action-widget>
+    </action-widgets>
+  </object>
+  <object class="GtkTextBuffer" id="ip_textbuffer"/>
+</interface>



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]