[vinagre] Add reverse-vnc plugin



commit c95743ebb3b8f2f7fc5bbcd431f96d28648b4945
Author: Jonh Wendell <jwendell gnome org>
Date:   Tue Aug 24 15:20:37 2010 -0300

    Add reverse-vnc plugin
    
    Moved this feature from vnc plugin into its own.

 configure.ac                                       |    1 +
 plugins/Makefile.am                                |    6 +-
 plugins/reverse-vnc/Makefile.am                    |   40 +++
 plugins/reverse-vnc/if/getifaddrs.c                |  217 +++++++++++++++
 plugins/reverse-vnc/if/ifaddrs.h                   |   48 ++++
 plugins/reverse-vnc/reverse-vnc.ui                 |  257 ++++++++++++++++++
 .../reverse-vnc.vinagre-plugin.desktop.in          |   10 +
 .../vinagre-reverse-vnc-listener-dialog.c          |  275 ++++++++++++++++++++
 .../vinagre-reverse-vnc-listener-dialog.h          |   31 +++
 plugins/reverse-vnc/vinagre-reverse-vnc-listener.c |  268 +++++++++++++++++++
 plugins/reverse-vnc/vinagre-reverse-vnc-listener.h |   62 +++++
 plugins/reverse-vnc/vinagre-reverse-vnc-plugin.c   |  239 +++++++++++++++++
 plugins/reverse-vnc/vinagre-reverse-vnc-plugin.h   |   64 +++++
 13 files changed, 1515 insertions(+), 3 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 24ede4f..da27744 100644
--- a/configure.ac
+++ b/configure.ac
@@ -311,6 +311,7 @@ plugins/Makefile
 plugins/vnc/Makefile
 plugins/ssh/Makefile
 plugins/rdp/Makefile
+plugins/reverse-vnc/Makefile
 vinagre/Makefile
 vinagre/view/Makefile
 ])
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 0018cee..0411bb4 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -1,10 +1,10 @@
 DIST_SUBDIRS =	\
   vnc		\
   ssh		\
-  rdp
+  rdp		\
+  reverse-vnc
 
-SUBDIRS = 		\
-  vnc
+SUBDIRS = vnc reverse-vnc
 
 if SSH
 SUBDIRS += ssh
