1 /*
2  * vinagre-reverse-vnc-listener-dialog.c
3  * This file is part of vinagre
4  *
5  * Copyright (C) 2009 Jonh Wendell <wendell@bani.com.br>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include <config.h>
22 
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <net/if.h>
26 #include <arpa/inet.h>
27 #include <netinet/in.h>
28 
29 #ifdef HAVE_IFADDRS_H
30 #include <ifaddrs.h>
31 #else
32 #include "if/ifaddrs.h"
33 #endif
34 
35 #ifdef RFC2553
36 #define ADDR_FAMILY_MEMBER ss_family
37 #else
38 #define ADDR_FAMILY_MEMBER sa_family
39 #endif
40 
41 #include <string.h>
42 #include <glib/gi18n.h>
43 
44 #include "vinagre-prefs.h"
45 #include "vinagre-reverse-vnc-listener-dialog.h"
46 #include "vinagre-reverse-vnc-listener.h"
47 #include "vinagre-vala.h"
48 
49 typedef struct
50 {
51   GtkBuilder *xml;
52   GtkWidget *dialog;
53   GtkWidget *enable_reverse_check;
54   GtkWidget *always_enabled_check;
55   GtkWidget *port_label;
56   GtkWidget *connectivity_exp;
57   GtkTextBuffer *ip_buffer;
58   VinagreReverseVncListener *listener;
59 } VncListenDialog;
60 
61 static void
setup_ip_buffer(VncListenDialog * dialog)62 setup_ip_buffer (VncListenDialog *dialog)
63 {
64   char            buf[INET6_ADDRSTRLEN], *dup;
65   struct ifaddrs  *myaddrs, *ifa;
66   void            *sin;
67   GArray          *ipv4, *ipv6;
68   GString         *str;
69   int             i;
70 
71   ipv4 = g_array_new (FALSE, TRUE, sizeof (char *));
72   ipv6 = g_array_new (FALSE, TRUE, sizeof (char *));
73   str = g_string_new (NULL);
74 
75   getifaddrs (&myaddrs);
76   for (ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next)
77     {
78       if (ifa->ifa_addr == NULL || ifa->ifa_name == NULL || (ifa->ifa_flags & IFF_UP) == 0 || strncmp (ifa->ifa_name, "lo", 2) == 0)
79 	continue;
80 
81       switch (ifa->ifa_addr->ADDR_FAMILY_MEMBER)
82 	{
83 	  case AF_INET:
84 	    sin = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
85 	    inet_ntop (AF_INET, sin, buf, INET6_ADDRSTRLEN);
86 	    dup = g_strdup (buf);
87 	    g_array_append_val (ipv4, dup);
88 	    break;
89 
90 	  case AF_INET6:
91 	    sin = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
92 	    inet_ntop (AF_INET6, sin, buf, INET6_ADDRSTRLEN);
93 	    dup = g_strdup (buf);
94 	    g_array_append_val (ipv6, dup);
95 	    break;
96 	  default: continue;
97 	}
98     }
99 
100   if (ipv4->len > 0)
101     {
102       if (ipv6->len > 0)
103         g_string_append (str, _("IPv4:"));
104 
105       for (i = 0; i < ipv4->len; i++)
106 	{
107 	  dup = g_array_index (ipv4, char *, i);
108 	  g_string_append_printf (str, "\n%s", dup);
109 	  g_free (dup);
110 	}
111     }
112   if (ipv6->len > 0)
113     {
114       if (ipv4->len > 0)
115         g_string_append (str, _("\n\nIPv6:"));
116 
117       for (i = 0; i < ipv6->len; i++)
118 	{
119 	  dup = g_array_index (ipv6, char *, i);
120 	  g_string_append_printf (str, "\n%s", g_array_index (ipv6, char *, i));
121 	  g_free (dup);
122 	}
123     }
124 
125   gtk_text_buffer_set_text (dialog->ip_buffer, str->str, -1);
126 
127   freeifaddrs (myaddrs);
128   g_array_free (ipv4, TRUE);
129   g_array_free (ipv6, TRUE);
130   g_string_free (str, TRUE);
131 }
132 
133 static void
dialog_destroy(GtkWidget * widget,VncListenDialog * dialog)134 dialog_destroy (GtkWidget *widget,
135 		VncListenDialog *dialog)
136 {
137   g_object_unref (dialog->xml);
138   g_object_unref (dialog->listener);
139   g_slice_free (VncListenDialog, dialog);
140 }
141 
142 static void
dialog_response_handler(GtkDialog * widget,gint res_id,VncListenDialog * dialog)143 dialog_response_handler (GtkDialog       *widget,
144 			 gint            res_id,
145 			 VncListenDialog *dialog)
146 {
147   switch (res_id)
148     {
149       case GTK_RESPONSE_HELP:
150 	vinagre_utils_show_help (GTK_WINDOW (dialog->dialog),
151                                  "connect-reverse");
152 	break;
153 
154       default:
155 	gtk_widget_destroy (dialog->dialog);
156 	break;
157     }
158 }
159 
160 static void
update_ui_sensitivity(VncListenDialog * dialog)161 update_ui_sensitivity (VncListenDialog *dialog)
162 {
163   gboolean listening;
164   gchar *str;
165 
166   listening = vinagre_reverse_vnc_listener_is_listening (dialog->listener);
167 
168   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->enable_reverse_check),
169 				listening);
170   gtk_widget_set_sensitive (dialog->always_enabled_check, listening);
171   gtk_widget_set_sensitive (dialog->connectivity_exp, listening);
172 
173   if (listening)
174     {
175       str = g_strdup_printf (_("On the port %d"), vinagre_reverse_vnc_listener_get_port (dialog->listener));
176       gtk_label_set_label (GTK_LABEL (dialog->port_label), str);
177       g_free (str);
178     }
179   else
180     {
181       gtk_expander_set_expanded (GTK_EXPANDER (dialog->connectivity_exp), FALSE);
182     }
183 }
184 
185 static void
enable_reverse_toggled_cb(GtkToggleButton * button,VncListenDialog * dialog)186 enable_reverse_toggled_cb (GtkToggleButton *button, VncListenDialog *dialog)
187 {
188   if (gtk_toggle_button_get_active (button))
189     vinagre_reverse_vnc_listener_start (dialog->listener);
190   else
191     {
192       vinagre_reverse_vnc_listener_stop (dialog->listener);
193       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->always_enabled_check),
194 				    FALSE);
195     }
196 
197   update_ui_sensitivity (dialog);
198 }
199 
200 static void
always_enabled_toggled_cb(GtkToggleButton * button,VncListenDialog * dialog)201 always_enabled_toggled_cb (GtkToggleButton *button, VncListenDialog *dialog)
202 {
203   g_object_set (vinagre_prefs_get_default (),
204 		"always-enable-listening", gtk_toggle_button_get_active (button),
205 		NULL);
206 }
207 
208 void
vinagre_reverse_vnc_listener_dialog_show(GtkWindow * parent)209 vinagre_reverse_vnc_listener_dialog_show (GtkWindow *parent)
210 {
211   VncListenDialog *dialog;
212   GtkBuilder *xml;
213   gboolean always;
214 
215   xml = vinagre_utils_get_builder ();
216 
217   if (!xml)
218     return;
219 
220   dialog = g_slice_new (VncListenDialog);
221   dialog->xml = xml;
222 
223   dialog->listener = vinagre_reverse_vnc_listener_get_default ();
224 
225   dialog->dialog = GTK_WIDGET (gtk_builder_get_object (xml, "listener_dialog"));
226   g_assert (dialog->dialog != NULL);
227 
228   dialog->ip_buffer = GTK_TEXT_BUFFER (gtk_builder_get_object (xml, "ip_textbuffer"));
229   g_assert (dialog->ip_buffer != NULL);
230   setup_ip_buffer (dialog);
231 
232   dialog->enable_reverse_check = GTK_WIDGET (gtk_builder_get_object (xml, "enable_reverse_check"));
233   g_assert (dialog->enable_reverse_check != NULL);
234   g_signal_connect (dialog->enable_reverse_check,
235 		    "toggled",
236 		    G_CALLBACK (enable_reverse_toggled_cb),
237 		    dialog);
238 
239   dialog->always_enabled_check = GTK_WIDGET (gtk_builder_get_object (xml, "always_enabled_check"));
240   g_assert (dialog->always_enabled_check != NULL);
241   g_object_get (vinagre_prefs_get_default (),
242 		"always-enable-listening", &always,
243 		NULL);
244   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->always_enabled_check),
245 				always);
246   g_signal_connect (dialog->always_enabled_check,
247 		    "toggled",
248 		    G_CALLBACK (always_enabled_toggled_cb),
249 		    dialog);
250 
251   dialog->connectivity_exp = GTK_WIDGET (gtk_builder_get_object (xml, "connectivity_exp"));
252   g_assert (dialog->connectivity_exp != NULL);
253 
254   dialog->port_label = GTK_WIDGET (gtk_builder_get_object (xml, "port_label"));
255   g_assert (dialog->port_label != NULL);
256 
257   update_ui_sensitivity (dialog);
258 
259   g_signal_connect (dialog->dialog,
260 		    "destroy",
261 		    G_CALLBACK (dialog_destroy),
262 		    dialog);
263 
264   g_signal_connect (dialog->dialog,
265 		    "response",
266 		    G_CALLBACK (dialog_response_handler),
267 		    dialog);
268 
269   if (parent)
270     gtk_window_set_transient_for (GTK_WINDOW (dialog->dialog), parent);
271 
272   gtk_widget_show_all (dialog->dialog);
273 }
274