From e9fb2b739f7a375574bedb51d8cdb9df4e44a8fa Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 26 Feb 2010 18:23:28 +0100 Subject: [PATCH] Log viewer and bridge relay configuration UI --- src/status-area-applet-tor.vala | 240 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 239 insertions(+), 1 deletion(-) diff --git a/src/status-area-applet-tor.vala b/src/status-area-applet-tor.vala index 8461817..fc39bad 100644 --- a/src/status-area-applet-tor.vala +++ b/src/status-area-applet-tor.vala @@ -36,6 +36,7 @@ class TorStatusMenuItem : HD.StatusMenuItem { private const string GCONF_DIR_TOR = "/apps/maemo/tor"; private const string GCONF_KEY_TOR_ENABLED = GCONF_DIR_TOR + "/enabled"; + private const string GCONF_KEY_BRIDGES = GCONF_DIR_TOR + "/bridges"; private const string GCONF_DIR_PROXY_HTTP = "/system/http_proxy"; private const string GCONF_KEY_PROXY_HTTP_ENABLED = GCONF_DIR_PROXY_HTTP + "/use_http_proxy"; @@ -71,6 +72,7 @@ class TorStatusMenuItem : HD.StatusMenuItem { int tor_stdout; Pid polipo_pid; ProxyBackup backup; + string tor_log; /** * Update status area icon and status menu button value @@ -134,6 +136,7 @@ class TorStatusMenuItem : HD.StatusMenuItem { try { /* var status = */ source.read_line (out line, out length, null); + tor_log += line; if ("[notice]" in line) { if ("Bootstrapped 100%" in line) { tor_connected = true; @@ -186,10 +189,11 @@ class TorStatusMenuItem : HD.StatusMenuItem { * be set to true once Tor signals 100% */ } catch (SpawnError e) { - error ("Failed to spawn polipo and tor: %s", e.message); + Hildon.Banner.show_information (null, null, "DEBUG: Failed to spawn polipo and tor: %s".printf (e.message)); return; } + tor_log = ""; update_status (); } @@ -283,11 +287,210 @@ class TorStatusMenuItem : HD.StatusMenuItem { } /** + * Show the bridge relay configuration dialog + */ + private const int RESPONSE_NEW = 1; + private void bridges_clicked_cb () { + var dialog = new Gtk.Dialog (); + var content = (Gtk.VBox) dialog.get_content_area (); + content.set_size_request (-1, 5*70); + + dialog.set_title (_("Bridge relays")); + + var bridges = new SList (); + try { + bridges = gconf.get_list (GCONF_KEY_BRIDGES, GConf.ValueType.STRING); + } catch (Error e) { + error ("Error loading bridges: %s", e.message); + } + + var list_store = new Gtk.ListStore (1, typeof (string)); + Gtk.TreeIter iter; + foreach (string bridge in bridges) { + list_store.append (out iter); + list_store.@set (iter, 0, bridge); + } + + var pannable_area = new Hildon.PannableArea (); + var tree_view = new Gtk.TreeView.with_model (list_store); + var renderer = new Gtk.CellRendererText (); + var column = new Gtk.TreeViewColumn.with_attributes ("IP", renderer, "text", 0); + tree_view.append_column (column); + pannable_area.add (tree_view); + content.pack_start (pannable_area, true, true, 0); + + tree_view.row_activated.connect ((path, column) => { + bridge_edit_dialog (list_store, path); + }); + + dialog.add_button (_("New"), RESPONSE_NEW); + dialog.response.connect ((response_id) => { + if (response_id == RESPONSE_NEW) { + bridge_edit_dialog (list_store, null); + } + }); + + dialog.show_all (); + } + + /** + * Show the bridge relay edit dialog + */ + private const int RESPONSE_DELETE = 1; + private void bridge_edit_dialog (Gtk.ListStore store, Gtk.TreePath? path) { + var dialog = new Gtk.Dialog (); + var content = (Gtk.VBox) dialog.get_content_area (); + + if (path == null) + dialog.set_title (_("New bridge relay")); + else + dialog.set_title (_("Edit bridge relay")); + + var size_group = new Gtk.SizeGroup (Gtk.SizeGroupMode.HORIZONTAL); + + var hbox = new Gtk.HBox (false, Hildon.MARGIN_DOUBLE); + var label = new Gtk.Label (_("IP address")); + label.set_alignment (0, 0.5f); + size_group.add_widget (label); + hbox.pack_start (label, false, false, 0); + var ip_entry = new Hildon.Entry (Hildon.SizeType.FINGER_HEIGHT); + Hildon.gtk_entry_set_input_mode (ip_entry, Hildon.GtkInputMode.NUMERIC | + Hildon.GtkInputMode.SPECIAL); + hbox.pack_start (ip_entry, true, true, 0); + content.pack_start (hbox, false, false, 0); + + hbox = new Gtk.HBox (false, Hildon.MARGIN_DOUBLE); + label = new Gtk.Label (_("Port")); + label.set_alignment (0, 0.5f); + size_group.add_widget (label); + hbox.pack_start (label, false, false, 0); + var port_entry = new Hildon.Entry (Hildon.SizeType.FINGER_HEIGHT); + Hildon.gtk_entry_set_input_mode (port_entry, Hildon.GtkInputMode.NUMERIC); + hbox.pack_start (port_entry, true, true, 0); + content.pack_start (hbox, true, true, 0); + + hbox = new Gtk.HBox (false, Hildon.MARGIN_DOUBLE); + label = new Gtk.Label (_("Fingerprint")); + label.set_alignment (0, 0.5f); + size_group.add_widget (label); + hbox.pack_start (label, false, false, 0); + var fingerprint_entry = new Hildon.Entry (Hildon.SizeType.FINGER_HEIGHT); + Hildon.gtk_entry_set_input_mode (fingerprint_entry, Hildon.GtkInputMode.HEXA); + hbox.pack_start (fingerprint_entry, true, true, 0); + content.pack_start (hbox, true, true, 0); + + var iter = Gtk.TreeIter (); + if (path == null) { + port_entry.set_text ("443"); + } else if (store.get_iter (out iter, path)) { + string tmp; + store.@get (iter, 0, out tmp); + string[] ip_port = tmp.split (":"); + if (ip_port.length == 2) { + ip_entry.set_text (ip_port[0]); + port_entry.set_text (ip_port[1]); + } + + dialog.add_button (_("Delete"), RESPONSE_DELETE); + } + dialog.add_button (_("Save"), Gtk.ResponseType.OK); + dialog.response.connect ((response_id) => { + var bridges = new SList (); + + if (response_id == RESPONSE_DELETE) { + if (path != null) { + store.remove (iter); + string bridge; + if (store.get_iter_first (out iter)) do { + store.@get (iter, 0, out bridge); + bridges.append (bridge); + } while (store.iter_next (ref iter)); + gconf.set_list (GCONF_KEY_BRIDGES, GConf.ValueType.STRING, + bridges); + } + dialog.destroy (); + } + if (response_id == Gtk.ResponseType.OK) { + if (!is_valid_ip_address (ip_entry.get_text ())) { + Hildon.Banner.show_information (dialog, null, + _("Invalid IP address")); + return; + } + int port = port_entry.get_text ().to_int (); + if (port < 0 || port > 65565) { + Hildon.Banner.show_information (dialog, null, + _("Invalid port number")); + return; + } + if (path == null) { + store.append (out iter); + } + store.@set (iter, 0, "%s:%d".printf (ip_entry.get_text (), port)); + + bridges = gconf.get_list (GCONF_KEY_BRIDGES, GConf.ValueType.STRING); + if (path == null) { + bridges.append ("%s:%d".printf (ip_entry.get_text (), port)); + } else { + bridges = null; + string bridge; + if (store.get_iter_first (out iter)) do { + store.@get (iter, 0, out bridge); + bridges.append (bridge); + } while (store.iter_next (ref iter)); + } + gconf.set_list (GCONF_KEY_BRIDGES, GConf.ValueType.STRING, bridges); + + dialog.destroy (); + } + }); + + dialog.show_all (); + } + + /** + * Check whether the IP address consists of four numbers in the 0..255 range + */ + bool is_valid_ip_address (string address) { + string[] ip = address.split ("."); + + if (ip.length != 4) + return false; + + for (int i = 0; i < ip.length; i++) { + int n = ip[i].to_int (); + if (n < 0 || n > 255) + return false; + } + + return true; + } + + /** + * Show the Tor log dialog + */ + private void show_tor_log () { + var dialog = new Gtk.Dialog (); + var content = (Gtk.VBox) dialog.get_content_area (); + content.set_size_request (-1, 5*70); + + dialog.set_title (_("Log")); + + var pannable = new Hildon.PannableArea (); + var label = new Gtk.Label (tor_log); + pannable.add_with_viewport (label); + content.pack_start (pannable, true, true, 0); + + dialog.show_all (); + } + + /** * Callback for the status menu button clicked signal */ + private const int RESPONSE_LOG = 1; private void button_clicked_cb () { var dialog = new Gtk.Dialog (); var content = (Gtk.VBox) dialog.get_content_area (); + content.set_size_request (-1, 2*70); dialog.set_title (_("Tor: anonymity online")); @@ -296,8 +499,23 @@ class TorStatusMenuItem : HD.StatusMenuItem { check.set_active (tor_enabled); content.pack_start (check, true, true, 0); + var button = new Hildon.Button.with_text (Hildon.SizeType.FINGER_HEIGHT, + Hildon.ButtonArrangement.VERTICAL, + _("Bridge relays"), + get_bridge_list ()); + button.set_style (Hildon.ButtonStyle.PICKER); + button.set_alignment (0, 0.5f, 0, 0.5f); + button.clicked.connect (bridges_clicked_cb); + content.pack_start (button, true, true, 0); + + dialog.add_button (_("Log"), RESPONSE_LOG); + dialog.add_button (_("Save"), Gtk.ResponseType.ACCEPT); dialog.response.connect ((response_id) => { + if (response_id == RESPONSE_LOG) { + show_tor_log (); + return; + } if (response_id == Gtk.ResponseType.ACCEPT) { if (!tor_enabled && check.get_active ()) { tor_enabled = true; @@ -321,6 +539,26 @@ class TorStatusMenuItem : HD.StatusMenuItem { dialog.show_all (); } + private string get_bridge_list () { + string list = null; + var bridges = new SList (); + try { + bridges = gconf.get_list (GCONF_KEY_BRIDGES, GConf.ValueType.STRING); + } catch (Error e) { + error ("Error loading bridges: %s", e.message); + } + foreach (string bridge in bridges) { + if (list == null) + list = bridge; + else + list += ", " + bridge; + } + if (list == null) + list = _("None"); + + return list; + } + /** * Callback for the ConIc connection-event signal */ -- 1.7.9.5