diff --git a/plugins/reverse-vnc/Makefile.am b/plugins/reverse-vnc/Makefile.am
new file mode 100644
index 0000000..d5c1e5f
--- /dev/null
+++ b/plugins/reverse-vnc/Makefile.am
@@ -0,0 +1,40 @@
+# reverse-vnc plugin
+plugindir = $(VINAGRE_PLUGINS_LIBS_DIR)
+
+INCLUDES = \
+	-DDATADIR=\"$(VINAGRE_PLUGINS_DATA_DIR)/reverse-vnc\"	\
+	-I$(top_srcdir) 					\
+	$(VINAGRE_CFLAGS)					\
+	$(WARN_CFLAGS)						\
+	$(DISABLE_DEPRECATED_CFLAGS)
+
+plugin_LTLIBRARIES = libreversevnc.la
+
+libreversevnc_la_SOURCES = 						\
+	vinagre-reverse-vnc-plugin.h vinagre-reverse-vnc-plugin.c	\
+	vinagre-reverse-vnc-listener.h vinagre-reverse-vnc-listener.c	\
+	vinagre-reverse-vnc-listener-dialog.h vinagre-reverse-vnc-listener-dialog.c
+
+if SELF_IFADDRS
+libreversevnc_la_SOURCES += if/ifaddrs.h if/getifaddrs.c
+endif
+
+libreversevnc_la_LDFLAGS = $(PLUGIN_LIBTOOL_FLAGS)
+libreversevnc_la_LIBADD  = $(VNC_LIBS)
+
+uidir = $(VINAGRE_PLUGINS_DATA_DIR)/reverse-vnc
+ui_DATA = reverse-vnc.ui
+
+plugin_in_files = reverse-vnc.vinagre-plugin.desktop.in
+
+reverse-vnc.vinagre-plugin: reverse-vnc.vinagre-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(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 = $(ui_DATA) $(plugin_in_files)
+
+CLEANFILES = $(plugin_DATA)
+DISTCLEANFILES = $(plugin_DATA)
+
+
+-include $(top_srcdir)/git.mk
diff --git a/plugins/reverse-vnc/if/getifaddrs.c b/plugins/reverse-vnc/if/getifaddrs.c
new file mode 100644
index 0000000..e6d4d9b
--- /dev/null
+++ b/plugins/reverse-vnc/if/getifaddrs.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2006 WIDE Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/sockio.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#include "ifaddrs.h"
+
+static int
+get_lifreq(int fd, struct lifreq **ifr_ret)
+{
+	struct lifnum lifn;
+	struct lifconf lifc;
+	struct lifreq *lifrp;
+
+	lifn.lifn_family = AF_UNSPEC;
+	lifn.lifn_flags = 0;
+	if (ioctl(fd, SIOCGLIFNUM, &lifn) == -1)
+		lifn.lifn_count = 16;
+	else
+		lifn.lifn_count += 16;
+
+	for (;;) {
+		lifc.lifc_len = lifn.lifn_count * sizeof (*lifrp);
+		lifrp = malloc(lifc.lifc_len);
+		if (lifrp == NULL)
+			return (-1);
+
+		lifc.lifc_family = AF_UNSPEC;
+		lifc.lifc_flags = 0;
+		lifc.lifc_buf = (char *)lifrp;
+		if (ioctl(fd, SIOCGLIFCONF, &lifc) == -1) {
+			free(lifrp);
+			if (errno == EINVAL) {
+				lifn.lifn_count <<= 1;
+				continue;
+			}
+			(void) close(fd);
+			return (-1);
+		}
+		if (lifc.lifc_len < (lifn.lifn_count - 1) * sizeof (*lifrp))
+			break;
+		free(lifrp);
+		lifn.lifn_count <<= 1;
+	}
+
+	*ifr_ret = lifrp;
+
+	return (lifc.lifc_len / sizeof (*lifrp));
+}
+
+static size_t
+nbytes(const struct lifreq *lifrp, int nlif, size_t socklen)
+{
+	size_t len = 0;
+	size_t slen;
+
+	while (nlif > 0) {
+		slen = strlen(lifrp->lifr_name) + 1;
+		len += sizeof (struct ifaddrs) + ((slen + 3) & ~3);
+		len += 3 * socklen;
+		lifrp++;
+		nlif--;
+	}
+	return (len);
+}
+
+static struct sockaddr *
+addrcpy(struct sockaddr_storage *addr, char **bufp)
+{
+	char *buf = *bufp;
+	size_t len;
+
+	len = addr->ss_family == AF_INET ? sizeof (struct sockaddr_in) :
+	    sizeof (struct sockaddr_in6);
+	(void) memcpy(buf, addr, len);
+	*bufp = buf + len;
+	return ((struct sockaddr *)buf);
+}
+
+static int
+populate(struct ifaddrs *ifa, int fd, struct lifreq *lifrp, int nlif, int af,
+    char **bufp)
+{
+	char *buf = *bufp;
+	size_t slen;
+
+	while (nlif > 0) {
+		ifa->ifa_next = (nlif > 1) ? ifa + 1 : NULL;
+		(void) strcpy(ifa->ifa_name = buf, lifrp->lifr_name);
+		slen = strlen(lifrp->lifr_name) + 1;
+		buf += (slen + 3) & ~3;
+		if (ioctl(fd, SIOCGLIFFLAGS, lifrp) == -1)
+			ifa->ifa_flags = 0;
+		else
+			ifa->ifa_flags = lifrp->lifr_flags;
+		if (ioctl(fd, SIOCGLIFADDR, lifrp) == -1)
+			ifa->ifa_addr = NULL;
+		else
+			ifa->ifa_addr = addrcpy(&lifrp->lifr_addr, &buf);
+		if (ioctl(fd, SIOCGLIFNETMASK, lifrp) == -1)
+			ifa->ifa_netmask = NULL;
+		else
+			ifa->ifa_netmask = addrcpy(&lifrp->lifr_addr, &buf);
+		if (ifa->ifa_flags & IFF_POINTOPOINT) {
+			if (ioctl(fd, SIOCGLIFDSTADDR, lifrp) == -1)
+				ifa->ifa_dstaddr = NULL;
+			else
+				ifa->ifa_dstaddr =
+				    addrcpy(&lifrp->lifr_dstaddr, &buf);
+		} else if (ifa->ifa_flags & IFF_BROADCAST) {
+			if (ioctl(fd, SIOCGLIFBRDADDR, lifrp) == -1)
+				ifa->ifa_broadaddr = NULL;
+			else
+				ifa->ifa_broadaddr =
+				    addrcpy(&lifrp->lifr_broadaddr, &buf);
+		} else {
+			ifa->ifa_dstaddr = NULL;
+		}
+
+		ifa++;
+		nlif--;
+		lifrp++;
+	}
+	*bufp = buf;
+	return (0);
+}
+
+int
+getifaddrs(struct ifaddrs **ifap)
+{
+	int fd4, fd6;
+	int nif4, nif6 = 0;
+	struct lifreq *ifr4 = NULL;
+	struct lifreq *ifr6 = NULL;
+	struct ifaddrs *ifa = NULL;
+	char *buf;
+
+	if ((fd4 = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
+		return (-1);
+	if ((fd6 = socket(AF_INET6, SOCK_DGRAM, 0)) == -1 &&
+	    errno != EAFNOSUPPORT) {
+		(void) close(fd4);
+		return (-1);
+	}
+
+	if ((nif4 = get_lifreq(fd4, &ifr4)) == -1 ||
+	    (fd6 != -1 && (nif6 = get_lifreq(fd6, &ifr6)) == -1))
+		goto failure;
+
+	if (nif4 == 0 && nif6 == 0) {
+		*ifap = NULL;
+		return (0);
+	}
+
+	ifa = malloc(nbytes(ifr4, nif4, sizeof (struct sockaddr_in)) +
+	    nbytes(ifr6, nif6, sizeof (struct sockaddr_in6)));
+	if (ifa == NULL)
+		goto failure;
+
+	buf = (char *)(ifa + nif4 + nif6);
+
+	if (populate(ifa, fd4, ifr4, nif4, AF_INET, &buf) == -1)
+		goto failure;
+	if (nif4 > 0 && nif6 > 0)
+		ifa[nif4 - 1].ifa_next = ifa + nif4;
+	if (populate(ifa + nif4, fd6, ifr6, nif6, AF_INET6, &buf) == -1)
+		goto failure;
+
+	*ifap = ifa;
+	return (0);
+
+failure:
+	free(ifa);
+	(void) close(fd4);
+	if (fd6 != -1)
+		(void) close(fd6);
+	free(ifr4);
+	free(ifr6);
+	return (-1);
+}
+
+void
+freeifaddrs(struct ifaddrs *ifa)
+{
+	free(ifa);
+}
diff --git a/plugins/reverse-vnc/if/ifaddrs.h b/plugins/reverse-vnc/if/ifaddrs.h
new file mode 100644
index 0000000..5686143
--- /dev/null
+++ b/plugins/reverse-vnc/if/ifaddrs.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2006 WIDE Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __IFADDRS_H
+#define __IFADDRS_H
+
+#include <sys/types.h>
+
+#undef ifa_broadaddr
+#undef ifa_dstaddr
+struct ifaddrs {
+	struct ifaddrs	*ifa_next;	/* Pointer to next struct */
+	char		*ifa_name;	/* Interface name */
+	uint64_t	ifa_flags;	/* Interface flags */
+	struct sockaddr	*ifa_addr;	/* Interface address */
+	struct sockaddr	*ifa_netmask;	/* Interface netmask */
+	struct sockaddr	*ifa_dstaddr;	/* P2P interface destination */
+};
+#define	ifa_broadaddr	ifa_dstaddr
+
+extern int getifaddrs(struct ifaddrs **);
+extern void freeifaddrs(struct ifaddrs *);
+#endif
diff --git a/plugins/reverse-vnc/reverse-vnc.ui b/plugins/reverse-vnc/reverse-vnc.ui
new file mode 100644
index 0000000..e2e459e
--- /dev/null
+++ b/plugins/reverse-vnc/reverse-vnc.ui
@@ -0,0 +1,257 @@
+<?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" comments="Translators: this is the reverse connection mode. &quot;Always enabled&quot; means it will be enabled by default in the program startup. You can see this string in the dialog Machine-&gt;Reverse connections.">_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>
+            <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>
diff --git a/plugins/reverse-vnc/reverse-vnc.vinagre-plugin.desktop.in b/plugins/reverse-vnc/reverse-vnc.vinagre-plugin.desktop.in
new file mode 100644
index 0000000..52851ff
--- /dev/null
+++ b/plugins/reverse-vnc/reverse-vnc.vinagre-plugin.desktop.in
@@ -0,0 +1,10 @@
+[Vinagre Plugin]
+Module=reversevnc
+IAge=1
+_Name=Reverse VNC
+_Description=Allows reverse VNC connections
+Authors=Jonh Wendell
+Copyright=Copyright © 2009-2010 Jonh Wendell
+Website=http://www.bani.com.br
+Version=1.0
+Depends=vnc
diff --git a/plugins/reverse-vnc/vinagre-reverse-vnc-listener-dialog.c b/plugins/reverse-vnc/vinagre-reverse-vnc-listener-dialog.c
new file mode 100644
index 0000000..e4d8a12
--- /dev/null
+++ b/plugins/reverse-vnc/vinagre-reverse-vnc-listener-dialog.c
@@ -0,0 +1,275 @@
+/*
+ * vinagre-reverse-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 <config.h>
+
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#ifdef HAVE_IFADDRS_H
+#include <ifaddrs.h>
+#else
+#include "if/ifaddrs.h"
+#endif
+
+#ifdef RFC2553
+#define ADDR_FAMILY_MEMBER ss_family
+#else
+#define ADDR_FAMILY_MEMBER sa_family
+#endif
+
+#include <string.h>
+#include <glib/gi18n.h>
+
+#include <vinagre/vinagre-utils.h>
+#include <vinagre/vinagre-prefs.h>
+#include "vinagre-reverse-vnc-listener-dialog.h"
+#include "vinagre-reverse-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;
+  VinagreReverseVncListener *listener;
+} 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->ADDR_FAMILY_MEMBER)
+	{
+	  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_object_unref (dialog->listener);
+  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;
+
+  listening = vinagre_reverse_vnc_listener_is_listening (dialog->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_reverse_vnc_listener_get_port (dialog->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)
+{
+  if (gtk_toggle_button_get_active (button))
+    vinagre_reverse_vnc_listener_start (dialog->listener);
+  else
+    {
+      vinagre_reverse_vnc_listener_stop (dialog->listener);
+      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->always_enabled_check),
+				    FALSE);
+    }
+
+  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_reverse_vnc_listener_dialog_show (GtkWindow *parent)
+{
+  VncListenDialog *dialog;
+  GtkBuilder *xml;
+  gboolean always;
+  gchar *filename;
+
+  filename = g_build_filename (DATADIR, "reverse-vnc.ui", NULL);
+
+  xml = vinagre_utils_get_builder (filename);
+  g_free (filename);
+  if (!xml)
+    return;
+
+  dialog = g_slice_new (VncListenDialog);
+  dialog->xml = xml;
+
+  dialog->listener = vinagre_reverse_vnc_listener_get_default ();
+
+  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 (parent)
+    gtk_window_set_transient_for (GTK_WINDOW (dialog->dialog), parent);
+
+  gtk_widget_show_all (dialog->dialog);
+}
+
+/* vim: set ts=8: */
diff --git a/plugins/reverse-vnc/vinagre-reverse-vnc-listener-dialog.h b/plugins/reverse-vnc/vinagre-reverse-vnc-listener-dialog.h
new file mode 100644
index 0000000..b779da1
--- /dev/null
+++ b/plugins/reverse-vnc/vinagre-reverse-vnc-listener-dialog.h
@@ -0,0 +1,31 @@
+/*
+ * vinagre-reverse-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_REVERSE_VNC_LISTENER_DIALOG_H__
+#define __VINAGRE_REVERSE_VNC_LISTENER_DIALOG_H__
+
+G_BEGIN_DECLS
+
+void vinagre_reverse_vnc_listener_dialog_show (GtkWindow *parent);
+
+G_END_DECLS
+
+#endif /* __VINAGRE_REVERSE_VNC_LISTENER_DIALOG_H__ */
+/* vim: set ts=8: */
diff --git a/plugins/reverse-vnc/vinagre-reverse-vnc-listener.c b/plugins/reverse-vnc/vinagre-reverse-vnc-listener.c
new file mode 100644
index 0000000..ba3997f
--- /dev/null
+++ b/plugins/reverse-vnc/vinagre-reverse-vnc-listener.c
@@ -0,0 +1,268 @@
+/*
+ * vinagre-reverse-vnc-listener.c
+ * This file is part of vinagre
+ *
+ * Copyright (C) 2009-2010 - 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-reverse-vnc-listener.h"
+#include "../vnc/vinagre-vnc-connection.h"
+
+struct _VinagreReverseVncListenerPrivate
+{
+  int server_sock;
+  GIOChannel *io;
+  gboolean listening;
+  guint io_uid;
+  gint port;
+};
+
+enum
+{
+  PROP_0,
+  PROP_LISTENING,
+  PROP_PORT
+};
+
+static VinagreReverseVncListener *listener_singleton = NULL;
+
+#define VINAGRE_REVERSE_VNC_LISTENER_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), VINAGRE_TYPE_REVERSE_VNC_LISTENER, VinagreReverseVncListenerPrivate))
+G_DEFINE_TYPE (VinagreReverseVncListener, vinagre_reverse_vnc_listener, G_TYPE_OBJECT);
+
+static void
+vinagre_reverse_vnc_listener_init (VinagreReverseVncListener *listener)
+{
+  listener->priv = G_TYPE_INSTANCE_GET_PRIVATE (listener, VINAGRE_TYPE_REVERSE_VNC_LISTENER, VinagreReverseVncListenerPrivate);
+
+  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_reverse_vnc_listener_dispose (GObject *object)
+{
+  VinagreReverseVncListener *listener = VINAGRE_REVERSE_VNC_LISTENER (object);
+
+  vinagre_reverse_vnc_listener_stop (listener);
+
+  G_OBJECT_CLASS (vinagre_reverse_vnc_listener_parent_class)->dispose (object);
+}
+
+static void
+vinagre_reverse_vnc_listener_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+  VinagreReverseVncListener *listener;
+
+  g_return_if_fail (VINAGRE_IS_REVERSE_VNC_LISTENER (object));
+
+  listener = VINAGRE_REVERSE_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_reverse_vnc_listener_get_port (listener));
+	break;
+
+      default:
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	break;
+    }
+}
+
+static void
+vinagre_reverse_vnc_listener_class_init (VinagreReverseVncListenerClass *klass)
+{
+  GObjectClass* object_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (VinagreReverseVncListenerPrivate));
+
+  object_class->dispose = vinagre_reverse_vnc_listener_dispose;
+  object_class->get_property = vinagre_reverse_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));
+
+}
+
+VinagreReverseVncListener *
+vinagre_reverse_vnc_listener_get_default (void)
+{
+  if (G_UNLIKELY (!listener_singleton))
+    {
+      listener_singleton = VINAGRE_REVERSE_VNC_LISTENER (g_object_new (VINAGRE_TYPE_REVERSE_VNC_LISTENER, NULL));
+      g_object_add_weak_pointer (G_OBJECT (listener_singleton), (gpointer *)&listener_singleton);
+      return listener_singleton;
+    }
+
+  return g_object_ref (listener_singleton);
+}
+
+static gboolean
+incoming (GIOChannel *source, GIOCondition condition, VinagreReverseVncListener *listener)
+{
+  VinagreConnection *conn;
+  GtkWindow *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 = gtk_application_get_window (GTK_APPLICATION (g_application_get_instance ()));
+  if (!window)
+    {
+      g_warning (_("Incoming VNC connection arrived but there is no 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, VINAGRE_WINDOW (window));
+
+  return TRUE;
+}
+
+void
+vinagre_reverse_vnc_listener_start (VinagreReverseVncListener *listener)
+{
+  struct sockaddr_in6 server_addr;
+  int port;
+
+  g_return_if_fail (VINAGRE_IS_REVERSE_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_reverse_vnc_listener_stop (VinagreReverseVncListener *listener)
+{
+  g_return_if_fail (VINAGRE_IS_REVERSE_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_reverse_vnc_listener_is_listening (VinagreReverseVncListener *listener)
+{
+  g_return_val_if_fail (VINAGRE_IS_REVERSE_VNC_LISTENER (listener), FALSE);
+
+  return listener->priv->listening;
+}
+
+gint
+vinagre_reverse_vnc_listener_get_port (VinagreReverseVncListener *listener)
+{
+  g_return_val_if_fail (VINAGRE_IS_REVERSE_VNC_LISTENER (listener), 0);
+
+  return listener->priv->listening ? listener->priv->port : 0;
+}
+
+/* vim: set ts=8: */
diff --git a/plugins/reverse-vnc/vinagre-reverse-vnc-listener.h b/plugins/reverse-vnc/vinagre-reverse-vnc-listener.h
new file mode 100644
index 0000000..e84b012
--- /dev/null
+++ b/plugins/reverse-vnc/vinagre-reverse-vnc-listener.h
@@ -0,0 +1,62 @@
+/*
+ * vinagre-reverse-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_REVERSE_VNC_LISTENER_H__
+#define __VINAGRE_REVERSE_VNC_LISTENER_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define VINAGRE_TYPE_REVERSE_VNC_LISTENER             (vinagre_reverse_vnc_listener_get_type ())
+#define VINAGRE_REVERSE_VNC_LISTENER(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), VINAGRE_TYPE_REVERSE_VNC_LISTENER, VinagreReverseVncListener))
+#define VINAGRE_REVERSE_VNC_LISTENER_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), VINAGRE_TYPE_REVERSE_VNC_LISTENER, VinagreReverseVncListenerClass))
+#define VINAGRE_IS_REVERSE_VNC_LISTENER(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VINAGRE_TYPE_REVERSE_VNC_LISTENER))
+#define VINAGRE_IS_REVERSE_VNC_LISTENER_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), VINAGRE_TYPE_REVERSE_VNC_LISTENER))
+#define VINAGRE_REVERSE_VNC_LISTENER_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), VINAGRE_TYPE_REVERSE_VNC_LISTENER, VinagreReverseVncListenerClass))
+
+typedef struct _VinagreReverseVncListenerClass   VinagreReverseVncListenerClass;
+typedef struct _VinagreReverseVncListener        VinagreReverseVncListener;
+typedef struct _VinagreReverseVncListenerPrivate VinagreReverseVncListenerPrivate;
+
+struct _VinagreReverseVncListenerClass
+{
+  GObjectClass parent_class;
+};
+
+struct _VinagreReverseVncListener
+{
+  GObject parent_instance;
+  VinagreReverseVncListenerPrivate *priv;
+};
+
+
+GType vinagre_reverse_vnc_listener_get_type (void) G_GNUC_CONST;
+
+VinagreReverseVncListener*	vinagre_reverse_vnc_listener_get_default (void);
+void			vinagre_reverse_vnc_listener_start (VinagreReverseVncListener *listener);
+void			vinagre_reverse_vnc_listener_stop  (VinagreReverseVncListener *listener);
+gboolean		vinagre_reverse_vnc_listener_is_listening (VinagreReverseVncListener *listener);
+gint			vinagre_reverse_vnc_listener_get_port (VinagreReverseVncListener *listener);
+
+G_END_DECLS
+
+#endif /* __VINAGRE_REVERSE_VNC_LISTENER_H__  */
+/* vim: set ts=8: */
diff --git a/plugins/reverse-vnc/vinagre-reverse-vnc-plugin.c b/plugins/reverse-vnc/vinagre-reverse-vnc-plugin.c
new file mode 100644
index 0000000..4093236
--- /dev/null
+++ b/plugins/reverse-vnc/vinagre-reverse-vnc-plugin.c
@@ -0,0 +1,239 @@
+/*
+ * vinagre-reverse-vnc-plugin.c
+ * This file is part of vinagre
+ *
+ * Copyright (C) 2009-2010 Jonh Wendell <wendell bani com br>
+ * 
+ * vinagre-reverse-vnc-plugin.c 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.
+ * 
+ * vinagre-reverse-vnc-plugin.c 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/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n-lib.h>
+#include <gmodule.h>
+
+#include <vinagre/vinagre-prefs.h>
+
+#include "vinagre-reverse-vnc-plugin.h"
+#include "vinagre-reverse-vnc-listener-dialog.h"
+#include "vinagre-reverse-vnc-listener.h"
+
+#define WINDOW_DATA_KEY "VinagreVNCPluginWindowData"
+
+static void vnc_activatable_iface_init (PeasActivatableInterface *iface);
+G_DEFINE_DYNAMIC_TYPE_EXTENDED (VinagreReverseVncPlugin,
+				vinagre_reverse_vnc_plugin,
+				PEAS_TYPE_EXTENSION_BASE,
+				0,
+				G_IMPLEMENT_INTERFACE_DYNAMIC (PEAS_TYPE_ACTIVATABLE,
+							       vnc_activatable_iface_init))
+
+struct _VinagreReverseVncPluginPrivate
+{
+  VinagreWindow *window;
+  GtkActionGroup *ui_action_group;
+  guint ui_id;
+  VinagreReverseVncListener *listener;
+};
+
+enum
+{
+  PROP_0,
+  PROP_OBJECT
+};
+
+static void
+listening_cb (GtkAction *action, VinagreReverseVncPlugin *plugin)
+{
+  vinagre_reverse_vnc_listener_dialog_show (GTK_WINDOW (plugin->priv->window));
+}
+
+static GtkActionEntry action_entries[] =
+{
+  { "VNCListener",
+    NULL,
+    /* Translators: "Reverse" here is an adjective, not a verb. */
+    N_("_Reverse Connections..."),
+    NULL,
+    N_("Configure incoming VNC connections"),
+    G_CALLBACK (listening_cb)
+  }
+};
+
+static void
+impl_activate (PeasActivatable *activatable)
+{
+  VinagreReverseVncPluginPrivate *priv;
+  GtkUIManager *manager;
+  gboolean always;
+
+  priv = VINAGRE_REVERSE_VNC_PLUGIN (activatable)->priv;
+
+  manager = vinagre_window_get_ui_manager (priv->window);
+
+  priv->ui_action_group = gtk_action_group_new ("VinagreReverseVNCPluginActions");
+  gtk_action_group_set_translation_domain (priv->ui_action_group, GETTEXT_PACKAGE);
+  gtk_action_group_add_actions (priv->ui_action_group,
+				action_entries,
+				G_N_ELEMENTS (action_entries),
+				activatable);
+  gtk_ui_manager_insert_action_group (manager,
+				      priv->ui_action_group,
+				      -1);
+
+  priv->ui_id = gtk_ui_manager_new_merge_id (manager);
+  gtk_ui_manager_add_ui (manager,
+			 priv->ui_id,
+			 "/MenuBar/MachineMenu/MachineOps_1",
+			 "VNCListener",
+			 "VNCListener",
+			 GTK_UI_MANAGER_AUTO,
+			 TRUE);
+
+  g_object_get (vinagre_prefs_get_default (),
+		"always-enable-listening", &always,
+		NULL);
+  if (always)
+    vinagre_reverse_vnc_listener_start (priv->listener);
+}
+
+static void
+impl_deactivate (PeasActivatable *activatable)
+{
+  VinagreReverseVncPluginPrivate *priv;
+  GtkUIManager *manager;
+
+  priv = VINAGRE_REVERSE_VNC_PLUGIN (activatable)->priv;
+
+  manager = vinagre_window_get_ui_manager (priv->window);
+
+  gtk_ui_manager_remove_ui (manager, priv->ui_id);
+  gtk_ui_manager_remove_action_group (manager, priv->ui_action_group);
+}
+
+static void
+vinagre_reverse_vnc_plugin_set_property (GObject      *object,
+					 guint         prop_id,
+					 const GValue *value,
+					 GParamSpec   *pspec)
+{
+  VinagreReverseVncPlugin *plugin = VINAGRE_REVERSE_VNC_PLUGIN (object);
+
+  switch (prop_id)
+    {
+      case PROP_OBJECT:
+	plugin->priv->window = VINAGRE_WINDOW (g_value_dup_object (value));
+	break;
+
+      default:
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	break;
+    }
+}
+
+static void
+vinagre_reverse_vnc_plugin_get_property (GObject    *object,
+					 guint       prop_id,
+					 GValue     *value,
+					 GParamSpec *pspec)
+{
+  VinagreReverseVncPlugin *plugin = VINAGRE_REVERSE_VNC_PLUGIN (object);
+
+  switch (prop_id)
+    {
+      case PROP_OBJECT:
+	g_value_set_object (value, plugin->priv->window);
+	break;
+
+      default:
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	break;
+    }
+}
+
+static void
+vinagre_reverse_vnc_plugin_dispose (GObject *object)
+{
+  VinagreReverseVncPluginPrivate *priv = VINAGRE_REVERSE_VNC_PLUGIN (object)->priv;
+
+  if (priv->ui_action_group)
+    {
+      g_object_unref (priv->ui_action_group);
+      priv->ui_action_group = NULL;
+    }
+
+  if (priv->window != NULL)
+    {
+      g_object_unref (priv->window);
+      priv->window = NULL;
+    }
+
+  if (priv->listener)
+    {
+      g_object_unref (priv->listener);
+      priv->listener = NULL;
+    }
+
+  G_OBJECT_CLASS (vinagre_reverse_vnc_plugin_parent_class)->dispose (object);
+}
+
+static void
+vinagre_reverse_vnc_plugin_class_init (VinagreReverseVncPluginClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->dispose = vinagre_reverse_vnc_plugin_dispose;
+  object_class->set_property = vinagre_reverse_vnc_plugin_set_property;
+  object_class->get_property = vinagre_reverse_vnc_plugin_get_property;
+
+  g_object_class_override_property (object_class, PROP_OBJECT, "object");
+
+  g_type_class_add_private (klass, sizeof (VinagreReverseVncPluginPrivate));
+
+}
+
+static void
+vinagre_reverse_vnc_plugin_class_finalize (VinagreReverseVncPluginClass *klass)
+{
+}
+
+static void
+vinagre_reverse_vnc_plugin_init (VinagreReverseVncPlugin *plugin)
+{
+  plugin->priv = G_TYPE_INSTANCE_GET_PRIVATE (plugin,
+					      VINAGRE_TYPE_REVERSE_VNC_PLUGIN,
+					      VinagreReverseVncPluginPrivate);
+
+  plugin->priv->listener = vinagre_reverse_vnc_listener_get_default ();
+}
+
+static void
+vnc_activatable_iface_init (PeasActivatableInterface *iface)
+{
+  iface->activate   = impl_activate;
+  iface->deactivate = impl_deactivate;
+}
+
+G_MODULE_EXPORT void
+peas_register_types (PeasObjectModule *module)
+{
+  vinagre_reverse_vnc_plugin_register_type (G_TYPE_MODULE (module));
+  peas_object_module_register_extension_type (module,
+					      PEAS_TYPE_ACTIVATABLE,
+					      VINAGRE_TYPE_REVERSE_VNC_PLUGIN);
+}
+
+/* vim: set ts=8: */
diff --git a/plugins/reverse-vnc/vinagre-reverse-vnc-plugin.h b/plugins/reverse-vnc/vinagre-reverse-vnc-plugin.h
new file mode 100644
index 0000000..c5e3684
--- /dev/null
+++ b/plugins/reverse-vnc/vinagre-reverse-vnc-plugin.h
@@ -0,0 +1,64 @@
+/*
+ * vinagre-reverse-vnc-plugin.h
+ * This file is part of vinagre
+ *
+ * Copyright (C) 2009 Jorge Pereira <jorge jorgepereira com br>
+ * Copyright (C) 2009-2010 Jonh Wendell <wendell bani com br>
+ * 
+ * vinagre-reverse-vnc-plugin.h 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.
+ * 
+ * vinagre-reverse-vnc-plugin.h 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_REVERSE_VNC_PLUGIN_H__
+#define __VINAGRE_REVERSE_VNC_PLUGIN_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libpeas/peas.h>
+
+G_BEGIN_DECLS
+
+/*
+ * Type checking and casting macros
+ */
+#define VINAGRE_TYPE_REVERSE_VNC_PLUGIN                 (vinagre_reverse_vnc_plugin_get_type ())
+#define VINAGRE_REVERSE_VNC_PLUGIN(o)                   (G_TYPE_CHECK_INSTANCE_CAST ((o), VINAGRE_TYPE_REVERSE_VNC_PLUGIN, VinagreReverseVncPlugin))
+#define VINAGRE_REVERSE_VNC_PLUGIN_CLASS(k)             (G_TYPE_CHECK_CLASS_CAST((k), VINAGRE_TYPE_REVERSE_VNC_PLUGIN, VinagreReverseVncPluginClass))
+#define VINAGRE_IS_REVERSE_VNC_PLUGIN(o)                (G_TYPE_CHECK_INSTANCE_TYPE ((o), VINAGRE_TYPE_REVERSE_VNC_PLUGIN))
+#define VINAGRE_IS_REVERSE_VNC_PLUGIN_CLASS(k)          (G_TYPE_CHECK_CLASS_TYPE ((k), VINAGRE_TYPE_REVERSE_VNC_PLUGIN))
+#define VINAGRE_REVERSE_VNC_PLUGIN_GET_CLASS(o)         (G_TYPE_INSTANCE_GET_CLASS ((o), VINAGRE_TYPE_REVERSE_VNC_PLUGIN, VinagreReverseVncPluginClass))
+
+typedef struct _VinagreReverseVncPlugin		VinagreReverseVncPlugin;
+typedef struct _VinagreReverseVncPluginClass	VinagreReverseVncPluginClass;
+typedef struct _VinagreReverseVncPluginPrivate	VinagreReverseVncPluginPrivate;
+
+struct _VinagreReverseVncPlugin
+{
+  PeasExtensionBase parent_instance;
+  VinagreReverseVncPluginPrivate *priv;
+};
+
+struct _VinagreReverseVncPluginClass
+{
+  PeasExtensionBaseClass parent_class;
+};
+
+GType vinagre_reverse_vnc_plugin_get_type (void) G_GNUC_CONST;
+
+G_MODULE_EXPORT void peas_register_types (PeasObjectModule *module);
+
+G_END_DECLS
+
+#endif /* __VINAGRE_REVERSE_VNC_PLUGIN_H__ */
+
+/* vim: set ts=8: */



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