commit 5ed6caafc77f43a389c7fcafa829803983c490a5 Author: Kamran Riaz Khan krkhan@inspirated.com Date: Sun Jun 5 21:10:48 2011 +0500
Skeletal Gtk+ UI.
Launched via -g or --gtk command-line flag. Rudimentary usage of torTools to display Tor pid. --- src/gui/__init__.py | 6 + src/gui/arm.xml | 628 +++++++++++++++++++++++++++++++++++++++++++++++++ src/gui/controller.py | 85 +++++++ src/starter.py | 13 +- 4 files changed, 729 insertions(+), 3 deletions(-)
diff --git a/src/gui/__init__.py b/src/gui/__init__.py new file mode 100644 index 0000000..f461b3e --- /dev/null +++ b/src/gui/__init__.py @@ -0,0 +1,6 @@ +""" +Panels, popups, and handlers comprising the arm user interface. +""" + +__all__ = ["controller"] + diff --git a/src/gui/arm.xml b/src/gui/arm.xml new file mode 100644 index 0000000..49ffc89 --- /dev/null +++ b/src/gui/arm.xml @@ -0,0 +1,628 @@ +<?xml version="1.0"?> +<interface> + <requires lib="gtk+" version="2.16"/> + <!-- interface-naming-policy project-wide --> + <object class="GtkListStore" id="liststore_sticky"> + <columns> + <!-- column-name gchararray1 --> + <column type="gchararray"/> + <!-- column-name gchararray2 --> + <column type="gchararray"/> + <!-- column-name gchararray3 --> + <column type="gchararray"/> + <!-- column-name gchararray4 --> + <column type="gchararray"/> + </columns> + <data> + <row> + <col id="0" translatable="yes">arm</col> + <col id="1" translatable="yes">orthanc (Linux 2.6.35.11-83.fc14)</col> + <col id="2" translatable="yes">black</col> + <col id="3" translatable="yes">white</col> + </row> + <row> + <col id="0" translatable="yes">Tor</col> + <col id="1" translatable="yes">0.2.1.28 (obsolete)</col> + <col id="2" translatable="yes">black</col> + <col id="3" translatable="yes">black</col> + </row> + <row> + <col id="0" translatable="yes">Relaying</col> + <col id="1" translatable="yes">Disabled</col> + <col id="2" translatable="yes">red</col> + <col id="3" translatable="yes">white</col> + </row> + <row> + <col id="0" translatable="yes">Control Port</col> + <col id="1" translatable="yes">9051 (open)</col> + <col id="2" translatable="yes">black</col> + <col id="3" translatable="yes">white</col> + </row> + <row> + <col id="0" translatable="yes">CPU Tor</col> + <col id="1" translatable="yes">0.0%</col> + <col id="2" translatable="yes">black</col> + <col id="3" translatable="yes">white</col> + </row> + <row> + <col id="0" translatable="yes">CPU arm</col> + <col id="1" translatable="yes">0.0%</col> + <col id="2" translatable="yes">black</col> + <col id="3" translatable="yes">white</col> + </row> + <row> + <col id="0" translatable="yes">Memory</col> + <col id="1" translatable="yes">20 MB (1.0%)</col> + <col id="2" translatable="yes">black</col> + <col id="3" translatable="yes">white</col> + </row> + <row> + <col id="0" translatable="yes">PID</col> + <col id="1" translatable="yes">3980</col> + <col id="2" translatable="yes">black</col> + <col id="3" translatable="yes">white</col> + </row> + <row> + <col id="0" translatable="yes">Uptime</col> + <col id="1" translatable="yes">01:01:34</col> + <col id="2" translatable="yes">black</col> + <col id="3" translatable="yes">white</col> + </row> + </data> + </object> + <object class="GtkListStore" id="liststore_conn"> + <columns> + <!-- column-name gchararray1 --> + <column type="gchararray"/> + <!-- column-name gchararray2 --> + <column type="gchararray"/> + <!-- column-name gchararray3 --> + <column type="gchararray"/> + <!-- column-name gchararray4 --> + <column type="gchararray"/> + <!-- column-name gchararray5 --> + <column type="gchararray"/> + <!-- column-name gchararray6 --> + <column type="gchararray"/> + </columns> + <data> + <row> + <col id="0" translatable="yes">115.167.31.237:56835</col> + <col id="1" translatable="yes">188.120.245.249:9001 (ru)</col> + <col id="2" translatable="yes">10.7m</col> + <col id="3" translatable="yes">CLIENT</col> + <col id="4" translatable="yes">blue</col> + <col id="5" translatable="yes">white</col> + </row> + <row> + <col id="0" translatable="yes">115.167.31.237:44940</col> + <col id="1" translatable="yes">206.217.215.183:53 (us)</col> + <col id="2" translatable="yes">28.3m</col> + <col id="3" translatable="yes">CLIENT</col> + <col id="4" translatable="yes">blue</col> + <col id="5" translatable="yes">white</col> + </row> + <row> + <col id="0" translatable="yes">127.0.0.1:9051</col> + <col id="1" translatable="yes">127.0.0.1:51665</col> + <col id="2" translatable="yes">30.0m</col> + <col id="3" translatable="yes">CONTROL</col> + <col id="4" translatable="yes">red</col> + <col id="5" translatable="yes">white</col> + </row> + </data> + </object> + <object class="GtkListStore" id="liststore_config"> + <columns> + <!-- column-name gchararray1 --> + <column type="gchararray"/> + <!-- column-name gchararray2 --> + <column type="gchararray"/> + <!-- column-name gchararray3 --> + <column type="gchararray"/> + <!-- column-name gchararray4 --> + <column type="gchararray"/> + <!-- column-name gchararray5 --> + <column type="gchararray"/> + </columns> + <data> + <row> + <col id="0" translatable="yes">BandwidthRate</col> + <col id="1" translatable="yes">5242880</col> + <col id="2" translatable="yes">Average bandwidth usage limit</col> + <col id="3" translatable="yes">#368918</col> + <col id="4" translatable="yes">white</col> + </row> + <row> + <col id="0" translatable="yes">BandwidthBurst</col> + <col id="1" translatable="yes">10485760</col> + <col id="2" translatable="yes">Maximum bandwidth usage limit</col> + <col id="3" translatable="yes">#368918</col> + <col id="4" translatable="yes">white</col> + </row> + <row> + <col id="0" translatable="yes">RelayBandwidthBurst</col> + <col id="1" translatable="yes">0 B</col> + <col id="2" translatable="yes">Maximum bandwidth usage limit for relaying</col> + <col id="3" translatable="yes">#368918</col> + <col id="4" translatable="yes">white</col> + </row> + <row> + <col id="0" translatable="yes">ControlPort</col> + <col id="1" translatable="yes">9051</col> + <col id="2" translatable="yes">Port providing access to tor controllers (arm, vidalia, etc)</col> + <col id="3" translatable="yes">#368918</col> + <col id="4" translatable="yes">white</col> + </row> + </data> + </object> + <object class="GtkWindow" id="window_main"> + <property name="title" translatable="yes">arm</property> + <property name="default_width">640</property> + <property name="default_height">480</property> + <signal name="delete_event" handler="on_window_main_delete_event"/> + <child> + <object class="GtkVBox" id="vbox_main"> + <property name="visible">True</property> + <property name="orientation">vertical</property> + <property name="spacing">5</property> + <child> + <object class="GtkMenuBar" id="menubar_main"> + <property name="visible">True</property> + <child> + <object class="GtkMenuItem" id="menuitem_file"> + <property name="visible">True</property> + <property name="label" translatable="yes">_File</property> + <property name="use_underline">True</property> + <child type="submenu"> + <object class="GtkMenu" id="menu_file"> + <property name="visible">True</property> + <child> + <object class="GtkImageMenuItem" id="imagemenuitem_new"> + <property name="label">gtk-new</property> + <property name="visible">True</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </object> + </child> + <child> + <object class="GtkImageMenuItem" id="imagemenuitem_open"> + <property name="label">gtk-open</property> + <property name="visible">True</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </object> + </child> + <child> + <object class="GtkImageMenuItem" id="imagemenuitem_save"> + <property name="label">gtk-save</property> + <property name="visible">True</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </object> + </child> + <child> + <object class="GtkImageMenuItem" id="imagemenuitem_saveas"> + <property name="label">gtk-save-as</property> + <property name="visible">True</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </object> + </child> + <child> + <object class="GtkSeparatorMenuItem" id="separatormenuitem_file"> + <property name="visible">True</property> + </object> + </child> + <child> + <object class="GtkImageMenuItem" id="imagemenuitem_exit"> + <property name="label">gtk-quit</property> + <property name="visible">True</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </object> + </child> + </object> + </child> + </object> + </child> + <child> + <object class="GtkMenuItem" id="menuitem_edit"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Edit</property> + <property name="use_underline">True</property> + <child type="submenu"> + <object class="GtkMenu" id="menu_edit"> + <property name="visible">True</property> + <child> + <object class="GtkImageMenuItem" id="imagemenuitem_cut"> + <property name="label">gtk-cut</property> + <property name="visible">True</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </object> + </child> + <child> + <object class="GtkImageMenuItem" id="imagemenuitem_copy"> + <property name="label">gtk-copy</property> + <property name="visible">True</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </object> + </child> + <child> + <object class="GtkImageMenuItem" id="imagemenuitem_paste"> + <property name="label">gtk-paste</property> + <property name="visible">True</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </object> + </child> + <child> + <object class="GtkImageMenuItem" id="imagemenuitem_delete"> + <property name="label">gtk-delete</property> + <property name="visible">True</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </object> + </child> + </object> + </child> + </object> + </child> + <child> + <object class="GtkMenuItem" id="menuitem_view"> + <property name="visible">True</property> + <property name="label" translatable="yes">_View</property> + <property name="use_underline">True</property> + </object> + </child> + <child> + <object class="GtkMenuItem" id="menuitem_help"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Help</property> + <property name="use_underline">True</property> + <child type="submenu"> + <object class="GtkMenu" id="menu_help"> + <property name="visible">True</property> + <child> + <object class="GtkImageMenuItem" id="imagemenuitem_about"> + <property name="label">gtk-about</property> + <property name="visible">True</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </object> + </child> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkHBox" id="hbox_main"> + <property name="visible">True</property> + <child> + <object class="GtkNotebook" id="notebook_main"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <child> + <object class="GtkVBox" id="vbox_graph"> + <property name="visible">True</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkLabel" id="label_graph_top"> + <property name="visible">True</property> + <property name="label" translatable="yes">Limit: 40 Mb/s, Burst: 80 Mb/s</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkHBox" id="hbox_graph"> + <property name="visible">True</property> + <child> + <object class="GtkVBox" id="vbox_graph_a"> + <property name="visible">True</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkLabel" id="label_graph_a_top"> + <property name="visible">True</property> + <property name="label" translatable="yes">Download (0.0 b/sec)</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkCurve" id="curve_graph_a"> + <property name="visible">True</property> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label_graph_a_bottom"> + <property name="visible">True</property> + <property name="label" translatable="yes">avg: 3.5 Kb/sec, total: 2.0 MB</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkVBox" id="vbox_graph_b"> + <property name="visible">True</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkLabel" id="label_graph_b_top"> + <property name="visible">True</property> + <property name="label" translatable="yes">Upload (0.0 b/sec)</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkCurve" id="curve_graph_b"> + <property name="visible">True</property> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label_graph_b_bottom"> + <property name="visible">True</property> + <property name="label" translatable="yes">avg: 3.5 Kb/sec, total: 2.0 MB</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + <child type="tab"> + <object class="GtkLabel" id="label_notebook_graph"> + <property name="visible">True</property> + <property name="label" translatable="yes">Graphs</property> + </object> + <packing> + <property name="tab_fill">False</property> + </packing> + </child> + <child> + <object class="GtkVBox" id="vbox_conn"> + <property name="visible">True</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkLabel" id="label_conn_top"> + <property name="visible">True</property> + <property name="label" translatable="yes">2 Clients, 1 Control</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkTreeView" id="treeview_conn"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="model">liststore_conn</property> + <property name="headers_visible">False</property> + <child> + <object class="GtkTreeViewColumn" id="treeviewcolumn_conn_origin"> + <property name="title">column</property> + </object> + </child> + <child> + <object class="GtkTreeViewColumn" id="treeviewcolumn_conn_dest"> + <property name="title">column</property> + </object> + </child> + <child> + <object class="GtkTreeViewColumn" id="treeviewcolumn_conn_time"> + <property name="title">column</property> + </object> + </child> + <child> + <object class="GtkTreeViewColumn" id="treeviewcolumn_conn_alive"> + <property name="title">column</property> + </object> + </child> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + <child type="tab"> + <object class="GtkLabel" id="label_notebook_conn"> + <property name="visible">True</property> + <property name="label" translatable="yes">Connections</property> + </object> + <packing> + <property name="position">1</property> + <property name="tab_fill">False</property> + </packing> + </child> + <child> + <object class="GtkVBox" id="vbox_config"> + <property name="visible">True</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkLabel" id="label_config_top"> + <property name="visible">True</property> + <property name="label" translatable="yes"><span foreground="#368918"><u>RelayBandwidthBurst</u> (General Option) +<b>Value</b>: 0 B (default, DataSize, usage: N bytes|KB|MB|GB|TB) +<b>Description</b>: Limit the maximum token bucket size (also known as +the burst) for <i>relayed traffic</i> to the given number of bytes in +each direction. (Default: 0) </span></property> + <property name="use_markup">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow" id="scrolledwindow_config"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">automatic</property> + <property name="vscrollbar_policy">automatic</property> + <child> + <object class="GtkTreeView" id="treeview_config"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="model">liststore_config</property> + <property name="headers_visible">False</property> + <property name="search_column">0</property> + <child> + <object class="GtkTreeViewColumn" id="treeviewcolumn_name"> + <property name="title">column</property> + </object> + </child> + <child> + <object class="GtkTreeViewColumn" id="treeviewcolumn_value"> + <property name="title">column</property> + </object> + </child> + <child> + <object class="GtkTreeViewColumn" id="treeviewcolumn_desc"> + <property name="title">column</property> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="position">2</property> + </packing> + </child> + <child type="tab"> + <object class="GtkLabel" id="label_notebook_config"> + <property name="visible">True</property> + <property name="label" translatable="yes">Configuration</property> + </object> + <packing> + <property name="position">2</property> + <property name="tab_fill">False</property> + </packing> + </child> + </object> + <packing> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow" id="scrolledwindow_sticky"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">automatic</property> + <property name="vscrollbar_policy">automatic</property> + <child> + <object class="GtkTreeView" id="treeview_sticky"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="model">liststore_sticky</property> + <property name="headers_visible">False</property> + <property name="headers_clickable">False</property> + <property name="search_column">0</property> + <child> + <object class="GtkTreeViewColumn" id="treeviewcolumn_sticky_name"> + <property name="title">column</property> + </object> + </child> + <child> + <object class="GtkTreeViewColumn" id="treeviewcolumn_sticky_value"> + <property name="title">column</property> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="padding">5</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow" id="scrolledwindow_log"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">automatic</property> + <property name="vscrollbar_policy">automatic</property> + <child> + <object class="GtkTextView" id="textview_log"> + <property name="visible">True</property> + <property name="can_focus">True</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="padding">5</property> + <property name="position">2</property> + </packing> + </child> + </object> + </child> + </object> + <object class="GtkTextBuffer" id="textbuffer_log"> + <property name="text" translatable="yes">16:09:20 [NOTICE] Bootstrapped 90%: Establishing a Tor circuit. +16:09:23 [NOTICE] Tor has successfully opened a circuit. Looks like client functionality is working. +16:09:23 [NOTICE] Tor has successfully opened a circuit. Looks like client functionality is working. +16:09:24 [NOTICE] Bootstrapped 100%: Done. +</property> + </object> +</interface> diff --git a/src/gui/controller.py b/src/gui/controller.py new file mode 100755 index 0000000..2f54933 --- /dev/null +++ b/src/gui/controller.py @@ -0,0 +1,85 @@ +from util import torTools + +import gtk + +class GuiController: + def __init__(self): + filename = 'src/gui/arm.xml' + self.builder = gtk.Builder() + self.builder.add_from_file(filename) + self.builder.connect_signals(self) + + def run(self): + window = self.builder.get_object('window_main') + + col = self.builder.get_object('treeview_sticky').get_column(0) + cell = gtk.CellRendererText() + col.pack_start(cell) + col.add_attribute(cell, 'text', 0) + + col = self.builder.get_object('treeview_sticky').get_column(1) + cell = gtk.CellRendererText() + col.pack_start(cell) + col.add_attribute(cell, 'markup', 1) + col.add_attribute(cell, 'foreground', 2) + + col = self.builder.get_object('treeview_conn').get_column(0) + cell = gtk.CellRendererText() + col.pack_start(cell) + col.add_attribute(cell, 'markup', 0) + col.add_attribute(cell, 'foreground', 4) + + col = self.builder.get_object('treeview_conn').get_column(1) + cell = gtk.CellRendererText() + col.pack_start(cell) + col.add_attribute(cell, 'markup', 1) + col.add_attribute(cell, 'foreground', 4) + + col = self.builder.get_object('treeview_conn').get_column(2) + cell = gtk.CellRendererText() + col.pack_start(cell) + col.add_attribute(cell, 'markup', 2) + col.add_attribute(cell, 'foreground', 4) + + col = self.builder.get_object('treeview_conn').get_column(3) + cell = gtk.CellRendererText() + col.pack_start(cell) + col.add_attribute(cell, 'markup', 3) + col.add_attribute(cell, 'foreground', 4) + + col = self.builder.get_object('treeview_config').get_column(0) + cell = gtk.CellRendererText() + col.pack_start(cell) + col.add_attribute(cell, 'markup', 0) + col.add_attribute(cell, 'foreground', 3) + + col = self.builder.get_object('treeview_config').get_column(1) + cell = gtk.CellRendererText() + col.pack_start(cell) + col.add_attribute(cell, 'markup', 1) + col.add_attribute(cell, 'foreground', 3) + + col = self.builder.get_object('treeview_config').get_column(2) + cell = gtk.CellRendererText() + col.pack_start(cell) + col.add_attribute(cell, 'markup', 2) + col.add_attribute(cell, 'foreground', 3) + + textview = self.builder.get_object('textview_log') + textbuffer = self.builder.get_object('textbuffer_log') + textview.set_buffer(textbuffer) + + conn = torTools.getConn() + torPid = conn.getMyPid() + textbuffer.set_text("Tor pid: %s" % torPid) + + window.show_all() + gtk.main() + + def on_window_main_delete_event(self, widget, data=None): + gtk.main_quit() + +def startGui(): + controller = GuiController() + controller.run() + diff --git a/src/starter.py b/src/starter.py index b41b18b..9d7f17c 100644 --- a/src/starter.py +++ b/src/starter.py @@ -16,6 +16,7 @@ import platform import version import cli.controller import cli.logPanel +import gui.controller import util.conf import util.connections import util.hostnames @@ -49,11 +50,12 @@ CONFIG = {"startup.controlPassword": None, "log.configDescriptions.persistance.saveFailed": util.log.NOTICE, "log.savingDebugLog": util.log.NOTICE}
-OPT = "i:c:dbe:vh" -OPT_EXPANDED = ["interface=", "config=", "debug", "blind", "event=", "version", "help"] +OPT = "gi:c:dbe:vh" +OPT_EXPANDED = ["gtk", "interface=", "config=", "debug", "blind", "event=", "version", "help"] HELP_MSG = """Usage arm [OPTION] Terminal status monitor for Tor relays.
+ -g, --gtk launch the Gtk+ interface -i, --interface [ADDRESS:]PORT change control interface from %s:%i -c, --config CONFIG_PATH loaded configuration options, CONFIG_PATH defaults to: %s @@ -208,6 +210,7 @@ def _dumpConfig(): if __name__ == '__main__': startTime = time.time() param = dict([(key, None) for key in CONFIG.keys()]) + launchGui = False isDebugMode = False configPath = DEFAULT_CONFIG # path used for customized configuration
@@ -236,6 +239,7 @@ if __name__ == '__main__':
param["startup.interface.ipAddress"] = controlAddr param["startup.interface.port"] = controlPort + elif opt in ("-g", "--gtk"): launchGui = True elif opt in ("-c", "--config"): configPath = arg # sets path of user's config elif opt in ("-d", "--debug"): isDebugMode = True # dumps all logs elif opt in ("-b", "--blind"): @@ -401,5 +405,8 @@ if __name__ == '__main__': if util.uiTools.isUnicodeAvailable(): locale.setlocale(locale.LC_ALL, "")
- cli.controller.startTorMonitor(time.time() - initTime) + if launchGui == True: + gui.controller.startGui() + else: + cli.controller.startTorMonitor(time.time() - initTime)
tor-commits@lists.torproject.org