class BridgeDialog : Gtk.Dialog { private const string GCONF_DIR_TOR = "/apps/maemo/tor"; private const string GCONF_KEY_BRIDGES = GCONF_DIR_TOR + "/bridges"; GConf.Client gconf; Gtk.ListStore list_store; /** * Show the bridge relay configuration dialog */ private const int RESPONSE_NEW = 1; public BridgeDialog () { var content = (Gtk.VBox) get_content_area (); content.set_size_request (-1, 5*70); set_title (_("Bridge relays")); gconf = GConf.Client.get_default (); var bridges = new SList (); try { bridges = gconf.get_list (GCONF_KEY_BRIDGES, GConf.ValueType.STRING); } catch (Error e) { Hildon.Banner.show_information (null, null, "Error loading bridges: %s".printf (e.message)); } 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); }); add_button (_("New"), RESPONSE_NEW); response.connect ((response_id) => { if (response_id == RESPONSE_NEW) { bridge_edit_dialog (list_store, null); } }); content.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); ip_entry.set ("hildon-input-mode", 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); port_entry.set ("hildon-input-mode", 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); fingerprint_entry.set ("hildon-input-mode", 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) { Gtk.TreeIter iter2; store.get_iter (out iter2, path); store.remove (iter2); string bridge; if (store.get_iter_first (out iter2)) do { store.@get (iter2, 0, out bridge); bridges.append (bridge); } while (store.iter_next (ref iter2)); try { gconf.set_list (GCONF_KEY_BRIDGES, GConf.ValueType.STRING, bridges); } catch (Error e) { Hildon.Banner.show_information (dialog, null, "Failed to save bridge relay list: %s".printf (e.message)); } } 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; } Gtk.TreeIter iter2; if (path == null) { store.append (out iter2); } else { store.get_iter (out iter2, path); } store.@set (iter2, 0, "%s:%d".printf (ip_entry.get_text (), port)); try { bridges = gconf.get_list (GCONF_KEY_BRIDGES, GConf.ValueType.STRING); } catch (Error e) { Hildon.Banner.show_information (null, null, "Error loading bridges: %s".printf (e.message)); } if (path == null) { bridges.append ("%s:%d".printf (ip_entry.get_text (), port)); } else { bridges = null; string bridge; if (store.get_iter_first (out iter2)) do { store.@get (iter2, 0, out bridge); bridges.append (bridge); } while (store.iter_next (ref iter2)); } try { gconf.set_list (GCONF_KEY_BRIDGES, GConf.ValueType.STRING, bridges); } catch (Error e) { Hildon.Banner.show_information (dialog, null, "Failed to save bridge relay list: %s".printf (e.message)); } 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; } }