tor-commits
Threads by month
- ----- 2025 -----
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
January 2013
- 19 participants
- 1125 discussions

[translation/orbot_completed] Update translations for orbot_completed
by translation@torproject.org 02 Jan '13
by translation@torproject.org 02 Jan '13
02 Jan '13
commit 95c57c2f8abcd732328184b62faf601c2a35eb08
Author: Translation commit bot <translation(a)torproject.org>
Date: Wed Jan 2 02:45:11 2013 +0000
Update translations for orbot_completed
---
values-es/strings.xml | 14 +++++++-------
1 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/values-es/strings.xml b/values-es/strings.xml
index e8d3415..662bea3 100644
--- a/values-es/strings.xml
+++ b/values-es/strings.xml
@@ -190,9 +190,9 @@
<string name="run_servers_accessible_via_the_tor_network">Permite el acceso a servidores ocultos por dispositivo (de IP oculta al usuario y con dominio .onion, sin DNS) ofrecidos a través de la red Tor</string>
<string name="enter_localhost_ports_for_hidden_services">Introduzca los puertos locales de sus servicios ocultos</string>
<string name="hidden_service_ports">Puertos de los servicios ocultos</string>
- <string name="the_addressable_name_for_your_hidden_service_generated_automatically_">El nombre direccionable (.onion, sin DNS, generado automáticamente) para su servicio oculto</string>
+ <string name="the_addressable_name_for_your_hidden_service_generated_automatically_">El nombre direccionable (sin DNS .onion, generado automáticamente) para su servicio oculto</string>
<string name="enable_debug_log_to_output_must_use_adb_or_alogcat_to_view_">Habilitar el registro de depuración (debug log) a la salida (debe utilizar adb o aLogCat para verlo)</string>
- <string name="project_home">Página principal del proyecto:</string>
+ <string name="project_home">Página(s) principal(es) del proyecto:</string>
<string name="project_urls">https://www.torproject.org/docs/android\nhttps://guardianproject.info/apps/…</string>
<string name="the_tor_license">Licencia de Tor</string>
<string name="https_torproject_org">https://torproject.org</string>
@@ -202,9 +202,9 @@
<string name="privoxy_version">Privoxy: http://www.privoxy.org</string>
<string name="iptables_version">Iptables: http://www.netfilter.org</string>
<string name="openssl_version">OpenSSL: http://www.openssl.org</string>
- <string name="hidden_service_request">Una aplicación está intentando abrir el puerto %S de uno de sus servidore ocultos, hacia la red Tor. Esto sólo es seguro si esa aplicación es de su confianza.</string>
+ <string name="hidden_service_request">Una aplicación está intentando abrir el puerto %S de un servidor oculto, hacia la red Tor. Esto sólo es seguro si esa aplicación es de su confianza.</string>
<string name="found_existing_tor_process">Se encontró un proceso de Tor ya existente...</string>
- <string name="something_bad_happened">Un suceso trastocó el funcionamiento de la aplicación. Compruebe el registro (log)</string>
+ <string name="something_bad_happened">Hubo algún tipo de problema. Compruebe el registro (log)</string>
<string name="hidden_service_on">Servicio oculto en:</string>
<string name="unable_to_read_hidden_service_name">No fue posible leer el nombre del servicio oculto</string>
<string name="unable_to_start_tor">No fue posible iniciar Tor: </string>
@@ -212,13 +212,13 @@
<string name="pref_use_sys_iptables_summary">Usa el binario de Iptables del sistema en lugar del incluído en el paquete de Orbot</string>
<string name="error_installing_binares">No fue posible instalar o actualizar los binarios de Tor.</string>
<string name="pref_use_persistent_notifications">Mantener siempre el icono de Orbot en la barra de tareas cuando esté conectado</string>
- <string name="pref_use_persistent_notifications_title">Notificaciones siempre encendidas</string>
+ <string name="pref_use_persistent_notifications_title">Notificaciones siempre activadas</string>
<string name="notification_using_bridges">¡Bridges habilitados! </string>
<string name="default_bridges"/>
- <string name="set_locale_title">Configuración regional</string>
+ <string name="set_locale_title">Establecer localización regional</string>
<string name="set_locale_summary">Elija configuración regional e idioma para Orbot</string>
<string name="wizard_locale_title">Escoja idioma</string>
- <string name="wizard_locale_msg">Deje el idioma predeterminado o cambie de idioma</string>
+ <string name="wizard_locale_msg">Deje el predeterminado o cambie de idioma</string>
<string name="powered_by">impulsado por The Tor Project</string>
<string name="btn_save_settings">Guardar configuración</string>
</resources>
1
0

02 Jan '13
commit e48ecfcf5324d2636b57236e3fb0b2fbf73b4861
Author: Translation commit bot <translation(a)torproject.org>
Date: Wed Jan 2 02:45:08 2013 +0000
Update translations for orbot
---
values-es/strings.xml | 14 +++++++-------
1 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/values-es/strings.xml b/values-es/strings.xml
index e8d3415..662bea3 100644
--- a/values-es/strings.xml
+++ b/values-es/strings.xml
@@ -190,9 +190,9 @@
<string name="run_servers_accessible_via_the_tor_network">Permite el acceso a servidores ocultos por dispositivo (de IP oculta al usuario y con dominio .onion, sin DNS) ofrecidos a través de la red Tor</string>
<string name="enter_localhost_ports_for_hidden_services">Introduzca los puertos locales de sus servicios ocultos</string>
<string name="hidden_service_ports">Puertos de los servicios ocultos</string>
- <string name="the_addressable_name_for_your_hidden_service_generated_automatically_">El nombre direccionable (.onion, sin DNS, generado automáticamente) para su servicio oculto</string>
+ <string name="the_addressable_name_for_your_hidden_service_generated_automatically_">El nombre direccionable (sin DNS .onion, generado automáticamente) para su servicio oculto</string>
<string name="enable_debug_log_to_output_must_use_adb_or_alogcat_to_view_">Habilitar el registro de depuración (debug log) a la salida (debe utilizar adb o aLogCat para verlo)</string>
- <string name="project_home">Página principal del proyecto:</string>
+ <string name="project_home">Página(s) principal(es) del proyecto:</string>
<string name="project_urls">https://www.torproject.org/docs/android\nhttps://guardianproject.info/apps/…</string>
<string name="the_tor_license">Licencia de Tor</string>
<string name="https_torproject_org">https://torproject.org</string>
@@ -202,9 +202,9 @@
<string name="privoxy_version">Privoxy: http://www.privoxy.org</string>
<string name="iptables_version">Iptables: http://www.netfilter.org</string>
<string name="openssl_version">OpenSSL: http://www.openssl.org</string>
- <string name="hidden_service_request">Una aplicación está intentando abrir el puerto %S de uno de sus servidore ocultos, hacia la red Tor. Esto sólo es seguro si esa aplicación es de su confianza.</string>
+ <string name="hidden_service_request">Una aplicación está intentando abrir el puerto %S de un servidor oculto, hacia la red Tor. Esto sólo es seguro si esa aplicación es de su confianza.</string>
<string name="found_existing_tor_process">Se encontró un proceso de Tor ya existente...</string>
- <string name="something_bad_happened">Un suceso trastocó el funcionamiento de la aplicación. Compruebe el registro (log)</string>
+ <string name="something_bad_happened">Hubo algún tipo de problema. Compruebe el registro (log)</string>
<string name="hidden_service_on">Servicio oculto en:</string>
<string name="unable_to_read_hidden_service_name">No fue posible leer el nombre del servicio oculto</string>
<string name="unable_to_start_tor">No fue posible iniciar Tor: </string>
@@ -212,13 +212,13 @@
<string name="pref_use_sys_iptables_summary">Usa el binario de Iptables del sistema en lugar del incluído en el paquete de Orbot</string>
<string name="error_installing_binares">No fue posible instalar o actualizar los binarios de Tor.</string>
<string name="pref_use_persistent_notifications">Mantener siempre el icono de Orbot en la barra de tareas cuando esté conectado</string>
- <string name="pref_use_persistent_notifications_title">Notificaciones siempre encendidas</string>
+ <string name="pref_use_persistent_notifications_title">Notificaciones siempre activadas</string>
<string name="notification_using_bridges">¡Bridges habilitados! </string>
<string name="default_bridges"/>
- <string name="set_locale_title">Configuración regional</string>
+ <string name="set_locale_title">Establecer localización regional</string>
<string name="set_locale_summary">Elija configuración regional e idioma para Orbot</string>
<string name="wizard_locale_title">Escoja idioma</string>
- <string name="wizard_locale_msg">Deje el idioma predeterminado o cambie de idioma</string>
+ <string name="wizard_locale_msg">Deje el predeterminado o cambie de idioma</string>
<string name="powered_by">impulsado por The Tor Project</string>
<string name="btn_save_settings">Guardar configuración</string>
</resources>
1
0
commit ec41f9b795f03efbd29fec3cb6ea831faa40532b
Author: Damian Johnson <atagar(a)torproject.org>
Date: Wed Dec 19 08:23:03 2012 -0800
Using stem's enum util
Replacing our Enum class with stem's. This is the start of a general migration
to stem's utility classes, which unlike ours actually have tests (yay!).
---
src/cli/configPanel.py | 10 ++-
src/cli/connections/connEntry.py | 6 +-
src/cli/connections/connPanel.py | 18 +++---
src/cli/connections/countPopup.py | 4 +-
src/cli/connections/entries.py | 2 +-
src/cli/controller.py | 4 +-
src/cli/graphing/graphPanel.py | 6 +-
src/cli/logPanel.py | 22 ++++----
src/cli/menu/actions.py | 6 +-
src/cli/torrcPanel.py | 4 +-
src/test.py | 4 +-
src/util/__init__.py | 2 +-
src/util/conf.py | 2 +-
src/util/connections.py | 4 +-
src/util/enum.py | 116 -------------------------------------
src/util/log.py | 11 ++--
src/util/procTools.py | 4 +-
src/util/torConfig.py | 6 +-
src/util/torTools.py | 4 +-
src/util/uiTools.py | 4 +-
20 files changed, 73 insertions(+), 166 deletions(-)
diff --git a/src/cli/configPanel.py b/src/cli/configPanel.py
index a73f2a8..50b66b3 100644
--- a/src/cli/configPanel.py
+++ b/src/cli/configPanel.py
@@ -9,7 +9,9 @@ import threading
import cli.controller
import popups
-from util import conf, enum, panel, sysTools, torConfig, torTools, uiTools
+from util import conf, panel, sysTools, torConfig, torTools, uiTools
+
+from stem.util import enum
DEFAULT_CONFIG = {"features.config.selectionDetails.height": 6,
"features.config.prepopulateEditValues": True,
@@ -182,7 +184,7 @@ class ConfigPanel(panel.Panel):
"features.config.state.colWidth.option": 5,
"features.config.state.colWidth.value": 5})
- sortFields = Field.values()
+ sortFields = list(Field)
customOrdering = config.getIntCSV("features.config.order", None, 3, 0, len(sortFields))
if customOrdering:
@@ -300,9 +302,9 @@ class ConfigPanel(panel.Panel):
# set ordering for config options
titleLabel = "Config Option Ordering:"
- options = [FIELD_ATTR[field][0] for field in Field.values()]
+ options = [FIELD_ATTR[field][0] for field in Field]
oldSelection = [FIELD_ATTR[field][0] for field in self.sortOrdering]
- optionColors = dict([FIELD_ATTR[field] for field in Field.values()])
+ optionColors = dict([FIELD_ATTR[field] for field in Field])
results = popups.showSortDialog(titleLabel, options, oldSelection, optionColors)
if results:
diff --git a/src/cli/connections/connEntry.py b/src/cli/connections/connEntry.py
index 7650149..2f57b51 100644
--- a/src/cli/connections/connEntry.py
+++ b/src/cli/connections/connEntry.py
@@ -6,9 +6,11 @@ Connection panel entries related to actual connections to or from the system
import time
import curses
-from util import connections, enum, torTools, uiTools
+from util import connections, torTools, uiTools
from cli.connections import entries
+from stem.util import enum
+
# Connection Categories:
# Inbound Relay connection, coming to us.
# Outbound Relay connection, leaving us.
@@ -178,7 +180,7 @@ class ConnectionEntry(entries.ConnectionPanelEntry):
if myNickname == "UNKNOWN": return "z" * 20 # orders at the end
else: return myNickname.lower()
elif attr == entries.SortAttr.CATEGORY:
- return Category.indexOf(connLine.getType())
+ return Category.index_of(connLine.getType())
elif attr == entries.SortAttr.UPTIME:
return connLine.startTime
elif attr == entries.SortAttr.COUNTRY:
diff --git a/src/cli/connections/connPanel.py b/src/cli/connections/connPanel.py
index 632669c..50ba2e8 100644
--- a/src/cli/connections/connPanel.py
+++ b/src/cli/connections/connPanel.py
@@ -10,7 +10,9 @@ import threading
import cli.popups
from cli.connections import countPopup, descriptorPopup, entries, connEntry, circEntry
-from util import connections, enum, panel, torTools, uiTools
+from util import connections, panel, torTools, uiTools
+
+from stem.util import enum
DEFAULT_CONFIG = {"features.connection.resolveApps": True,
"features.connection.listingType": 0,
@@ -41,7 +43,7 @@ class ConnectionPanel(panel.Panel, threading.Thread):
if config:
config.update(self._config, {
- "features.connection.listingType": (0, len(Listing.values()) - 1),
+ "features.connection.listingType": (0, len(list(Listing)) - 1),
"features.connection.refreshRate": 1})
# defaults our listing selection to fingerprints if ip address
@@ -49,13 +51,13 @@ class ConnectionPanel(panel.Panel, threading.Thread):
if not self._config["features.connection.showIps"] and self._config["features.connection.listingType"] == 0:
self._config["features.connection.listingType"] = 2
- sortFields = entries.SortAttr.values()
+ sortFields = list(entries.SortAttr)
customOrdering = config.getIntCSV("features.connection.order", None, 3, 0, len(sortFields))
if customOrdering:
self._sortOrdering = [sortFields[i] for i in customOrdering]
- self._listingType = Listing.values()[self._config["features.connection.listingType"]]
+ self._listingType = list(Listing)[self._config["features.connection.listingType"]]
self._scroller = uiTools.Scroller(True)
self._title = "Connections:" # title line of the panel
self._entries = [] # last fetched display entries
@@ -205,7 +207,7 @@ class ConnectionPanel(panel.Panel, threading.Thread):
# set ordering for connection options
titleLabel = "Connection Ordering:"
- options = entries.SortAttr.values()
+ options = list(entries.SortAttr)
oldSelection = self._sortOrdering
optionColors = dict([(attr, entries.SORT_COLORS[attr]) for attr in options])
results = cli.popups.showSortDialog(titleLabel, options, oldSelection, optionColors)
@@ -228,7 +230,7 @@ class ConnectionPanel(panel.Panel, threading.Thread):
elif key == ord('u') or key == ord('U'):
# provides a menu to pick the connection resolver
title = "Resolver Util:"
- options = ["auto"] + connections.Resolver.values()
+ options = ["auto"] + list(connections.Resolver)
connResolver = connections.getResolver("tor")
currentOverwrite = connResolver.overwriteResolver
@@ -244,7 +246,7 @@ class ConnectionPanel(panel.Panel, threading.Thread):
elif key == ord('l') or key == ord('L'):
# provides a menu to pick the primary information we list connections by
title = "List By:"
- options = entries.ListingType.values()
+ options = list(entries.ListingType)
# dropping the HOSTNAME listing type until we support displaying that content
options.remove(cli.connections.entries.ListingType.HOSTNAME)
@@ -489,7 +491,7 @@ class ConnectionPanel(panel.Panel, threading.Thread):
# type cache for all of the connections (in case its changed since last
# fetched).
- categoryTypes = connEntry.Category.values()
+ categoryTypes = list(connEntry.Category)
typeCounts = dict((type, 0) for type in categoryTypes)
for entry in newEntries:
if isinstance(entry, connEntry.ConnectionEntry):
diff --git a/src/cli/connections/countPopup.py b/src/cli/connections/countPopup.py
index 7904519..7ec6e60 100644
--- a/src/cli/connections/countPopup.py
+++ b/src/cli/connections/countPopup.py
@@ -8,7 +8,9 @@ import operator
import cli.controller
import cli.popups
-from util import connections, enum, log, uiTools
+from util import connections, log, uiTools
+
+from stem.util import enum
CountType = enum.Enum("CLIENT_LOCALE", "EXIT_PORT")
EXIT_USAGE_WIDTH = 15
diff --git a/src/cli/connections/entries.py b/src/cli/connections/entries.py
index f832b6a..d5085aa 100644
--- a/src/cli/connections/entries.py
+++ b/src/cli/connections/entries.py
@@ -4,7 +4,7 @@ entry itself (ie, Tor connection, client circuit, etc) and the lines it
consists of in the listing.
"""
-from util import enum
+from stem.util import enum
# attributes we can list entries by
ListingType = enum.Enum(("IP_ADDRESS", "IP Address"), "HOSTNAME", "FINGERPRINT", "NICKNAME")
diff --git a/src/cli/controller.py b/src/cli/controller.py
index 478bc02..af3fdac 100644
--- a/src/cli/controller.py
+++ b/src/cli/controller.py
@@ -22,7 +22,9 @@ import cli.connections.connPanel
from stem.control import Controller
-from util import connections, conf, enum, hostnames, log, panel, sysTools, torConfig, torTools
+from util import connections, conf, hostnames, log, panel, sysTools, torConfig, torTools
+
+from stem.util import enum
ARM_CONTROLLER = None
diff --git a/src/cli/graphing/graphPanel.py b/src/cli/graphing/graphPanel.py
index d03d1bd..16efe8f 100644
--- a/src/cli/graphing/graphPanel.py
+++ b/src/cli/graphing/graphPanel.py
@@ -24,7 +24,9 @@ import cli.controller
import stem.control
-from util import enum, panel, torTools, uiTools
+from util import panel, torTools, uiTools
+
+from stem.util import enum
# time intervals at which graphs can be updated
UPDATE_INTERVALS = [("each second", 1), ("5 seconds", 5), ("30 seconds", 30),
@@ -232,7 +234,7 @@ class GraphPanel(panel.Panel):
def __init__(self, stdscr):
panel.Panel.__init__(self, stdscr, "graph", 0)
self.updateInterval = CONFIG["features.graph.interval"]
- self.bounds = Bounds.values()[CONFIG["features.graph.bound"]]
+ self.bounds = list(Bounds)[CONFIG["features.graph.bound"]]
self.graphHeight = CONFIG["features.graph.height"]
self.currentDisplay = None # label of the stats currently being displayed
self.stats = {} # available stats (mappings of label -> instance)
diff --git a/src/cli/logPanel.py b/src/cli/logPanel.py
index b866c62..d03973d 100644
--- a/src/cli/logPanel.py
+++ b/src/cli/logPanel.py
@@ -120,9 +120,9 @@ def expandEvents(eventAbbr):
for flag in eventAbbr:
if flag == "A":
- armRunlevels = ["ARM_" + runlevel for runlevel in log.Runlevel.values()]
- stemRunlevels = ["STEM_" + runlevel for runlevel in log.Runlevel.values()]
- expandedEvents = set(TOR_EVENT_TYPES.values() + armRunlevels + stemRunlevels + ["UNKNOWN"])
+ armRunlevels = ["ARM_" + runlevel for runlevel in log.Runlevel]
+ stemRunlevels = ["STEM_" + runlevel for runlevel in log.Runlevel]
+ expandedEvents = set(list(TOR_EVENT_TYPES) + armRunlevels + stemRunlevels + ["UNKNOWN"])
break
elif flag == "X":
expandedEvents = set()
@@ -136,11 +136,11 @@ def expandEvents(eventAbbr):
elif flag in "E5": runlevelIndex = 4
if flag in "DINWE":
- runlevelSet = [runlevel for runlevel in log.Runlevel.values()[runlevelIndex:]]
+ runlevelSet = [runlevel for runlevel in list(log.Runlevel)[runlevelIndex:]]
expandedEvents = expandedEvents.union(set(runlevelSet))
elif flag in "12345":
for prefix in ("ARM_", "STEM_"):
- runlevelSet = [prefix + runlevel for runlevel in log.Runlevel.values()[runlevelIndex:]]
+ runlevelSet = [prefix + runlevel for runlevel in list(log.Runlevel)[runlevelIndex:]]
expandedEvents = expandedEvents.union(set(runlevelSet))
elif flag == "U":
expandedEvents.add("UNKNOWN")
@@ -219,7 +219,7 @@ def getLogFileEntries(runlevels, readLimit = None, addLimit = None, config = Non
# if the runlevels argument is a superset of the log file then we can
# limit the read contents to the addLimit
- runlevels = log.Runlevel.values()
+ runlevels = list(log.Runlevel)
loggingTypes = loggingTypes.upper()
if addLimit and (not readLimit or readLimit > addLimit):
if "-" in loggingTypes:
@@ -550,7 +550,7 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler):
# adds arm listener and prepopulates log with past tor/arm events
log.LOG_LOCK.acquire()
try:
- log.addListeners(log.Runlevel.values(), self._registerArmEvent)
+ log.addListeners(list(log.Runlevel), self._registerArmEvent)
self.reprepopulateEvents()
finally:
log.LOG_LOCK.release()
@@ -597,16 +597,16 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler):
# fetches past tor events from log file, if available
torEventBacklog = []
if self._config["features.log.prepopulate"]:
- setRunlevels = list(set.intersection(set(self.loggedEvents), set(log.Runlevel.values())))
+ setRunlevels = list(set.intersection(set(self.loggedEvents), set(list(log.Runlevel))))
readLimit = self._config["features.log.prepopulateReadLimit"]
addLimit = self._config["cache.logPanel.size"]
torEventBacklog = getLogFileEntries(setRunlevels, readLimit, addLimit, self._config)
# gets the set of arm events we're logging
setRunlevels = []
- armRunlevels = log.Runlevel.values()
+ armRunlevels = list(log.Runlevel)
for i in range(len(armRunlevels)):
- if "ARM_" + log.Runlevel.values()[i] in self.loggedEvents:
+ if "ARM_" + list(log.Runlevel)[i] in self.loggedEvents:
setRunlevels.append(armRunlevels[i])
armEventBacklog = []
@@ -1213,7 +1213,7 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler):
runlevelRanges = [] # tuple of type, startLevel, endLevel for ranges to be consensed
# reverses runlevels and types so they're appended in the right order
- reversedRunlevels = log.Runlevel.values()
+ reversedRunlevels = list(log.Runlevel)
reversedRunlevels.reverse()
for prefix in ("STEM_", "ARM_", ""):
# blank ending runlevel forces the break condition to be reached at the end
diff --git a/src/cli/menu/actions.py b/src/cli/menu/actions.py
index 30dff69..b1371c4 100644
--- a/src/cli/menu/actions.py
+++ b/src/cli/menu/actions.py
@@ -157,7 +157,7 @@ def makeGraphMenu(graphPanel):
boundsMenu = cli.menu.item.Submenu("Bounds")
boundsGroup = cli.menu.item.SelectionGroup(graphPanel.setBoundsType, graphPanel.getBoundsType())
- for boundsType in cli.graphing.graphPanel.Bounds.values():
+ for boundsType in cli.graphing.graphPanel.Bounds:
boundsMenu.add(cli.menu.item.SelectionMenuItem(boundsType, boundsGroup, boundsType))
graphMenu.add(boundsMenu)
@@ -219,7 +219,7 @@ def makeConnectionsMenu(connPanel):
# listing options
listingGroup = cli.menu.item.SelectionGroup(connPanel.setListingType, connPanel.getListingType())
- listingOptions = cli.connections.entries.ListingType.values()
+ listingOptions = list(cli.connections.entries.ListingType)
listingOptions.remove(cli.connections.entries.ListingType.HOSTNAME)
for option in listingOptions:
@@ -235,7 +235,7 @@ def makeConnectionsMenu(connPanel):
resolverMenu.add(cli.menu.item.SelectionMenuItem("auto", resolverGroup, None))
- for option in connections.Resolver.values():
+ for option in connections.Resolver:
resolverMenu.add(cli.menu.item.SelectionMenuItem(option, resolverGroup, option))
connectionsMenu.add(resolverMenu)
diff --git a/src/cli/torrcPanel.py b/src/cli/torrcPanel.py
index c1bb3f9..983768f 100644
--- a/src/cli/torrcPanel.py
+++ b/src/cli/torrcPanel.py
@@ -8,7 +8,9 @@ import threading
import popups
-from util import conf, enum, panel, torConfig, torTools, uiTools
+from util import conf, panel, torConfig, torTools, uiTools
+
+from stem.util import enum
DEFAULT_CONFIG = {"features.config.file.showScrollbars": True,
"features.config.file.maxLinesPerEntry": 8}
diff --git a/src/test.py b/src/test.py
index 7129120..10eddb0 100644
--- a/src/test.py
+++ b/src/test.py
@@ -68,7 +68,7 @@ while True:
# provide the selection options
printDivider()
print("Select a resolver:")
- availableResolvers = connections.Resolver.values()
+ availableResolvers = list(connections.Resolver)
for i in range(len(availableResolvers)):
print(" %i. %s" % (i, availableResolvers[i]))
print(" q. Go back to the main menu")
@@ -80,7 +80,7 @@ while True:
if userSelection.isdigit() and int(userSelection) in range(0, 7):
try:
- resolver = connections.Resolver.values()[int(userSelection)]
+ resolver = list(connections.Resolver)[int(userSelection)]
startTime = time.time()
print(connections.getResolverCommand(resolver, "tor", conn.getMyPid()))
diff --git a/src/util/__init__.py b/src/util/__init__.py
index 5afde12..e4e22c1 100644
--- a/src/util/__init__.py
+++ b/src/util/__init__.py
@@ -4,5 +4,5 @@ application's status, making cross platform system calls, parsing tor data,
and safely working with curses (hiding some of the gory details).
"""
-__all__ = ["conf", "connections", "enum", "hostnames", "log", "panel", "procTools", "procName", "sysTools", "textInput", "torConfig", "torTools", "uiTools"]
+__all__ = ["conf", "connections", "hostnames", "log", "panel", "procTools", "procName", "sysTools", "textInput", "torConfig", "torTools", "uiTools"]
diff --git a/src/util/conf.py b/src/util/conf.py
index bfbf468..a8ca6de 100644
--- a/src/util/conf.py
+++ b/src/util/conf.py
@@ -111,7 +111,7 @@ class Config():
if key.startswith("log."):
if val.upper() == "NONE": val = None
- elif val.upper() in log.Runlevel.values(): val = val.upper()
+ elif val.upper() in list(log.Runlevel): val = val.upper()
else:
msg = "Config entry '%s' is expected to be a runlevel" % key
if default != None: msg += ", defaulting to '%s'" % default
diff --git a/src/util/connections.py b/src/util/connections.py
index 250b113..de128c2 100644
--- a/src/util/connections.py
+++ b/src/util/connections.py
@@ -21,7 +21,9 @@ import os
import time
import threading
-from util import enum, log, procTools, sysTools
+from util import log, procTools, sysTools
+
+from stem.util import enum
# enums for connection resolution utilities
Resolver = enum.Enum(("PROC", "proc"),
diff --git a/src/util/enum.py b/src/util/enum.py
deleted file mode 100644
index bdba6b4..0000000
--- a/src/util/enum.py
+++ /dev/null
@@ -1,116 +0,0 @@
-"""
-Basic enumeration, providing ordered types for collections. These can be
-constructed as simple type listings, ie:
->>> insects = Enum("ANT", "WASP", "LADYBUG", "FIREFLY")
->>> insects.ANT
-'Ant'
->>> insects.values()
-['Ant', 'Wasp', 'Ladybug', 'Firefly']
-
-with overwritten string counterparts:
->>> pets = Enum(("DOG", "Skippy"), "CAT", ("FISH", "Nemo"))
->>> pets.DOG
-'Skippy'
->>> pets.CAT
-'Cat'
-
-or with entirely custom string components as an unordered enum with:
->>> pets = LEnum(DOG="Skippy", CAT="Kitty", FISH="Nemo")
->>> pets.CAT
-'Kitty'
-"""
-
-def toCamelCase(label):
- """
- Converts the given string to camel case, ie:
- >>> toCamelCase("I_LIKE_PEPPERJACK!")
- 'I Like Pepperjack!'
-
- Arguments:
- label - input string to be converted
- """
-
- words = []
- for entry in label.split("_"):
- if len(entry) == 0: words.append("")
- elif len(entry) == 1: words.append(entry.upper())
- else: words.append(entry[0].upper() + entry[1:].lower())
-
- return " ".join(words)
-
-class Enum:
- """
- Basic enumeration.
- """
-
- def __init__(self, *args):
- self.orderedValues = []
-
- for entry in args:
- if isinstance(entry, str):
- key, val = entry, toCamelCase(entry)
- elif isinstance(entry, tuple) and len(entry) == 2:
- key, val = entry
- else: raise ValueError("Unrecognized input: %s" % args)
-
- self.__dict__[key] = val
- self.orderedValues.append(val)
-
- def values(self):
- """
- Provides an ordered listing of the enumerations in this set.
- """
-
- return list(self.orderedValues)
-
- def indexOf(self, value):
- """
- Provides the index of the given value in the collection. This raises a
- ValueError if no such element exists.
-
- Arguments:
- value - entry to be looked up
- """
-
- return self.orderedValues.index(value)
-
- def next(self, value):
- """
- Provides the next enumeration after the given value, raising a ValueError
- if no such enum exists.
-
- Arguments:
- value - enumeration for which to get the next entry
- """
-
- if not value in self.orderedValues:
- raise ValueError("No such enumeration exists: %s (options: %s)" % (value, ", ".join(self.orderedValues)))
-
- nextIndex = (self.orderedValues.index(value) + 1) % len(self.orderedValues)
- return self.orderedValues[nextIndex]
-
- def previous(self, value):
- """
- Provides the previous enumeration before the given value, raising a
- ValueError if no such enum exists.
-
- Arguments:
- value - enumeration for which to get the previous entry
- """
-
- if not value in self.orderedValues:
- raise ValueError("No such enumeration exists: %s (options: %s)" % (value, ", ".join(self.orderedValues)))
-
- prevIndex = (self.orderedValues.index(value) - 1) % len(self.orderedValues)
- return self.orderedValues[prevIndex]
-
-class LEnum(Enum):
- """
- Enumeration that accepts custom string mappings.
- """
-
- def __init__(self, **args):
- Enum.__init__(self)
- self.__dict__.update(args)
- self.orderedValues = sorted(args.values())
-
diff --git a/src/util/log.py b/src/util/log.py
index e4bd231..56a6636 100644
--- a/src/util/log.py
+++ b/src/util/log.py
@@ -11,23 +11,22 @@ import time
from sys import maxint
from threading import RLock
-from util import enum
+from stem.util import enum
# Logging runlevels. These are *very* commonly used so including shorter
# aliases (so they can be referenced as log.DEBUG, log.WARN, etc).
-Runlevel = enum.Enum(("DEBUG", "DEBUG"), ("INFO", "INFO"), ("NOTICE", "NOTICE"),
- ("WARN", "WARN"), ("ERR", "ERR"))
-DEBUG, INFO, NOTICE, WARN, ERR = Runlevel.values()
+Runlevel = enum.UppercaseEnum("DEBUG", "INFO", "NOTICE", "WARN", "ERR")
+DEBUG, INFO, NOTICE, WARN, ERR = list(Runlevel)
# provides thread safety for logging operations
LOG_LOCK = RLock()
# chronologically ordered records of events for each runlevel, stored as tuples
# consisting of: (time, message)
-_backlog = dict([(level, []) for level in Runlevel.values()])
+_backlog = dict([(level, []) for level in Runlevel])
# mapping of runlevels to the listeners interested in receiving events from it
-_listeners = dict([(level, []) for level in Runlevel.values()])
+_listeners = dict([(level, []) for level in Runlevel])
CONFIG = {"cache.armLog.size": 1000,
"cache.armLog.trimSize": 200}
diff --git a/src/util/procTools.py b/src/util/procTools.py
index 39b5407..835814e 100644
--- a/src/util/procTools.py
+++ b/src/util/procTools.py
@@ -20,7 +20,9 @@ import time
import socket
import base64
-from util import enum, log
+from util import log
+
+from stem.util import enum
# cached system values
SYS_START_TIME, SYS_PHYSICAL_MEMORY = None, None
diff --git a/src/util/torConfig.py b/src/util/torConfig.py
index 0f6452d..5566e9d 100644
--- a/src/util/torConfig.py
+++ b/src/util/torConfig.py
@@ -9,7 +9,9 @@ import threading
import stem.version
-from util import enum, log, sysTools, torTools, uiTools
+from util import log, sysTools, torTools, uiTools
+
+from stem.util import enum
CONFIG = {"features.torrc.validate": True,
"config.important": [],
@@ -147,7 +149,7 @@ def loadOptionDescriptions(loadPath = None, checkVersion = True):
while inputFileContents:
# gets category enum, failing if it doesn't exist
category = inputFileContents.pop(0).rstrip()
- if not category in Category.values():
+ if not category in Category:
baseMsg = "invalid category in input file: '%s'"
raise IOError(baseMsg % category)
diff --git a/src/util/torTools.py b/src/util/torTools.py
index a5add1a..7aea8fa 100644
--- a/src/util/torTools.py
+++ b/src/util/torTools.py
@@ -16,7 +16,9 @@ import stem
import stem.control
import stem.descriptor
-from util import connections, enum, log, procTools, sysTools, uiTools
+from util import connections, log, procTools, sysTools, uiTools
+
+from stem.util import enum
# enums for tor's controller state:
# INIT - attached to a new controller
diff --git a/src/util/uiTools.py b/src/util/uiTools.py
index bc1fefe..c1f1a86 100644
--- a/src/util/uiTools.py
+++ b/src/util/uiTools.py
@@ -10,7 +10,9 @@ import sys
import curses
from curses.ascii import isprint
-from util import enum, log
+from util import log
+
+from stem.util import enum
# colors curses can handle
COLOR_LIST = {"red": curses.COLOR_RED, "green": curses.COLOR_GREEN,
1
0
commit d0ec1e72ef3d7745b68fad7a652f2773ea7bc2b0
Author: Damian Johnson <atagar(a)torproject.org>
Date: Tue Jan 1 13:58:06 2013 -0800
Using stem's conf util
Ok, let's get this out of the way first. This is a major overhaul. Arm's conf
util had its insidious clutch over just about every file in our codebase.
Stem's conf util introduces a new pattern for managing configurations that
turns out to be vastly cleaner.
I'll be amazed if this doesn't introduce some sort of regression but so far so
good. In the long run this'll be a big step toward having a simpler, more
manageable codebase.
---
armrc.sample | 42 ++++--
src/cli/configPanel.py | 75 ++++----
src/cli/connections/connEntry.py | 21 +--
src/cli/connections/connPanel.py | 90 ++++++-----
src/cli/controller.py | 70 ++++----
src/cli/graphing/bandwidthStats.py | 53 +++---
src/cli/graphing/graphPanel.py | 31 ++--
src/cli/headerPanel.py | 34 ++--
src/cli/logPanel.py | 137 +++++++--------
src/cli/torrcPanel.py | 30 ++--
src/starter.py | 73 ++++-----
src/util/conf.py | 337 ------------------------------------
src/util/connections.py | 74 ++++----
src/util/hostnames.py | 30 ++--
src/util/log.py | 23 ++-
src/util/panel.py | 9 +-
src/util/procTools.py | 11 +-
src/util/sysTools.py | 25 ++--
src/util/torConfig.py | 66 ++++----
src/util/torTools.py | 18 +-
src/util/uiTools.py | 33 ++--
21 files changed, 488 insertions(+), 794 deletions(-)
diff --git a/armrc.sample b/armrc.sample
index 9072713..2c3a8ca 100644
--- a/armrc.sample
+++ b/armrc.sample
@@ -109,9 +109,17 @@ features.log.maxRefreshRate 300
# ---------------------------
# order
# three comma separated configuration attributes, options including:
-# 0 -> Category, 1 -> Option Name, 2 -> Value, 3 -> Arg Type,
-# 4 -> Arg Usage, 5 -> Summary, 6 -> Description, 7 -> Man Entry,
-# 8 -> Is Default
+#
+# * CATEGORY
+# * OPTION
+# * VALUE
+# * TYPE
+# * ARG_USAGE
+# * SUMMARY
+# * DESCRIPTION
+# * MAN_ENTRY
+# * IS_DEFAULT
+#
# selectionDetails.height
# rows of data for the panel showing details on the current selection, this
# is disabled entirely if zero
@@ -131,7 +139,7 @@ features.log.maxRefreshRate 300
# file.maxLinesPerEntry
# max number of lines to display for a single entry in the torrc
-features.config.order 7, 1, 8
+features.config.order MAN_ENTRY, OPTION, IS_DEFAULT
features.config.selectionDetails.height 6
features.config.prepopulateEditValues true
features.config.state.colWidth.option 25
@@ -200,13 +208,25 @@ features.graph.bw.accounting.isTimeLong false
# ---------------------------------
# listingType
# the primary category of information shown by default, options including:
-# 0 -> IP Address / Port 1 -> Hostname
-# 2 -> Fingerprint 3 -> Nickname
+#
+# * IP_ADDRESS
+# * HOSTNAME
+# * FINGERPRINT
+# * NICKNAME
+#
# order
# three comma separated configuration attributes, options including:
-# 0 -> Category, 1 -> Uptime, 2 -> Listing, 3 -> IP Address,
-# 4 -> Port, 5 -> Hostname, 6 -> Fingerprint, 7 -> Nickname,
-# 8 -> Country
+#
+# * CATEGORY
+# * UPTIME
+# * LISTING
+# * IP_ADDRESS
+# * PORT
+# * HOSTNAME
+# * FINGERPRINT
+# * NICKNAME
+# * COUNTRY
+#
# refreshRate
# rate at which the connection panel contents is redrawn (if higher than the
# connection resolution rate then reducing this won't casue new data to
@@ -227,8 +247,8 @@ features.graph.bw.accounting.isTimeLong false
# showColumn.*
# toggles the visability of the connection table columns
-features.connection.listingType 0
-features.connection.order 0, 2, 1
+features.connection.listingType IP_ADDRESS
+features.connection.order CATEGORY, LISTING, UPTIME
features.connection.refreshRate 5
features.connection.resolveApps true
features.connection.markInitialConnections true
diff --git a/src/cli/configPanel.py b/src/cli/configPanel.py
index 50b66b3..38df235 100644
--- a/src/cli/configPanel.py
+++ b/src/cli/configPanel.py
@@ -9,16 +9,9 @@ import threading
import cli.controller
import popups
-from util import conf, panel, sysTools, torConfig, torTools, uiTools
+from util import panel, sysTools, torConfig, torTools, uiTools
-from stem.util import enum
-
-DEFAULT_CONFIG = {"features.config.selectionDetails.height": 6,
- "features.config.prepopulateEditValues": True,
- "features.config.state.showPrivateOptions": False,
- "features.config.state.showVirtualOptions": False,
- "features.config.state.colWidth.option": 25,
- "features.config.state.colWidth.value": 15}
+from stem.util import conf, enum
# TODO: The arm use cases are incomplete since they currently can't be
# modified, have their descriptions fetched, or even get a complete listing
@@ -38,7 +31,7 @@ CATEGORY_COLOR = {torConfig.Category.GENERAL: "green",
# attributes of a ConfigEntry
Field = enum.Enum("CATEGORY", "OPTION", "VALUE", "TYPE", "ARG_USAGE",
"SUMMARY", "DESCRIPTION", "MAN_ENTRY", "IS_DEFAULT")
-DEFAULT_SORT_ORDER = (Field.MAN_ENTRY, Field.OPTION, Field.IS_DEFAULT)
+
FIELD_ATTR = {Field.CATEGORY: ("Category", "red"),
Field.OPTION: ("Option Name", "blue"),
Field.VALUE: ("Value", "cyan"),
@@ -49,6 +42,26 @@ FIELD_ATTR = {Field.CATEGORY: ("Category", "red"),
Field.MAN_ENTRY: ("Man Page Entry", "blue"),
Field.IS_DEFAULT: ("Is Default", "magenta")}
+def conf_handler(key, value):
+ if key == "features.config.selectionDetails.height":
+ return max(0, value)
+ elif key == "features.config.state.colWidth.option":
+ return max(5, value)
+ elif key == "features.config.state.colWidth.value":
+ return max(5, value)
+ elif key == "features.config.order":
+ return conf.parse_enum_csv(key, value[0], Field, 3)
+
+CONFIG = conf.config_dict("arm", {
+ "features.config.order": [Field.MAN_ENTRY, Field.OPTION, Field.IS_DEFAULT],
+ "features.config.selectionDetails.height": 6,
+ "features.config.prepopulateEditValues": True,
+ "features.config.state.showPrivateOptions": False,
+ "features.config.state.showVirtualOptions": False,
+ "features.config.state.colWidth.option": 25,
+ "features.config.state.colWidth.value": 15,
+}, conf_handler)
+
def getFieldFromLabel(fieldLabel):
"""
Converts field labels back to their enumeration, raising a ValueError if it
@@ -173,23 +186,9 @@ class ConfigPanel(panel.Panel):
be selected and edited.
"""
- def __init__(self, stdscr, configType, config=None):
+ def __init__(self, stdscr, configType):
panel.Panel.__init__(self, stdscr, "configuration", 0)
- self.sortOrdering = DEFAULT_SORT_ORDER
- self._config = dict(DEFAULT_CONFIG)
- if config:
- config.update(self._config, {
- "features.config.selectionDetails.height": 0,
- "features.config.state.colWidth.option": 5,
- "features.config.state.colWidth.value": 5})
-
- sortFields = list(Field)
- customOrdering = config.getIntCSV("features.config.order", None, 3, 0, len(sortFields))
-
- if customOrdering:
- self.sortOrdering = [sortFields[i] for i in customOrdering]
-
self.configType = configType
self.confContents = []
self.confImportantContents = []
@@ -237,16 +236,16 @@ class ConfigPanel(panel.Panel):
confOption, confType = lineComp[0], lineComp[1]
# skips private and virtual entries if not configured to show them
- if not self._config["features.config.state.showPrivateOptions"] and confOption.startswith("__"):
+ if not CONFIG["features.config.state.showPrivateOptions"] and confOption.startswith("__"):
continue
- elif not self._config["features.config.state.showVirtualOptions"] and confType == "Virtual":
+ elif not CONFIG["features.config.state.showVirtualOptions"] and confType == "Virtual":
continue
self.confContents.append(ConfigEntry(confOption, confType, not confOption in customOptions))
elif self.configType == State.ARM:
# loaded via the conf utility
- armConf = conf.getConfig("arm")
- for key in armConf.getKeys():
+ armConf = conf.get_config("arm")
+ for key in armConf.keys():
pass # TODO: implement
# mirror listing with only the important configuration options
@@ -290,9 +289,9 @@ class ConfigPanel(panel.Panel):
"""
self.valsLock.acquire()
- if ordering: self.sortOrdering = ordering
- self.confContents.sort(key=lambda i: (i.getAll(self.sortOrdering)))
- self.confImportantContents.sort(key=lambda i: (i.getAll(self.sortOrdering)))
+ if ordering: CONFIG["features.config.order"] = ordering
+ self.confContents.sort(key=lambda i: (i.getAll(CONFIG["features.config.order"])))
+ self.confImportantContents.sort(key=lambda i: (i.getAll(CONFIG["features.config.order"])))
self.valsLock.release()
def showSortDialog(self):
@@ -303,7 +302,7 @@ class ConfigPanel(panel.Panel):
# set ordering for config options
titleLabel = "Config Option Ordering:"
options = [FIELD_ATTR[field][0] for field in Field]
- oldSelection = [FIELD_ATTR[field][0] for field in self.sortOrdering]
+ oldSelection = [FIELD_ATTR[field][0] for field in CONFIG["features.config.order"]]
optionColors = dict([FIELD_ATTR[field] for field in Field])
results = popups.showSortDialog(titleLabel, options, oldSelection, optionColors)
@@ -317,7 +316,7 @@ class ConfigPanel(panel.Panel):
isKeystrokeConsumed = True
if uiTools.isScrollKey(key):
pageHeight = self.getPreferredSize()[0] - 1
- detailPanelHeight = self._config["features.config.selectionDetails.height"]
+ detailPanelHeight = CONFIG["features.config.selectionDetails.height"]
if detailPanelHeight > 0 and detailPanelHeight + 2 <= pageHeight:
pageHeight -= (detailPanelHeight + 1)
@@ -336,7 +335,7 @@ class ConfigPanel(panel.Panel):
else: initialValue = selection.get(Field.VALUE)
promptMsg = "%s Value (esc to cancel): " % configOption
- isPrepopulated = self._config["features.config.prepopulateEditValues"]
+ isPrepopulated = CONFIG["features.config.prepopulateEditValues"]
newValue = popups.inputPrompt(promptMsg, initialValue if isPrepopulated else "")
if newValue != None and newValue != initialValue:
@@ -494,7 +493,7 @@ class ConfigPanel(panel.Panel):
self.valsLock.acquire()
# panel with details for the current selection
- detailPanelHeight = self._config["features.config.selectionDetails.height"]
+ detailPanelHeight = CONFIG["features.config.selectionDetails.height"]
isScrollbarVisible = False
if detailPanelHeight == 0 or detailPanelHeight + 2 >= height:
# no detail panel
@@ -526,8 +525,8 @@ class ConfigPanel(panel.Panel):
scrollOffset = 3
self.addScrollBar(scrollLoc, scrollLoc + height - detailPanelHeight - 1, len(self._getConfigOptions()), 1 + detailPanelHeight)
- optionWidth = self._config["features.config.state.colWidth.option"]
- valueWidth = self._config["features.config.state.colWidth.value"]
+ optionWidth = CONFIG["features.config.state.colWidth.option"]
+ valueWidth = CONFIG["features.config.state.colWidth.value"]
descriptionWidth = max(0, width - scrollOffset - optionWidth - valueWidth - 2)
# if the description column is overly long then use its space for the
diff --git a/src/cli/connections/connEntry.py b/src/cli/connections/connEntry.py
index 2f57b51..73c3ece 100644
--- a/src/cli/connections/connEntry.py
+++ b/src/cli/connections/connEntry.py
@@ -9,7 +9,7 @@ import curses
from util import connections, torTools, uiTools
from cli.connections import entries
-from stem.util import enum
+from stem.util import conf, enum
# Connection Categories:
# Inbound Relay connection, coming to us.
@@ -35,16 +35,15 @@ LABEL_MIN_PADDING = 2 # min space between listing label and following data
# sort value for scrubbed ip addresses
SCRUBBED_IP_VAL = 255 ** 4
-CONFIG = {"features.connection.markInitialConnections": True,
- "features.connection.showIps": True,
- "features.connection.showExitPort": True,
- "features.connection.showColumn.fingerprint": True,
- "features.connection.showColumn.nickname": True,
- "features.connection.showColumn.destination": True,
- "features.connection.showColumn.expandedIp": True}
-
-def loadConfig(config):
- config.update(CONFIG)
+CONFIG = conf.config_dict("arm", {
+ "features.connection.markInitialConnections": True,
+ "features.connection.showIps": True,
+ "features.connection.showExitPort": True,
+ "features.connection.showColumn.fingerprint": True,
+ "features.connection.showColumn.nickname": True,
+ "features.connection.showColumn.destination": True,
+ "features.connection.showColumn.expandedIp": True,
+})
class Endpoint:
"""
diff --git a/src/cli/connections/connPanel.py b/src/cli/connections/connPanel.py
index 50ba2e8..9f3a5ed 100644
--- a/src/cli/connections/connPanel.py
+++ b/src/cli/connections/connPanel.py
@@ -12,12 +12,7 @@ import cli.popups
from cli.connections import countPopup, descriptorPopup, entries, connEntry, circEntry
from util import connections, panel, torTools, uiTools
-from stem.util import enum
-
-DEFAULT_CONFIG = {"features.connection.resolveApps": True,
- "features.connection.listingType": 0,
- "features.connection.refreshRate": 5,
- "features.connection.showIps": True}
+from stem.util import conf, enum
# height of the detail panel content, not counting top and bottom border
DETAILS_HEIGHT = 7
@@ -25,7 +20,24 @@ DETAILS_HEIGHT = 7
# listing types
Listing = enum.Enum(("IP_ADDRESS", "IP Address"), "HOSTNAME", "FINGERPRINT", "NICKNAME")
-DEFAULT_SORT_ORDER = (entries.SortAttr.CATEGORY, entries.SortAttr.LISTING, entries.SortAttr.UPTIME)
+def conf_handler(key, value):
+ if key == "features.connection.listingType":
+ return conf.parse_enum(key, value, Listing)
+ elif key == "features.connection.refreshRate":
+ return max(1, value)
+ elif key == "features.connection.order":
+ return conf.parse_enum_csv(key, value[0], entries.SortAttr, 3)
+
+CONFIG = conf.config_dict("arm", {
+ "features.connection.resolveApps": True,
+ "features.connection.listingType": Listing.IP_ADDRESS,
+ "features.connection.order": [
+ entries.SortAttr.CATEGORY,
+ entries.SortAttr.LISTING,
+ entries.SortAttr.UPTIME],
+ "features.connection.refreshRate": 5,
+ "features.connection.showIps": True,
+}, conf_handler)
class ConnectionPanel(panel.Panel, threading.Thread):
"""
@@ -33,31 +45,21 @@ class ConnectionPanel(panel.Panel, threading.Thread):
the current consensus and other data sources.
"""
- def __init__(self, stdscr, config=None):
+ def __init__(self, stdscr):
panel.Panel.__init__(self, stdscr, "connections", 0)
threading.Thread.__init__(self)
self.setDaemon(True)
- self._sortOrdering = DEFAULT_SORT_ORDER
- self._config = dict(DEFAULT_CONFIG)
+ # defaults our listing selection to fingerprints if ip address
+ # displaying is disabled
+ #
+ # TODO: This is a little sucky in that it won't work if showIps changes
+ # while we're running (... but arm doesn't allow for that atm)
- if config:
- config.update(self._config, {
- "features.connection.listingType": (0, len(list(Listing)) - 1),
- "features.connection.refreshRate": 1})
-
- # defaults our listing selection to fingerprints if ip address
- # displaying is disabled
- if not self._config["features.connection.showIps"] and self._config["features.connection.listingType"] == 0:
- self._config["features.connection.listingType"] = 2
-
- sortFields = list(entries.SortAttr)
- customOrdering = config.getIntCSV("features.connection.order", None, 3, 0, len(sortFields))
-
- if customOrdering:
- self._sortOrdering = [sortFields[i] for i in customOrdering]
+ if not CONFIG["features.connection.showIps"] and CONFIG["features.connection.listingType"] == 0:
+ armConf = conf.get_config("arm")
+ armConf.set("features.connection.listingType", enumeration.keys()[Listing.index_of(Listing.FINGERPRINT)])
- self._listingType = list(Listing)[self._config["features.connection.listingType"]]
self._scroller = uiTools.Scroller(True)
self._title = "Connections:" # title line of the panel
self._entries = [] # last fetched display entries
@@ -150,8 +152,14 @@ class ConnectionPanel(panel.Panel, threading.Thread):
"""
self.valsLock.acquire()
- if ordering: self._sortOrdering = ordering
- self._entries.sort(key=lambda i: (i.getSortValues(self._sortOrdering, self._listingType)))
+
+ if ordering:
+ armConf = conf.get_config("arm")
+
+ ordering_keys = [entries.SortAttr.keys()[entries.SortAttr.index_of(v)] for v in ordering]
+ armConf.set("features.connection.order", ", ".join(ordering_keys))
+
+ self._entries.sort(key=lambda i: (i.getSortValues(CONFIG["features.connection.order"], self.getListingType())))
self._entryLines = []
for entry in self._entries:
@@ -163,7 +171,7 @@ class ConnectionPanel(panel.Panel, threading.Thread):
Provides the priority content we list connections by.
"""
- return self._listingType
+ return CONFIG["features.connection.listingType"]
def setListingType(self, listingType):
"""
@@ -173,13 +181,15 @@ class ConnectionPanel(panel.Panel, threading.Thread):
listingType - Listing instance for the primary information to be shown
"""
- if self._listingType == listingType: return
+ if self.getListingType() == listingType: return
self.valsLock.acquire()
- self._listingType = listingType
+
+ armConf = conf.get_config("arm")
+ armConf.set("features.connection.listingType", enumeration.keys()[Listing.index_of(listingType)])
# if we're sorting by the listing then we need to resort
- if entries.SortAttr.LISTING in self._sortOrdering:
+ if entries.SortAttr.LISTING in CONFIG["features.connection.order"]:
self.setSortOrder()
self.valsLock.release()
@@ -208,7 +218,7 @@ class ConnectionPanel(panel.Panel, threading.Thread):
# set ordering for connection options
titleLabel = "Connection Ordering:"
options = list(entries.SortAttr)
- oldSelection = self._sortOrdering
+ oldSelection = CONFIG["features.connection.order"]
optionColors = dict([(attr, entries.SORT_COLORS[attr]) for attr in options])
results = cli.popups.showSortDialog(titleLabel, options, oldSelection, optionColors)
if results: self.setSortOrder(results)
@@ -251,7 +261,7 @@ class ConnectionPanel(panel.Panel, threading.Thread):
# dropping the HOSTNAME listing type until we support displaying that content
options.remove(cli.connections.entries.ListingType.HOSTNAME)
- oldSelection = options.index(self._listingType)
+ oldSelection = options.index(self.getListingType())
selection = cli.popups.showMenu(title, options, oldSelection)
# applies new setting
@@ -287,7 +297,7 @@ class ConnectionPanel(panel.Panel, threading.Thread):
while not self._halt:
currentTime = time.time()
- if self.isPaused() or not self._isTorRunning or currentTime - lastDraw < self._config["features.connection.refreshRate"]:
+ if self.isPaused() or not self._isTorRunning or currentTime - lastDraw < CONFIG["features.connection.refreshRate"]:
self._cond.acquire()
if not self._halt: self._cond.wait(0.2)
self._cond.release()
@@ -298,8 +308,8 @@ class ConnectionPanel(panel.Panel, threading.Thread):
# we may have missed multiple updates due to being paused, showing
# another panel, etc so lastDraw might need to jump multiple ticks
- drawTicks = (time.time() - lastDraw) / self._config["features.connection.refreshRate"]
- lastDraw += self._config["features.connection.refreshRate"] * drawTicks
+ drawTicks = (time.time() - lastDraw) / CONFIG["features.connection.refreshRate"]
+ lastDraw += CONFIG["features.connection.refreshRate"] * drawTicks
def getHelp(self):
resolverUtil = connections.getResolver("tor").overwriteResolver
@@ -319,7 +329,7 @@ class ConnectionPanel(panel.Panel, threading.Thread):
if self.isExitsAllowed():
options.append(("e", "exit port usage summary", None))
- options.append(("l", "listed identity", self._listingType.lower()))
+ options.append(("l", "listed identity", self.getListingType().lower()))
options.append(("s", "sort ordering", None))
options.append(("u", "resolving utility", resolverUtil))
return options
@@ -387,7 +397,7 @@ class ConnectionPanel(panel.Panel, threading.Thread):
self.addch(drawLine, scrollOffset + i, prefix[i])
xOffset = scrollOffset + len(prefix)
- drawEntry = entryLine.getListingEntry(width - scrollOffset - len(prefix), currentTime, self._listingType)
+ drawEntry = entryLine.getListingEntry(width - scrollOffset - len(prefix), currentTime, self.getListingType())
for msg, attr in drawEntry:
attr |= extraFormat
@@ -530,7 +540,7 @@ class ConnectionPanel(panel.Panel, threading.Thread):
until the next update if true
"""
- if self.appResolveSinceUpdate or not self._config["features.connection.resolveApps"]: return
+ if self.appResolveSinceUpdate or not CONFIG["features.connection.resolveApps"]: return
unresolvedLines = [l for l in self._entryLines if isinstance(l, connEntry.ConnectionLine) and l.isUnresolvedApp()]
# get the ports used for unresolved applications
diff --git a/src/cli/controller.py b/src/cli/controller.py
index af3fdac..a41cc83 100644
--- a/src/cli/controller.py
+++ b/src/cli/controller.py
@@ -22,29 +22,37 @@ import cli.connections.connPanel
from stem.control import Controller
-from util import connections, conf, hostnames, log, panel, sysTools, torConfig, torTools
+from util import connections, hostnames, log, panel, sysTools, torConfig, torTools
-from stem.util import enum
+from stem.util import conf, enum
ARM_CONTROLLER = None
-CONFIG = {"startup.events": "N3",
- "startup.dataDirectory": "~/.arm",
- "startup.blindModeEnabled": False,
- "features.panels.show.graph": True,
- "features.panels.show.log": True,
- "features.panels.show.connection": True,
- "features.panels.show.config": True,
- "features.panels.show.torrc": True,
- "features.redrawRate": 5,
- "features.refreshRate": 5,
- "features.confirmQuit": True,
- "features.graph.type": 1,
- "features.graph.bw.prepopulate": True,
- "log.startTime": log.INFO,
- "log.torEventTypeUnrecognized": log.INFO,
- "log.configEntryUndefined": log.NOTICE,
- "log.unknownTorPid": log.WARN}
+def conf_handler(key, value):
+ if key == "features.redrawRate":
+ return max(1, value)
+ elif key == "features.refreshRate":
+ return max(0, value)
+
+CONFIG = conf.config_dict("arm", {
+ "startup.events": "N3",
+ "startup.dataDirectory": "~/.arm",
+ "startup.blindModeEnabled": False,
+ "features.panels.show.graph": True,
+ "features.panels.show.log": True,
+ "features.panels.show.connection": True,
+ "features.panels.show.config": True,
+ "features.panels.show.torrc": True,
+ "features.redrawRate": 5,
+ "features.refreshRate": 5,
+ "features.confirmQuit": True,
+ "features.graph.type": 1,
+ "features.graph.bw.prepopulate": True,
+ "log.startTime": log.INFO,
+ "log.torEventTypeUnrecognized": log.INFO,
+ "log.configEntryUndefined": log.NOTICE,
+ "log.unknownTorPid": log.WARN,
+}, conf_handler)
GraphStat = enum.Enum("BANDWIDTH", "CONNECTIONS", "SYSTEM_RESOURCES")
@@ -67,10 +75,9 @@ def initController(stdscr, startTime):
"""
global ARM_CONTROLLER
- config = conf.getConfig("arm")
# initializes the panels
- stickyPanels = [cli.headerPanel.HeaderPanel(stdscr, startTime, config),
+ stickyPanels = [cli.headerPanel.HeaderPanel(stdscr, startTime),
LabelPanel(stdscr)]
pagePanels, firstPagePanels = [], []
@@ -80,21 +87,21 @@ def initController(stdscr, startTime):
if CONFIG["features.panels.show.log"]:
expandedEvents = cli.logPanel.expandEvents(CONFIG["startup.events"])
- firstPagePanels.append(cli.logPanel.LogPanel(stdscr, expandedEvents, config))
+ firstPagePanels.append(cli.logPanel.LogPanel(stdscr, expandedEvents))
if firstPagePanels: pagePanels.append(firstPagePanels)
# second page: connections
if not CONFIG["startup.blindModeEnabled"] and CONFIG["features.panels.show.connection"]:
- pagePanels.append([cli.connections.connPanel.ConnectionPanel(stdscr, config)])
+ pagePanels.append([cli.connections.connPanel.ConnectionPanel(stdscr)])
# third page: config
if CONFIG["features.panels.show.config"]:
- pagePanels.append([cli.configPanel.ConfigPanel(stdscr, cli.configPanel.State.TOR, config)])
+ pagePanels.append([cli.configPanel.ConfigPanel(stdscr, cli.configPanel.State.TOR)])
# fourth page: torrc
if CONFIG["features.panels.show.torrc"]:
- pagePanels.append([cli.torrcPanel.TorrcPanel(stdscr, cli.torrcPanel.Config.TORRC, config)])
+ pagePanels.append([cli.torrcPanel.TorrcPanel(stdscr, cli.torrcPanel.Config.TORRC)])
# initializes the controller
ARM_CONTROLLER = Controller(stdscr, stickyPanels, pagePanels)
@@ -104,7 +111,7 @@ def initController(stdscr, startTime):
if graphPanel:
# statistical monitors for graph
- bwStats = cli.graphing.bandwidthStats.BandwidthStats(config)
+ bwStats = cli.graphing.bandwidthStats.BandwidthStats()
graphPanel.addStats(GraphStat.BANDWIDTH, bwStats)
graphPanel.addStats(GraphStat.SYSTEM_RESOURCES, cli.graphing.resourceStats.ResourceStats())
if not CONFIG["startup.blindModeEnabled"]:
@@ -509,15 +516,6 @@ def startTorMonitor(startTime):
startTime - unix time for when arm was started
"""
- # initializes interface configs
- config = conf.getConfig("arm")
- config.update(CONFIG, {
- "features.redrawRate": 1,
- "features.refreshRate": 0})
-
- cli.graphing.graphPanel.loadConfig(config)
- cli.connections.connEntry.loadConfig(config)
-
# attempts to fetch the tor pid, warning if unsuccessful (this is needed for
# checking its resource usage, among other things)
conn = torTools.getConn()
@@ -592,7 +590,7 @@ def drawTorMonitor(stdscr, startTime):
control = getController()
# provides notice about any unused config keys
- for key in conf.getConfig("arm").getUnusedKeys():
+ for key in conf.get_config("arm").unused_keys():
log.log(CONFIG["log.configEntryUndefined"], "Unused configuration entry: %s" % key)
# tells daemon panels to start
diff --git a/src/cli/graphing/bandwidthStats.py b/src/cli/graphing/bandwidthStats.py
index 2b60c7e..9aecf96 100644
--- a/src/cli/graphing/bandwidthStats.py
+++ b/src/cli/graphing/bandwidthStats.py
@@ -11,6 +11,21 @@ import cli.controller
from cli.graphing import graphPanel
from util import log, sysTools, torTools, uiTools
+from stem.util import conf
+
+def conf_handler(key, value):
+ if key == "features.graph.bw.accounting.rate":
+ return max(1, value)
+
+CONFIG = conf.config_dict("arm", {
+ "features.graph.bw.transferInBytes": False,
+ "features.graph.bw.accounting.show": True,
+ "features.graph.bw.accounting.rate": 10,
+ "features.graph.bw.accounting.isTimeLong": False,
+ "log.graph.bw.prepopulateSuccess": log.NOTICE,
+ "log.graph.bw.prepopulateFailure": log.NOTICE,
+}, conf_handler)
+
DL_COLOR, UL_COLOR = "green", "cyan"
# width at which panel abandons placing optional stats (avg and total) with
@@ -23,26 +38,14 @@ ACCOUNTING_ARGS = ("status", "resetTime", "read", "written", "readLimit", "writt
PREPOPULATE_SUCCESS_MSG = "Read the last day of bandwidth history from the state file"
PREPOPULATE_FAILURE_MSG = "Unable to prepopulate bandwidth information (%s)"
-DEFAULT_CONFIG = {"features.graph.bw.transferInBytes": False,
- "features.graph.bw.accounting.show": True,
- "features.graph.bw.accounting.rate": 10,
- "features.graph.bw.accounting.isTimeLong": False,
- "log.graph.bw.prepopulateSuccess": log.NOTICE,
- "log.graph.bw.prepopulateFailure": log.NOTICE}
-
class BandwidthStats(graphPanel.GraphStats):
"""
Uses tor BW events to generate bandwidth usage graph.
"""
- def __init__(self, config=None, isPauseBuffer=False):
+ def __init__(self, isPauseBuffer=False):
graphPanel.GraphStats.__init__(self)
- self.inputConfig = config
- self._config = dict(DEFAULT_CONFIG)
- if config:
- config.update(self._config, {"features.graph.bw.accounting.rate": 1})
-
# stats prepopulated from tor's state file
self.prepopulatePrimaryTotal = 0
self.prepopulateSecondaryTotal = 0
@@ -78,7 +81,7 @@ class BandwidthStats(graphPanel.GraphStats):
self.initialSecondaryTotal = int(writeTotal) / 1024 # Bytes -> KB
def clone(self, newCopy=None):
- if not newCopy: newCopy = BandwidthStats(self.inputConfig, True)
+ if not newCopy: newCopy = BandwidthStats(True)
newCopy.accountingLastUpdated = self.accountingLastUpdated
newCopy.accountingInfo = self.accountingInfo
@@ -93,7 +96,7 @@ class BandwidthStats(graphPanel.GraphStats):
self._titleStats = [] # force reset of title
self.new_desc_event(None) # updates title params
- if eventType in (torTools.State.INIT, torTools.State.RESET) and self._config["features.graph.bw.accounting.show"]:
+ if eventType in (torTools.State.INIT, torTools.State.RESET) and CONFIG["features.graph.bw.accounting.show"]:
isAccountingEnabled = conn.getInfo('accounting/enabled', None) == '1'
if isAccountingEnabled != self.isAccounting:
@@ -136,21 +139,21 @@ class BandwidthStats(graphPanel.GraphStats):
# results associated with this tor instance
if not uptime or not "-" in uptime:
msg = PREPOPULATE_FAILURE_MSG % "insufficient uptime"
- log.log(self._config["log.graph.bw.prepopulateFailure"], msg)
+ log.log(CONFIG["log.graph.bw.prepopulateFailure"], msg)
return False
# get the user's data directory (usually '~/.tor')
dataDir = conn.getOption("DataDirectory", None)
if not dataDir:
msg = PREPOPULATE_FAILURE_MSG % "data directory not found"
- log.log(self._config["log.graph.bw.prepopulateFailure"], msg)
+ log.log(CONFIG["log.graph.bw.prepopulateFailure"], msg)
return False
# attempt to open the state file
try: stateFile = open("%s%s/state" % (conn.getPathPrefix(), dataDir), "r")
except IOError:
msg = PREPOPULATE_FAILURE_MSG % "unable to read the state file"
- log.log(self._config["log.graph.bw.prepopulateFailure"], msg)
+ log.log(CONFIG["log.graph.bw.prepopulateFailure"], msg)
return False
# get the BWHistory entries (ordered oldest to newest) and number of
@@ -189,7 +192,7 @@ class BandwidthStats(graphPanel.GraphStats):
if not bwReadEntries or not bwWriteEntries or not lastReadTime or not lastWriteTime:
msg = PREPOPULATE_FAILURE_MSG % "bandwidth stats missing from state file"
- log.log(self._config["log.graph.bw.prepopulateFailure"], msg)
+ log.log(CONFIG["log.graph.bw.prepopulateFailure"], msg)
return False
# fills missing entries with the last value
@@ -228,13 +231,13 @@ class BandwidthStats(graphPanel.GraphStats):
msg = PREPOPULATE_SUCCESS_MSG
missingSec = time.time() - min(lastReadTime, lastWriteTime)
if missingSec: msg += " (%s is missing)" % uiTools.getTimeLabel(missingSec, 0, True)
- log.log(self._config["log.graph.bw.prepopulateSuccess"], msg)
+ log.log(CONFIG["log.graph.bw.prepopulateSuccess"], msg)
return True
def bandwidth_event(self, event):
if self.isAccounting and self.isNextTickRedraw():
- if time.time() - self.accountingLastUpdated >= self._config["features.graph.bw.accounting.rate"]:
+ if time.time() - self.accountingLastUpdated >= CONFIG["features.graph.bw.accounting.rate"]:
self._updateAccountingInfo()
# scales units from B to KB for graphing
@@ -309,7 +312,7 @@ class BandwidthStats(graphPanel.GraphStats):
stats[1] = "- %s" % self._getAvgLabel(isPrimary)
stats[2] = ", %s" % self._getTotalLabel(isPrimary)
- stats[0] = "%-14s" % ("%s/sec" % uiTools.getSizeLabel((self.lastPrimary if isPrimary else self.lastSecondary) * 1024, 1, False, self._config["features.graph.bw.transferInBytes"]))
+ stats[0] = "%-14s" % ("%s/sec" % uiTools.getSizeLabel((self.lastPrimary if isPrimary else self.lastSecondary) * 1024, 1, False, CONFIG["features.graph.bw.transferInBytes"]))
# drops label's components if there's not enough space
labeling = graphType + " (" + "".join(stats).strip() + "):"
@@ -342,7 +345,7 @@ class BandwidthStats(graphPanel.GraphStats):
bwBurst = conn.getMyBandwidthBurst()
bwObserved = conn.getMyBandwidthObserved()
bwMeasured = conn.getMyBandwidthMeasured()
- labelInBytes = self._config["features.graph.bw.transferInBytes"]
+ labelInBytes = CONFIG["features.graph.bw.transferInBytes"]
if bwRate and bwBurst:
bwRateLabel = uiTools.getSizeLabel(bwRate, 1, False, labelInBytes)
@@ -369,7 +372,7 @@ class BandwidthStats(graphPanel.GraphStats):
def _getAvgLabel(self, isPrimary):
total = self.primaryTotal if isPrimary else self.secondaryTotal
total += self.prepopulatePrimaryTotal if isPrimary else self.prepopulateSecondaryTotal
- return "avg: %s/sec" % uiTools.getSizeLabel((total / max(1, self.tick + self.prepopulateTicks)) * 1024, 1, False, self._config["features.graph.bw.transferInBytes"])
+ return "avg: %s/sec" % uiTools.getSizeLabel((total / max(1, self.tick + self.prepopulateTicks)) * 1024, 1, False, CONFIG["features.graph.bw.transferInBytes"])
def _getTotalLabel(self, isPrimary):
total = self.primaryTotal if isPrimary else self.secondaryTotal
@@ -396,7 +399,7 @@ class BandwidthStats(graphPanel.GraphStats):
else: tz_offset = time.timezone
sec = time.mktime(time.strptime(endInterval, "%Y-%m-%d %H:%M:%S")) - time.time() - tz_offset
- if self._config["features.graph.bw.accounting.isTimeLong"]:
+ if CONFIG["features.graph.bw.accounting.isTimeLong"]:
queried["resetTime"] = ", ".join(uiTools.getTimeLabels(sec, True))
else:
days = sec / 86400
diff --git a/src/cli/graphing/graphPanel.py b/src/cli/graphing/graphPanel.py
index 16efe8f..b989ef5 100644
--- a/src/cli/graphing/graphPanel.py
+++ b/src/cli/graphing/graphPanel.py
@@ -26,7 +26,7 @@ import stem.control
from util import panel, torTools, uiTools
-from stem.util import enum
+from stem.util import conf, enum
# time intervals at which graphs can be updated
UPDATE_INTERVALS = [("each second", 1), ("5 seconds", 5), ("30 seconds", 30),
@@ -45,19 +45,24 @@ Bounds = enum.Enum("GLOBAL_MAX", "LOCAL_MAX", "TIGHT")
WIDE_LABELING_GRAPH_COL = 50 # minimum graph columns to use wide spacing for x-axis labels
-# used for setting defaults when initializing GraphStats and GraphPanel instances
-CONFIG = {"features.graph.height": 7,
- "features.graph.interval": 0,
- "features.graph.bound": 1,
- "features.graph.maxWidth": 150,
- "features.graph.showIntermediateBounds": True}
+def conf_handler(key, value):
+ if key == "features.graph.height":
+ return max(MIN_GRAPH_HEIGHT, value)
+ elif key == "features.graph.maxWidth":
+ return max(1, value)
+ elif key == "features.graph.interval":
+ return max(0, min(len(UPDATE_INTERVALS) - 1, value))
+ elif key == "features.graph.bound":
+ return max(0, min(2, value))
-def loadConfig(config):
- config.update(CONFIG, {
- "features.graph.height": MIN_GRAPH_HEIGHT,
- "features.graph.maxWidth": 1,
- "features.graph.interval": (0, len(UPDATE_INTERVALS) - 1),
- "features.graph.bound": (0, 2)})
+# used for setting defaults when initializing GraphStats and GraphPanel instances
+CONFIG = conf.config_dict("arm", {
+ "features.graph.height": 7,
+ "features.graph.interval": 0,
+ "features.graph.bound": 1,
+ "features.graph.maxWidth": 150,
+ "features.graph.showIntermediateBounds": True,
+}, conf_handler)
class GraphStats:
"""
diff --git a/src/cli/headerPanel.py b/src/cli/headerPanel.py
index 4ab3daf..07937e0 100644
--- a/src/cli/headerPanel.py
+++ b/src/cli/headerPanel.py
@@ -23,6 +23,7 @@ import stem
import stem.connection
from stem.control import Controller
+from stem.util import conf
import starter
import cli.popups
@@ -42,12 +43,14 @@ FLAG_COLORS = {"Authority": "white", "BadExit": "red", "BadDirectory": "red
VERSION_STATUS_COLORS = {"new": "blue", "new in series": "blue", "obsolete": "red", "recommended": "green",
"old": "red", "unrecommended": "red", "unknown": "cyan"}
-DEFAULT_CONFIG = {"startup.interface.ipAddress": "127.0.0.1",
- "startup.interface.port": 9051,
- "startup.interface.socket": "/var/run/tor/control",
- "features.showFdUsage": False,
- "log.fdUsageSixtyPercent": log.NOTICE,
- "log.fdUsageNinetyPercent": log.WARN}
+CONFIG = conf.config_dict("arm", {
+ "startup.interface.ipAddress": "127.0.0.1",
+ "startup.interface.port": 9051,
+ "startup.interface.socket": "/var/run/tor/control",
+ "features.showFdUsage": False,
+ "log.fdUsageSixtyPercent": log.NOTICE,
+ "log.fdUsageNinetyPercent": log.WARN,
+})
class HeaderPanel(panel.Panel, threading.Thread):
"""
@@ -63,14 +66,11 @@ class HeaderPanel(panel.Panel, threading.Thread):
* volatile parameter that'll be reset on each update
"""
- def __init__(self, stdscr, startTime, config = None):
+ def __init__(self, stdscr, startTime):
panel.Panel.__init__(self, stdscr, "header", 0)
threading.Thread.__init__(self)
self.setDaemon(True)
- self._config = dict(DEFAULT_CONFIG)
- if config: config.update(self._config)
-
self._isTorConnected = torTools.getConn().isAlive()
self._lastUpdate = -1 # time the content was last revised
self._halt = False # terminates thread if true
@@ -140,10 +140,10 @@ class HeaderPanel(panel.Panel, threading.Thread):
controller = None
allowPortConnection, allowSocketConnection, _ = starter.allowConnectionTypes()
- if os.path.exists(self._config["startup.interface.socket"]) and allowSocketConnection:
+ if os.path.exists(CONFIG["startup.interface.socket"]) and allowSocketConnection:
try:
# TODO: um... what about passwords?
- controller = Controller.from_socket_file(self._config["startup.interface.socket"])
+ controller = Controller.from_socket_file(CONFIG["startup.interface.socket"])
controller.authenticate()
except (IOError, stem.SocketError), exc:
controller = None
@@ -151,7 +151,7 @@ class HeaderPanel(panel.Panel, threading.Thread):
if not allowPortConnection:
cli.popups.showMsg("Unable to reconnect (%s)" % exc, 3)
elif not allowPortConnection:
- cli.popups.showMsg("Unable to reconnect (socket '%s' doesn't exist)" % self._config["startup.interface.socket"], 3)
+ cli.popups.showMsg("Unable to reconnect (socket '%s' doesn't exist)" % CONFIG["startup.interface.socket"], 3)
if not controller and allowPortConnection:
# TODO: This has diverged from starter.py's connection, for instance it
@@ -161,7 +161,7 @@ class HeaderPanel(panel.Panel, threading.Thread):
# manageable.
try:
- ctlAddr, ctlPort = self._config["startup.interface.ipAddress"], self._config["startup.interface.port"]
+ ctlAddr, ctlPort = CONFIG["startup.interface.ipAddress"], CONFIG["startup.interface.port"]
controller = Controller.from_port(ctlAddr, ctlPort)
try:
@@ -297,7 +297,7 @@ class HeaderPanel(panel.Panel, threading.Thread):
fdPercent = 100 * self.vals["tor/fdUsed"] / self.vals["tor/fdLimit"]
- if fdPercent >= 60 or self._config["features.showFdUsage"]:
+ if fdPercent >= 60 or CONFIG["features.showFdUsage"]:
fdPercentLabel, fdPercentFormat = "%i%%" % fdPercent, curses.A_NORMAL
if fdPercent >= 95:
fdPercentFormat = curses.A_BOLD | uiTools.getColor("red")
@@ -559,10 +559,10 @@ class HeaderPanel(panel.Panel, threading.Thread):
if fdPercent >= 90 and not self._isFdNinetyPercentWarned:
self._isFdSixtyPercentWarned, self._isFdNinetyPercentWarned = True, True
msg += " If you run out Tor will be unable to continue functioning."
- log.log(self._config["log.fdUsageNinetyPercent"], msg)
+ log.log(CONFIG["log.fdUsageNinetyPercent"], msg)
elif fdPercent >= 60 and not self._isFdSixtyPercentWarned:
self._isFdSixtyPercentWarned = True
- log.log(self._config["log.fdUsageSixtyPercent"], msg)
+ log.log(CONFIG["log.fdUsageSixtyPercent"], msg)
# ps or proc derived resource usage stats
if self.vals["tor/pid"]:
diff --git a/src/cli/logPanel.py b/src/cli/logPanel.py
index d03973d..e196544 100644
--- a/src/cli/logPanel.py
+++ b/src/cli/logPanel.py
@@ -11,12 +11,13 @@ import curses
import logging
import threading
-import stem.util.log
+import stem.util.log # move to a 'from' import when we've dropped the other log util
from stem.response import events
+from stem.util import conf
import popups
from version import VERSION
-from util import conf, log, panel, sysTools, torTools, uiTools
+from util import log, panel, sysTools, torTools, uiTools
TOR_EVENT_TYPES = {
"d": "DEBUG", "a": "ADDRMAP", "k": "DESCCHANGED", "s": "STREAM",
@@ -42,22 +43,35 @@ DAYBREAK_EVENT = "DAYBREAK" # special event for marking when the date changes
TIMEZONE_OFFSET = time.altzone if time.localtime()[8] else time.timezone
ENTRY_INDENT = 2 # spaces an entry's message is indented after the first line
-DEFAULT_CONFIG = {"features.logFile": "",
- "features.log.showDateDividers": True,
- "features.log.showDuplicateEntries": False,
- "features.log.entryDuration": 7,
- "features.log.maxLinesPerEntry": 6,
- "features.log.prepopulate": True,
- "features.log.prepopulateReadLimit": 5000,
- "features.log.maxRefreshRate": 300,
- "features.log.regex": [],
- "cache.logPanel.size": 1000,
- "log.logPanel.prepopulateSuccess": log.INFO,
- "log.logPanel.prepopulateFailed": log.WARN,
- "log.logPanel.logFileOpened": log.NOTICE,
- "log.logPanel.logFileWriteFailed": log.ERR,
- "log.logPanel.forceDoubleRedraw": log.DEBUG,
- "log.configEntryTypeError": log.NOTICE}
+
+def conf_handler(key, value):
+ if key == "features.log.maxLinesPerEntry":
+ return max(1, value)
+ elif key == "features.log.prepopulateReadLimit":
+ return max(0, value)
+ elif key == "features.log.maxRefreshRate":
+ return max(10, value)
+ elif key == "cache.logPanel.size":
+ return max(1000, value)
+
+CONFIG = conf.config_dict("arm", {
+ "features.logFile": "",
+ "features.log.showDateDividers": True,
+ "features.log.showDuplicateEntries": False,
+ "features.log.entryDuration": 7,
+ "features.log.maxLinesPerEntry": 6,
+ "features.log.prepopulate": True,
+ "features.log.prepopulateReadLimit": 5000,
+ "features.log.maxRefreshRate": 300,
+ "features.log.regex": [],
+ "cache.logPanel.size": 1000,
+ "log.logPanel.prepopulateSuccess": log.INFO,
+ "log.logPanel.prepopulateFailed": log.WARN,
+ "log.logPanel.logFileOpened": log.NOTICE,
+ "log.logPanel.logFileWriteFailed": log.ERR,
+ "log.logPanel.forceDoubleRedraw": log.DEBUG,
+ "log.configEntryTypeError": log.NOTICE,
+}, conf_handler)
DUPLICATE_MSG = " [%i duplicate%s hidden]"
@@ -173,16 +187,16 @@ def loadLogMessages():
"""
global COMMON_LOG_MESSAGES
- armConf = conf.getConfig("arm")
+ armConf = conf.get_config("arm")
COMMON_LOG_MESSAGES = {}
- for confKey in armConf.getKeys():
+ for confKey in armConf.keys():
if confKey.startswith("msg."):
eventType = confKey[4:].upper()
messages = armConf.get(confKey, [])
COMMON_LOG_MESSAGES[eventType] = messages
-def getLogFileEntries(runlevels, readLimit = None, addLimit = None, config = None):
+def getLogFileEntries(runlevels, readLimit = None, addLimit = None):
"""
Parses tor's log file for past events matching the given runlevels, providing
a list of log entries (ordered newest to oldest). Limiting the number of read
@@ -193,15 +207,11 @@ def getLogFileEntries(runlevels, readLimit = None, addLimit = None, config = Non
runlevels - event types (DEBUG - ERR) to be returned
readLimit - max lines of the log file that'll be read (unlimited if None)
addLimit - maximum entries to provide back (unlimited if None)
- config - configuration parameters related to this panel, uses defaults
- if left as None
"""
startTime = time.time()
if not runlevels: return []
- if not config: config = DEFAULT_CONFIG
-
# checks tor's configuration for the log file's location (if any exists)
loggingTypes, loggingLocation = None, None
for loggingEntry in torTools.getConn().getOption("Log", [], True):
@@ -252,7 +262,7 @@ def getLogFileEntries(runlevels, readLimit = None, addLimit = None, config = Non
logFile.close()
except IOError:
msg = "Unable to read tor's log file: %s" % loggingLocation
- log.log(config["log.logPanel.prepopulateFailed"], msg)
+ log.log(CONFIG["log.logPanel.prepopulateFailed"], msg)
if not lines: return []
@@ -308,7 +318,7 @@ def getLogFileEntries(runlevels, readLimit = None, addLimit = None, config = Non
if addLimit: loggedEvents = loggedEvents[:addLimit]
msg = "Read %i entries from tor's log file: %s (read limit: %i, runtime: %0.3f)" % (len(loggedEvents), loggingLocation, readLimit, time.time() - startTime)
- log.log(config["log.logPanel.prepopulateSuccess"], msg)
+ log.log(CONFIG["log.logPanel.prepopulateSuccess"], msg)
return loggedEvents
def getDaybreaks(events, ignoreTimeForCache = False):
@@ -474,7 +484,7 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler):
from tor's log file if it exists.
"""
- def __init__(self, stdscr, loggedEvents, config=None):
+ def __init__(self, stdscr, loggedEvents):
panel.Panel.__init__(self, stdscr, "log", 0)
logging.Handler.__init__(self, level = stem.util.log.logging_level(stem.util.log.DEBUG))
@@ -494,28 +504,16 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler):
# regex filters the user has defined
self.filterOptions = []
- self._config = dict(DEFAULT_CONFIG)
-
- if config:
- config.update(self._config, {
- "features.log.maxLinesPerEntry": 1,
- "features.log.prepopulateReadLimit": 0,
- "features.log.maxRefreshRate": 10,
- "cache.logPanel.size": 1000})
+ for filter in CONFIG["features.log.regex"]:
+ # checks if we can't have more filters
+ if len(self.filterOptions) >= MAX_REGEX_FILTERS: break
- for filter in self._config["features.log.regex"]:
- # checks if we can't have more filters
- if len(self.filterOptions) >= MAX_REGEX_FILTERS: break
-
- try:
- re.compile(filter)
- self.filterOptions.append(filter)
- except re.error, exc:
- msg = "Invalid regular expression pattern (%s): %s" % (exc, filter)
- log.log(self._config["log.configEntryTypeError"], msg)
-
- # collapses duplicate log entries if false, showing only the most recent
- self.showDuplicates = self._config["features.log.showDuplicateEntries"]
+ try:
+ re.compile(filter)
+ self.filterOptions.append(filter)
+ except re.error, exc:
+ msg = "Invalid regular expression pattern (%s): %s" % (exc, filter)
+ log.log(CONFIG["log.configEntryTypeError"], msg)
self.loggedEvents = [] # needs to be set before we receive any events
@@ -563,8 +561,8 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler):
conn.addStatusListener(self._resetListener)
# opens log file if we'll be saving entries
- if self._config["features.logFile"]:
- logPath = self._config["features.logFile"]
+ if CONFIG["features.logFile"]:
+ logPath = CONFIG["features.logFile"]
try:
# make dir if the path doesn't already exist
@@ -572,9 +570,9 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler):
if not os.path.exists(baseDir): os.makedirs(baseDir)
self.logFile = open(logPath, "a")
- log.log(self._config["log.logPanel.logFileOpened"], "arm %s opening log file (%s)" % (VERSION, logPath))
+ log.log(CONFIG["log.logPanel.logFileOpened"], "arm %s opening log file (%s)" % (VERSION, logPath))
except (IOError, OSError), exc:
- log.log(self._config["log.logPanel.logFileWriteFailed"], "Unable to write to log file: %s" % sysTools.getFileErrorMsg(exc))
+ log.log(CONFIG["log.logPanel.logFileWriteFailed"], "Unable to write to log file: %s" % sysTools.getFileErrorMsg(exc))
self.logFile = None
stem_logger = stem.util.log.get_logger()
@@ -596,11 +594,11 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler):
# fetches past tor events from log file, if available
torEventBacklog = []
- if self._config["features.log.prepopulate"]:
+ if CONFIG["features.log.prepopulate"]:
setRunlevels = list(set.intersection(set(self.loggedEvents), set(list(log.Runlevel))))
- readLimit = self._config["features.log.prepopulateReadLimit"]
- addLimit = self._config["cache.logPanel.size"]
- torEventBacklog = getLogFileEntries(setRunlevels, readLimit, addLimit, self._config)
+ readLimit = CONFIG["features.log.prepopulateReadLimit"]
+ addLimit = CONFIG["cache.logPanel.size"]
+ torEventBacklog = getLogFileEntries(setRunlevels, readLimit, addLimit)
# gets the set of arm events we're logging
setRunlevels = []
@@ -639,7 +637,8 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler):
deduplicated
"""
- self.showDuplicates = isVisible
+ armConf = conf.get_config("arm")
+ armConf.set("features.log.showDuplicateEntries", str(isVisible))
def registerTorEvent(self, event):
"""
@@ -687,7 +686,7 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler):
self.logFile.write(event.getDisplayMessage(True) + "\n")
self.logFile.flush()
except IOError, exc:
- log.log(self._config["log.logPanel.logFileWriteFailed"], "Unable to write to log file: %s" % sysTools.getFileErrorMsg(exc))
+ log.log(CONFIG["log.logPanel.logFileWriteFailed"], "Unable to write to log file: %s" % sysTools.getFileErrorMsg(exc))
self.logFile = None
self.valsLock.acquire()
@@ -883,7 +882,7 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler):
self.valsLock.release()
elif key in (ord('u'), ord('U')):
self.valsLock.acquire()
- self.showDuplicates = not self.showDuplicates
+ self.setDuplicateVisability(not CONFIG["features.log.showDuplicateEntries"])
self.redraw(True)
self.valsLock.release()
elif key == ord('c') or key == ord('C'):
@@ -929,7 +928,7 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler):
options.append(("a", "save snapshot of the log", None))
options.append(("e", "change logged events", None))
options.append(("f", "log regex filter", "enabled" if self.regexFilter else "disabled"))
- options.append(("u", "duplicate log entries", "visible" if self.showDuplicates else "hidden"))
+ options.append(("u", "duplicate log entries", "visible" if CONFIG["features.log.showDuplicateEntries"] else "hidden"))
options.append(("c", "clear event log", None))
return options
@@ -963,15 +962,15 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler):
seenFirstDateDivider = False
dividerAttr, duplicateAttr = curses.A_BOLD | uiTools.getColor("yellow"), curses.A_BOLD | uiTools.getColor("green")
- isDatesShown = self.regexFilter == None and self._config["features.log.showDateDividers"]
+ isDatesShown = self.regexFilter == None and CONFIG["features.log.showDateDividers"]
eventLog = getDaybreaks(currentLog, self.isPaused()) if isDatesShown else list(currentLog)
- if not self.showDuplicates:
+ if not CONFIG["features.log.showDuplicateEntries"]:
deduplicatedLog = getDuplicates(eventLog)
if deduplicatedLog == None:
msg = "Deduplication took too long. Its current implementation has difficulty handling large logs so disabling it to keep the interface responsive."
log.log(log.WARN, msg)
- self.showDuplicates = True
+ self.setDuplicateVisability(True)
deduplicatedLog = [(entry, 0) for entry in eventLog]
else: deduplicatedLog = [(entry, 0) for entry in eventLog]
@@ -1024,7 +1023,7 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler):
displayQueue.append((duplicateMsg, duplicateAttr, False))
cursorLoc, lineOffset = msgIndent, 0
- maxEntriesPerLine = self._config["features.log.maxLinesPerEntry"]
+ maxEntriesPerLine = CONFIG["features.log.maxLinesPerEntry"]
while displayQueue:
msg, format, includeBreak = displayQueue.pop(0)
drawLine = lineCount + lineOffset
@@ -1085,7 +1084,7 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler):
self.lastContentHeight = newContentHeight
if forceRedraw:
forceRedrawReason = "redrawing the log panel with the corrected content height (%s)" % forceRedrawReason
- log.log(self._config["log.logPanel.forceDoubleRedraw"], forceRedrawReason)
+ log.log(CONFIG["log.logPanel.forceDoubleRedraw"], forceRedrawReason)
self.redraw(True)
self.valsLock.release()
@@ -1105,7 +1104,7 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler):
while not self._halt:
currentDay = daysSince()
timeSinceReset = time.time() - self._lastUpdate
- maxLogUpdateRate = self._config["features.log.maxRefreshRate"] / 1000.0
+ maxLogUpdateRate = CONFIG["features.log.maxRefreshRate"] / 1000.0
sleepTime = 0
if (self.msgLog == self._lastLoggedEvents and lastDay == currentDay) or self.isPaused():
@@ -1281,10 +1280,10 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler):
eventListing - listing of log entries
"""
- cacheSize = self._config["cache.logPanel.size"]
+ cacheSize = CONFIG["cache.logPanel.size"]
if len(eventListing) > cacheSize: del eventListing[cacheSize:]
- logTTL = self._config["features.log.entryDuration"]
+ logTTL = CONFIG["features.log.entryDuration"]
if logTTL > 0:
currentDay = daysSince()
diff --git a/src/cli/torrcPanel.py b/src/cli/torrcPanel.py
index 983768f..635fc85 100644
--- a/src/cli/torrcPanel.py
+++ b/src/cli/torrcPanel.py
@@ -8,12 +8,18 @@ import threading
import popups
-from util import conf, panel, torConfig, torTools, uiTools
+from util import panel, torConfig, torTools, uiTools
-from stem.util import enum
+from stem.util import conf, enum
-DEFAULT_CONFIG = {"features.config.file.showScrollbars": True,
- "features.config.file.maxLinesPerEntry": 8}
+def conf_handler(key, value):
+ if key == "features.config.file.maxLinesPerEntry":
+ return max(1, value)
+
+CONFIG = conf.config_dict("arm", {
+ "features.config.file.showScrollbars": True,
+ "features.config.file.maxLinesPerEntry": 8,
+}, conf_handler)
# TODO: The armrc use case is incomplete. There should be equivilant reloading
# and validation capabilities to the torrc.
@@ -25,13 +31,9 @@ class TorrcPanel(panel.Panel):
area.
"""
- def __init__(self, stdscr, configType, config=None):
+ def __init__(self, stdscr, configType):
panel.Panel.__init__(self, stdscr, "torrc", 0)
- self._config = dict(DEFAULT_CONFIG)
- if config:
- config.update(self._config, {"features.config.file.maxLinesPerEntry": 1})
-
self.valsLock = threading.RLock()
self.configType = configType
self.scroll = 0
@@ -180,9 +182,9 @@ class TorrcPanel(panel.Panel):
loadedTorrc.getLock().release()
else:
- loadedArmrc = conf.getConfig("arm")
- confLocation = loadedArmrc.path
- renderedContents = list(loadedArmrc.rawContents)
+ loadedArmrc = conf.get_config("arm")
+ confLocation = loadedArmrc._path
+ renderedContents = list(loadedArmrc._raw_contents)
# offset to make room for the line numbers
lineNumOffset = 0
@@ -192,7 +194,7 @@ class TorrcPanel(panel.Panel):
# draws left-hand scroll bar if content's longer than the height
scrollOffset = 0
- if self._config["features.config.file.showScrollbars"] and self._lastContentHeight > height - 1:
+ if CONFIG["features.config.file.showScrollbars"] and self._lastContentHeight > height - 1:
scrollOffset = 3
self.addScrollBar(self.scroll, self.scroll + height - 1, self._lastContentHeight, 1)
@@ -267,7 +269,7 @@ class TorrcPanel(panel.Panel):
# draws the rest of the components with line wrap
cursorLoc, lineOffset = lineNumOffset + scrollOffset, 0
- maxLinesPerEntry = self._config["features.config.file.maxLinesPerEntry"]
+ maxLinesPerEntry = CONFIG["features.config.file.maxLinesPerEntry"]
displayQueue = [lineComp[entry] for entry in ("option", "argument", "correction", "comment")]
while displayQueue:
diff --git a/src/starter.py b/src/starter.py
index ccf7aad..3cf4dff 100644
--- a/src/starter.py
+++ b/src/starter.py
@@ -17,12 +17,8 @@ import platform
import version
import cli.controller
import cli.logPanel
-import util.conf
import util.connections
-import util.hostnames
import util.log
-import util.panel
-import util.procTools
import util.sysTools
import util.torConfig
import util.torTools
@@ -30,28 +26,32 @@ import util.uiTools
from stem.control import Controller
import stem.connection
+import stem.util.conf
LOG_DUMP_PATH = os.path.expanduser("~/.arm/log")
DEFAULT_CONFIG = os.path.expanduser("~/.arm/armrc")
-CONFIG = {"startup.controlPassword": None,
- "startup.interface.ipAddress": "127.0.0.1",
- "startup.interface.port": 9051,
- "startup.interface.socket": "/var/run/tor/control",
- "startup.blindModeEnabled": False,
- "startup.events": "N3",
- "startup.dataDirectory": "~/.arm",
- "features.allowDetachedStartup": False,
- "features.config.descriptions.enabled": True,
- "features.config.descriptions.persist": True,
- "log.configDescriptions.readManPageSuccess": util.log.INFO,
- "log.configDescriptions.readManPageFailed": util.log.NOTICE,
- "log.configDescriptions.internalLoadSuccess": util.log.NOTICE,
- "log.configDescriptions.internalLoadFailed": util.log.ERR,
- "log.configDescriptions.persistance.loadSuccess": util.log.INFO,
- "log.configDescriptions.persistance.loadFailed": util.log.INFO,
- "log.configDescriptions.persistance.saveSuccess": util.log.INFO,
- "log.configDescriptions.persistance.saveFailed": util.log.NOTICE,
- "log.savingDebugLog": util.log.NOTICE}
+
+CONFIG = stem.util.conf.config_dict("arm", {
+ "startup.controlPassword": None,
+ "startup.interface.ipAddress": "127.0.0.1",
+ "startup.interface.port": 9051,
+ "startup.interface.socket": "/var/run/tor/control",
+ "startup.blindModeEnabled": False,
+ "startup.events": "N3",
+ "startup.dataDirectory": "~/.arm",
+ "features.allowDetachedStartup": False,
+ "features.config.descriptions.enabled": True,
+ "features.config.descriptions.persist": True,
+ "log.configDescriptions.readManPageSuccess": util.log.INFO,
+ "log.configDescriptions.readManPageFailed": util.log.NOTICE,
+ "log.configDescriptions.internalLoadSuccess": util.log.NOTICE,
+ "log.configDescriptions.internalLoadFailed": util.log.ERR,
+ "log.configDescriptions.persistance.loadSuccess": util.log.INFO,
+ "log.configDescriptions.persistance.loadFailed": util.log.INFO,
+ "log.configDescriptions.persistance.saveSuccess": util.log.INFO,
+ "log.configDescriptions.persistance.saveFailed": util.log.NOTICE,
+ "log.savingDebugLog": util.log.NOTICE,
+})
OPT = "gi:s:c:dbe:vh"
OPT_EXPANDED = ["interface=", "socket=", "config=", "debug", "blind", "event=", "version", "help"]
@@ -113,7 +113,7 @@ def allowConnectionTypes():
(allowPortConnection, allowSocketConnection, allowDetachedStart)
"""
- confKeys = util.conf.getConfig("arm").getKeys()
+ confKeys = stem.util.conf.get_config("arm").keys()
isPortArgPresent = "startup.interface.ipAddress" in confKeys or "startup.interface.port" in confKeys
isSocketArgPresent = "startup.interface.socket" in confKeys
@@ -242,12 +242,12 @@ def _dumpConfig():
check that I didn't miss anything.
"""
- config = util.conf.getConfig("arm")
+ config = stem.util.conf.get_config("arm")
conn = util.torTools.getConn()
# dumps arm's configuration
armConfigEntry = ""
- armConfigKeys = list(config.getKeys())
+ armConfigKeys = list(config.keys())
armConfigKeys.sort()
for configKey in armConfigKeys:
@@ -256,7 +256,7 @@ def _dumpConfig():
# arm.
if not configKey.startswith("config.summary.") and not configKey.startswith("torrc.") and not configKey.startswith("msg."):
- armConfigEntry += "%s -> %s\n" % (configKey, config.contents[configKey])
+ armConfigEntry += "%s -> %s\n" % (configKey, config.get_value(configKey))
if armConfigEntry: armConfigEntry = "Arm Configuration:\n%s" % armConfigEntry
else: armConfigEntry = "Arm Configuration: None"
@@ -338,7 +338,7 @@ if __name__ == '__main__':
except (OSError, IOError), exc:
print "Unable to write to debug log file: %s" % util.sysTools.getFileErrorMsg(exc)
- config = util.conf.getConfig("arm")
+ config = stem.util.conf.get_config("arm")
# attempts to fetch attributes for parsing tor's logs, configuration, etc
pathPrefix = os.path.dirname(sys.argv[0])
@@ -371,13 +371,6 @@ if __name__ == '__main__':
if util.torTools.isTorRunning():
config.set("features.allowDetachedStartup", "false")
- # revises defaults to match user's configuration
- config.update(CONFIG)
-
- # loads user preferences for utilities
- for utilModule in (util.conf, util.connections, util.hostnames, util.log, util.panel, util.procTools, util.sysTools, util.torConfig, util.torTools, util.uiTools):
- utilModule.loadConfig(config)
-
# syncs config and parameters, saving changed config options and overwriting
# undefined parameters with defaults
for key in param.keys():
@@ -435,17 +428,17 @@ if __name__ == '__main__':
# (unfortunately python does allow for direct access to the memory so this
# is the best we can do)
del authPassword
- if "startup.controlPassword" in config.contents:
- del config.contents["startup.controlPassword"]
+ if "startup.controlPassword" in config._contents:
+ del config._contents["startup.controlPassword"]
pwLineNum = None
- for i in range(len(config.rawContents)):
- if config.rawContents[i].strip().startswith("startup.controlPassword"):
+ for i in range(len(config._raw_contents)):
+ if config._raw_contents[i].strip().startswith("startup.controlPassword"):
pwLineNum = i
break
if pwLineNum != None:
- del config.rawContents[i]
+ del config._raw_contents[i]
if controller is None and not allowDetachedStart: sys.exit(1)
diff --git a/src/util/conf.py b/src/util/conf.py
deleted file mode 100644
index a8ca6de..0000000
--- a/src/util/conf.py
+++ /dev/null
@@ -1,337 +0,0 @@
-"""
-This provides handlers for specially formatted configuration files. Entries are
-expected to consist of simple key/value pairs, and anything after "#" is
-stripped as a comment. Excess whitespace is trimmed and empty lines are
-ignored. For instance:
-# This is my sample config
-
-user.name Galen
-user.password yabba1234 # here's an inline comment
-user.notes takes a fancy to pepperjack chese
-blankEntry.example
-
-would be loaded as four entries (the last one's value being an empty string).
-If a key's defined multiple times then the last instance of it is used.
-"""
-
-import threading
-
-from util import log
-
-CONFS = {} # mapping of identifier to singleton instances of configs
-CONFIG = {"log.configEntryNotFound": None,
- "log.configEntryTypeError": log.NOTICE}
-
-def loadConfig(config):
- config.update(CONFIG)
-
-def getConfig(handle):
- """
- Singleton constructor for configuration file instances. If a configuration
- already exists for the handle then it's returned. Otherwise a fresh instance
- is constructed.
-
- Arguments:
- handle - unique identifier used to access this config instance
- """
-
- if not handle in CONFS: CONFS[handle] = Config()
- return CONFS[handle]
-
-class Config():
- """
- Handler for easily working with custom configurations, providing persistence
- to and from files. All operations are thread safe.
-
- Parameters:
- path - location from which configurations are saved and loaded
- contents - mapping of current key/value pairs
- rawContents - last read/written config (initialized to an empty string)
- """
-
- def __init__(self):
- """
- Creates a new configuration instance.
- """
-
- self.path = None # location last loaded from
- self.contents = {} # configuration key/value pairs
- self.contentsLock = threading.RLock()
- self.requestedKeys = set()
- self.rawContents = [] # raw contents read from configuration file
-
- def getValue(self, key, default=None, multiple=False):
- """
- This provides the currently value associated with a given key. If no such
- key exists then this provides the default.
-
- Arguments:
- key - config setting to be fetched
- default - value provided if no such key exists
- multiple - provides back a list of all values if true, otherwise this
- returns the last loaded configuration value
- """
-
- self.contentsLock.acquire()
-
- if key in self.contents:
- val = self.contents[key]
- if not multiple: val = val[-1]
- self.requestedKeys.add(key)
- else:
- msg = "config entry '%s' not found, defaulting to '%s'" % (key, str(default))
- log.log(CONFIG["log.configEntryNotFound"], msg)
- val = default
-
- self.contentsLock.release()
-
- return val
-
- def get(self, key, default=None):
- """
- Fetches the given configuration, using the key and default value to hint
- the type it should be. Recognized types are:
- - logging runlevel if key starts with "log."
- - boolean if default is a boolean (valid values are 'true' and 'false',
- anything else provides the default)
- - integer or float if default is a number (provides default if fails to
- cast)
- - list of all defined values default is a list
- - mapping of all defined values (key/value split via "=>") if the default
- is a dict
-
- Arguments:
- key - config setting to be fetched
- default - value provided if no such key exists
- """
-
- isMultivalue = isinstance(default, list) or isinstance(default, dict)
- val = self.getValue(key, default, isMultivalue)
- if val == default: return val
-
- if key.startswith("log."):
- if val.upper() == "NONE": val = None
- elif val.upper() in list(log.Runlevel): val = val.upper()
- else:
- msg = "Config entry '%s' is expected to be a runlevel" % key
- if default != None: msg += ", defaulting to '%s'" % default
- log.log(CONFIG["log.configEntryTypeError"], msg)
- val = default
- elif isinstance(default, bool):
- if val.lower() == "true": val = True
- elif val.lower() == "false": val = False
- else:
- msg = "Config entry '%s' is expected to be a boolean, defaulting to '%s'" % (key, str(default))
- log.log(CONFIG["log.configEntryTypeError"], msg)
- val = default
- elif isinstance(default, int):
- try: val = int(val)
- except ValueError:
- msg = "Config entry '%s' is expected to be an integer, defaulting to '%i'" % (key, default)
- log.log(CONFIG["log.configEntryTypeError"], msg)
- val = default
- elif isinstance(default, float):
- try: val = float(val)
- except ValueError:
- msg = "Config entry '%s' is expected to be a float, defaulting to '%f'" % (key, default)
- log.log(CONFIG["log.configEntryTypeError"], msg)
- val = default
- elif isinstance(default, list):
- pass # nothing special to do (already a list)
- elif isinstance(default, dict):
- valMap = {}
- for entry in val:
- if "=>" in entry:
- entryKey, entryVal = entry.split("=>", 1)
- valMap[entryKey.strip()] = entryVal.strip()
- else:
- msg = "Ignoring invalid %s config entry (expected a mapping, but \"%s\" was missing \"=>\")" % (key, entry)
- log.log(CONFIG["log.configEntryTypeError"], msg)
- val = valMap
-
- return val
-
- def getStrCSV(self, key, default = None, count = None):
- """
- Fetches the given key as a comma separated value. This provides back a list
- with the stripped values.
-
- Arguments:
- key - config setting to be fetched
- default - value provided if no such key exists or doesn't match the count
- count - if set, then a TypeError is logged (and default returned) if
- the number of elements doesn't match the count
- """
-
- confValue = self.getValue(key)
- if confValue == None: return default
- else:
- confComp = [entry.strip() for entry in confValue.split(",")]
-
- # check if the count doesn't match
- if count != None and len(confComp) != count:
- msg = "Config entry '%s' is expected to be %i comma separated values" % (key, count)
- if default != None and (isinstance(default, list) or isinstance(default, tuple)):
- defaultStr = ", ".join([str(i) for i in default])
- msg += ", defaulting to '%s'" % defaultStr
-
- log.log(CONFIG["log.configEntryTypeError"], msg)
- return default
-
- return confComp
-
- def getIntCSV(self, key, default = None, count = None, minValue = None, maxValue = None):
- """
- Fetches the given comma separated value, logging a TypeError (and returning
- the default) if the values arne't ints or aren't constrained to the given
- bounds.
-
- Arguments:
- key - config setting to be fetched
- default - value provided if no such key exists, doesn't match the count,
- values aren't all integers, or doesn't match the bounds
- count - checks that the number of values matches this if set
- minValue - checks that all values are over this if set
- maxValue - checks that all values are less than this if set
- """
-
- confComp = self.getStrCSV(key, default, count)
- if confComp == default: return default
-
- # validates the input, setting the errorMsg if there's a problem
- errorMsg = None
- baseErrorMsg = "Config entry '%s' is expected to %%s" % key
- if default != None and (isinstance(default, list) or isinstance(default, tuple)):
- defaultStr = ", ".join([str(i) for i in default])
- baseErrorMsg += ", defaulting to '%s'" % defaultStr
-
- for val in confComp:
- if not val.isdigit():
- errorMsg = baseErrorMsg % "only have integer values"
- break
- else:
- if minValue != None and int(val) < minValue:
- errorMsg = baseErrorMsg % "only have values over %i" % minValue
- break
- elif maxValue != None and int(val) > maxValue:
- errorMsg = baseErrorMsg % "only have values less than %i" % maxValue
- break
-
- if errorMsg:
- log.log(CONFIG["log.configEntryTypeError"], errorMsg)
- return default
- else: return [int(val) for val in confComp]
-
- def update(self, confMappings, limits = {}):
- """
- Revises a set of key/value mappings to reflect the current configuration.
- Undefined values are left with their current values.
-
- Arguments:
- confMappings - configuration key/value mappings to be revised
- limits - mappings of limits on numeric values, expected to be of
- the form "configKey -> min" or "configKey -> (min, max)"
- """
-
- for entry in confMappings.keys():
- val = self.get(entry, confMappings[entry])
-
- if entry in limits and (isinstance(val, int) or isinstance(val, float)):
- if isinstance(limits[entry], tuple):
- val = max(val, limits[entry][0])
- val = min(val, limits[entry][1])
- else: val = max(val, limits[entry])
-
- confMappings[entry] = val
-
- def getKeys(self):
- """
- Provides all keys in the currently loaded configuration.
- """
-
- return self.contents.keys()
-
- def getUnusedKeys(self):
- """
- Provides the set of keys that have never been requested.
- """
-
- return set(self.getKeys()).difference(self.requestedKeys)
-
- def set(self, key, value):
- """
- Stores the given configuration value.
-
- Arguments:
- key - config key to be set
- value - config value to be set
- """
-
- self.contentsLock.acquire()
- self.contents[key] = [value]
- self.contentsLock.release()
-
- def clear(self):
- """
- Drops all current key/value mappings.
- """
-
- self.contentsLock.acquire()
- self.contents.clear()
- self.contentsLock.release()
-
- def load(self, path):
- """
- Reads in the contents of the given path, adding its configuration values
- and overwriting any that already exist. If the file's empty then this
- doesn't do anything. Other issues (like having insufficient permissions or
- if the file doesn't exist) result in an IOError.
-
- Arguments:
- path - file path to be loaded
- """
-
- configFile = open(path, "r")
- self.rawContents = configFile.readlines()
- configFile.close()
-
- self.contentsLock.acquire()
-
- for line in self.rawContents:
- # strips any commenting or excess whitespace
- commentStart = line.find("#")
- if commentStart != -1: line = line[:commentStart]
- line = line.strip()
-
- # parse the key/value pair
- if line and " " in line:
- key, value = line.split(" ", 1)
- value = value.strip()
-
- if key in self.contents: self.contents[key].append(value)
- else: self.contents[key] = [value]
-
- self.path = path
- self.contentsLock.release()
-
- def save(self, saveBackup=True):
- """
- Writes the contents of the current configuration. If a configuration file
- already exists then merges as follows:
- - comments and file contents not in this config are left unchanged
- - lines with duplicate keys are stripped (first instance is kept)
- - existing entries are overwritten with their new values, preserving the
- positioning of in-line comments if able
- - config entries not in the file are appended to the end in alphabetical
- order
-
- If problems arise in writing (such as an unset path or insufficient
- permissions) result in an IOError.
-
- Arguments:
- saveBackup - if true and a file already exists then it's saved (with
- '.backup' appended to its filename)
- """
-
- pass # TODO: implement when persistence is needed
-
diff --git a/src/util/connections.py b/src/util/connections.py
index de128c2..5b3c9bb 100644
--- a/src/util/connections.py
+++ b/src/util/connections.py
@@ -23,7 +23,7 @@ import threading
from util import log, procTools, sysTools
-from stem.util import enum
+from stem.util import conf, enum
# enums for connection resolution utilities
Resolver = enum.Enum(("PROC", "proc"),
@@ -76,45 +76,43 @@ RESOLVERS = [] # connection resolvers available via the sin
RESOLVER_FAILURE_TOLERANCE = 3 # number of subsequent failures before moving on to another resolver
RESOLVER_SERIAL_FAILURE_MSG = "Unable to query connections with %s, trying %s"
RESOLVER_FINAL_FAILURE_MSG = "All connection resolvers failed"
-CONFIG = {"queries.connections.minRate": 5,
- "log.connResolverOptions": log.INFO,
- "log.connLookupFailed": log.INFO,
- "log.connLookupFailover": log.NOTICE,
- "log.connLookupAbandon": log.NOTICE,
- "log.connLookupRateGrowing": None,
- "log.configEntryTypeError": log.NOTICE}
-PORT_USAGE = {}
-
-def loadConfig(config):
- config.update(CONFIG)
-
- for configKey in config.getKeys():
- # fetches any port.label.* values
- if configKey.startswith("port.label."):
- portEntry = configKey[11:]
- purpose = config.get(configKey)
-
- divIndex = portEntry.find("-")
- if divIndex == -1:
- # single port
- if portEntry.isdigit():
- PORT_USAGE[portEntry] = purpose
- else:
- msg = "Port value isn't numeric for entry: %s" % configKey
- log.log(CONFIG["log.configEntryTypeError"], msg)
+def conf_handler(key, value):
+ if key.startswith("port.label."):
+ portEntry = key[11:]
+
+ divIndex = portEntry.find("-")
+ if divIndex == -1:
+ # single port
+ if portEntry.isdigit():
+ PORT_USAGE[portEntry] = value
else:
- try:
- # range of ports (inclusive)
- minPort = int(portEntry[:divIndex])
- maxPort = int(portEntry[divIndex + 1:])
- if minPort > maxPort: raise ValueError()
-
- for port in range(minPort, maxPort + 1):
- PORT_USAGE[str(port)] = purpose
- except ValueError:
- msg = "Unable to parse port range for entry: %s" % configKey
- log.log(CONFIG["log.configEntryTypeError"], msg)
+ msg = "Port value isn't numeric for entry: %s" % key
+ log.log(CONFIG["log.configEntryTypeError"], msg)
+ else:
+ try:
+ # range of ports (inclusive)
+ minPort = int(portEntry[:divIndex])
+ maxPort = int(portEntry[divIndex + 1:])
+ if minPort > maxPort: raise ValueError()
+
+ for port in range(minPort, maxPort + 1):
+ PORT_USAGE[str(port)] = value
+ except ValueError:
+ msg = "Unable to parse port range for entry: %s" % key
+ log.log(CONFIG["log.configEntryTypeError"], msg)
+
+CONFIG = conf.config_dict("arm", {
+ "queries.connections.minRate": 5,
+ "log.connResolverOptions": log.INFO,
+ "log.connLookupFailed": log.INFO,
+ "log.connLookupFailover": log.NOTICE,
+ "log.connLookupAbandon": log.NOTICE,
+ "log.connLookupRateGrowing": None,
+ "log.configEntryTypeError": log.NOTICE,
+}, conf_handler)
+
+PORT_USAGE = {}
def isValidIpAddress(ipStr):
"""
diff --git a/src/util/hostnames.py b/src/util/hostnames.py
index 9ae856a..d12f5cb 100644
--- a/src/util/hostnames.py
+++ b/src/util/hostnames.py
@@ -34,25 +34,31 @@ import distutils.sysconfig
from util import log, sysTools
+from stem.util import conf
+
RESOLVER = None # hostname resolver (service is stopped if None)
RESOLVER_LOCK = threading.RLock() # regulates assignment to the RESOLVER
RESOLVER_COUNTER = itertools.count() # atomic counter, providing the age for new entries (for trimming)
DNS_ERROR_CODES = ("1(FORMERR)", "2(SERVFAIL)", "3(NXDOMAIN)", "4(NOTIMP)", "5(REFUSED)", "6(YXDOMAIN)",
"7(YXRRSET)", "8(NXRRSET)", "9(NOTAUTH)", "10(NOTZONE)", "16(BADVERS)")
-CONFIG = {"queries.hostnames.poolSize": 5,
- "queries.hostnames.useSocketModule": False,
- "cache.hostnames.size": 700000,
- "cache.hostnames.trimSize": 200000,
- "log.hostnameCacheTrimmed": log.INFO}
+def conf_handler(key, value):
+ if key == "queries.hostnames.poolSize":
+ return max(1, value)
+ elif key == "cache.hostnames.size":
+ return max(100, value)
+ elif key == "cache.hostnames.trimSize":
+ return max(10, value)
+ elif key == "cache.hostnames.trimSize":
+ return min(value, CONFIG["cache.hostnames.size"] / 2)
-def loadConfig(config):
- config.update(CONFIG, {
- "queries.hostnames.poolSize": 1,
- "cache.hostnames.size": 100,
- "cache.hostnames.trimSize": 10})
-
- CONFIG["cache.hostnames.trimSize"] = min(CONFIG["cache.hostnames.trimSize"], CONFIG["cache.hostnames.size"] / 2)
+CONFIG = conf.config_dict("arm", {
+ "queries.hostnames.poolSize": 5,
+ "queries.hostnames.useSocketModule": False,
+ "cache.hostnames.size": 700000,
+ "cache.hostnames.trimSize": 200000,
+ "log.hostnameCacheTrimmed": log.INFO,
+}, conf_handler)
def start():
"""
diff --git a/src/util/log.py b/src/util/log.py
index 56a6636..60572d5 100644
--- a/src/util/log.py
+++ b/src/util/log.py
@@ -11,7 +11,7 @@ import time
from sys import maxint
from threading import RLock
-from stem.util import enum
+from stem.util import conf, enum
# Logging runlevels. These are *very* commonly used so including shorter
# aliases (so they can be referenced as log.DEBUG, log.WARN, etc).
@@ -28,17 +28,20 @@ _backlog = dict([(level, []) for level in Runlevel])
# mapping of runlevels to the listeners interested in receiving events from it
_listeners = dict([(level, []) for level in Runlevel])
-CONFIG = {"cache.armLog.size": 1000,
- "cache.armLog.trimSize": 200}
+def conf_handler(key, value):
+ if key == "cache.armLog.size":
+ return max(10, value)
+ elif key == "cache.armLog.trimSize":
+ return max(5, value)
+ elif key == "cache.armLog.trimSize":
+ return min(value, CONFIG["cache.armLog.size"] / 2)
-DUMP_FILE = None
+CONFIG = conf.config_dict("arm", {
+ "cache.armLog.size": 1000,
+ "cache.armLog.trimSize": 200,
+}, conf_handler)
-def loadConfig(config):
- config.update(CONFIG, {
- "cache.armLog.size": 10,
- "cache.armLog.trimSize": 5})
-
- CONFIG["cache.armLog.trimSize"] = min(CONFIG["cache.armLog.trimSize"], CONFIG["cache.armLog.size"] / 2)
+DUMP_FILE = None
def setDumpFile(logPath):
"""
diff --git a/src/util/panel.py b/src/util/panel.py
index 50ae2c0..6f69881 100644
--- a/src/util/panel.py
+++ b/src/util/panel.py
@@ -11,6 +11,8 @@ from threading import RLock
from util import log, textInput, uiTools
+from stem.util import conf
+
# global ui lock governing all panel instances (curses isn't thread save and
# concurrency bugs produce especially sinister glitches)
CURSES_LOCK = RLock()
@@ -23,14 +25,13 @@ FORMAT_TAGS = {"<b>": (_noOp, curses.A_BOLD),
"<h>": (_noOp, curses.A_STANDOUT)}
for colorLabel in uiTools.COLOR_LIST: FORMAT_TAGS["<%s>" % colorLabel] = (uiTools.getColor, colorLabel)
-CONFIG = {"log.panelRecreated": log.DEBUG}
+CONFIG = conf.config_dict("arm", {
+ "log.panelRecreated": log.DEBUG,
+})
# prevents curses redraws if set
HALT_ACTIVITY = False
-def loadConfig(config):
- config.update(CONFIG)
-
class Panel():
"""
Wrapper for curses subwindows. This hides most of the ugliness in common
diff --git a/src/util/procTools.py b/src/util/procTools.py
index 835814e..6f3c31a 100644
--- a/src/util/procTools.py
+++ b/src/util/procTools.py
@@ -22,18 +22,17 @@ import base64
from util import log
-from stem.util import enum
+from stem.util import conf, enum
# cached system values
SYS_START_TIME, SYS_PHYSICAL_MEMORY = None, None
CLOCK_TICKS = os.sysconf(os.sysconf_names["SC_CLK_TCK"])
Stat = enum.Enum("COMMAND", "CPU_UTIME", "CPU_STIME", "START_TIME")
-CONFIG = {"queries.useProc": True,
- "log.procCallMade": log.DEBUG}
-
-def loadConfig(config):
- config.update(CONFIG)
+CONFIG = conf.config_dict("arm", {
+ "queries.useProc": True,
+ "log.procCallMade": log.DEBUG,
+})
def isProcAvailable():
"""
diff --git a/src/util/sysTools.py b/src/util/sysTools.py
index 1c84462..e8acf86 100644
--- a/src/util/sysTools.py
+++ b/src/util/sysTools.py
@@ -8,6 +8,8 @@ import threading
from util import log, procTools, uiTools
+from stem.util import conf
+
# Mapping of commands to if they're available or not. This isn't always
# reliable, failing for some special commands. For these the cache is
# prepopulated to skip lookups.
@@ -28,18 +30,17 @@ RESOURCE_TRACKERS = {} # mapping of pids to their resource tracker instances
RUNTIMES = []
SAMPLING_PERIOD = 5 # time of the sampling period
-CONFIG = {"queries.resourceUsage.rate": 5,
- "cache.sysCalls.size": 600,
- "log.sysCallMade": log.DEBUG,
- "log.sysCallCached": None,
- "log.sysCallFailed": log.INFO,
- "log.sysCallCacheGrowing": log.INFO,
- "log.stats.failedProcResolution": log.DEBUG,
- "log.stats.procResolutionFailover": log.INFO,
- "log.stats.failedPsResolution": log.INFO}
-
-def loadConfig(config):
- config.update(CONFIG)
+CONFIG = conf.config_dict("arm", {
+ "queries.resourceUsage.rate": 5,
+ "cache.sysCalls.size": 600,
+ "log.sysCallMade": log.DEBUG,
+ "log.sysCallCached": None,
+ "log.sysCallFailed": log.INFO,
+ "log.sysCallCacheGrowing": log.INFO,
+ "log.stats.failedProcResolution": log.DEBUG,
+ "log.stats.procResolutionFailover": log.INFO,
+ "log.stats.failedPsResolution": log.INFO,
+})
def getSysCpuUsage():
"""
diff --git a/src/util/torConfig.py b/src/util/torConfig.py
index 5566e9d..27636b3 100644
--- a/src/util/torConfig.py
+++ b/src/util/torConfig.py
@@ -11,25 +11,38 @@ import stem.version
from util import log, sysTools, torTools, uiTools
-from stem.util import enum
+from stem.util import conf, enum
-CONFIG = {"features.torrc.validate": True,
- "config.important": [],
- "torrc.alias": {},
- "torrc.label.size.b": [],
- "torrc.label.size.kb": [],
- "torrc.label.size.mb": [],
- "torrc.label.size.gb": [],
- "torrc.label.size.tb": [],
- "torrc.label.time.sec": [],
- "torrc.label.time.min": [],
- "torrc.label.time.hour": [],
- "torrc.label.time.day": [],
- "torrc.label.time.week": [],
- "log.torrc.readFailed": log.WARN,
- "log.configDescriptions.unrecognizedCategory": log.NOTICE,
- "log.torrc.validation.unnecessaryTorrcEntries": log.NOTICE,
- "log.torrc.validation.torStateDiffers": log.WARN}
+def conf_handler(key, value):
+ if key == "config.important":
+ # stores lowercase entries to drop case sensitivity
+ return [entry.lower() for entry in value]
+ elif key.startswith("config.summary."):
+ # we'll look for summary keys with a lowercase config name
+ CONFIG[key.lower()] = value
+ elif key.startswith("torrc.label.") and value:
+ # all the torrc.label.* values are comma separated lists
+ return [entry.strip() for entry in value[0].split(",")]
+
+CONFIG = conf.config_dict("arm", {
+ "features.torrc.validate": True,
+ "config.important": [],
+ "torrc.alias": {},
+ "torrc.label.size.b": [],
+ "torrc.label.size.kb": [],
+ "torrc.label.size.mb": [],
+ "torrc.label.size.gb": [],
+ "torrc.label.size.tb": [],
+ "torrc.label.time.sec": [],
+ "torrc.label.time.min": [],
+ "torrc.label.time.hour": [],
+ "torrc.label.time.day": [],
+ "torrc.label.time.week": [],
+ "log.torrc.readFailed": log.WARN,
+ "log.configDescriptions.unrecognizedCategory": log.NOTICE,
+ "log.torrc.validation.unnecessaryTorrcEntries": log.NOTICE,
+ "log.torrc.validation.torStateDiffers": log.WARN,
+}, conf_handler)
# enums and values for numeric torrc entries
ValueType = enum.Enum("UNRECOGNIZED", "SIZE", "TIME")
@@ -59,23 +72,6 @@ MULTILINE_PARAM = None # cached multiline parameters (lazily loaded)
# torrc options that bind to ports
PORT_OPT = ("SocksPort", "ORPort", "DirPort", "ControlPort", "TransPort")
-def loadConfig(config):
- config.update(CONFIG)
-
- # stores lowercase entries to drop case sensitivity
- CONFIG["config.important"] = [entry.lower() for entry in CONFIG["config.important"]]
-
- for configKey in config.getKeys():
- # fetches any config.summary.* values
- if configKey.startswith("config.summary."):
- CONFIG[configKey.lower()] = config.get(configKey)
-
- # all the torrc.label.* values are comma separated lists
- for configKey in CONFIG.keys():
- if configKey.startswith("torrc.label."):
- configValues = config.get(configKey, "").split(",")
- if configValues: CONFIG[configKey] = [val.strip() for val in configValues]
-
class ManPageEntry:
"""
Information provided about a tor configuration option in its man page entry.
diff --git a/src/util/torTools.py b/src/util/torTools.py
index 7aea8fa..ff85496 100644
--- a/src/util/torTools.py
+++ b/src/util/torTools.py
@@ -18,7 +18,7 @@ import stem.descriptor
from util import connections, log, procTools, sysTools, uiTools
-from stem.util import enum
+from stem.util import conf, enum
# enums for tor's controller state:
# INIT - attached to a new controller
@@ -46,11 +46,14 @@ CONTROLLER = None # singleton Controller instance
UNDEFINED = "<Undefined_ >"
UNKNOWN = "UNKNOWN" # value used by cached information if undefined
-CONFIG = {"features.pathPrefix": "",
- "log.stemPortClosed": log.NOTICE,
- "log.torPrefixPathInvalid": log.NOTICE,
- "log.bsdJailFound": log.INFO,
- "log.unknownBsdJailId": log.WARN}
+
+CONFIG = conf.config_dict("arm", {
+ "features.pathPrefix": "",
+ "log.stemPortClosed": log.NOTICE,
+ "log.torPrefixPathInvalid": log.NOTICE,
+ "log.bsdJailFound": log.INFO,
+ "log.unknownBsdJailId": log.WARN,
+})
# events used for controller functionality:
# NOTICE - used to detect when tor is shut down
@@ -73,9 +76,6 @@ NO_SPAWN = False
# startup performance so we don't introduce a sleep while initializing.
IS_STARTUP_SIGNAL = True
-def loadConfig(config):
- config.update(CONFIG)
-
def getPid(controlPort=9051, pidFilePath=None):
"""
Attempts to determine the process id for a running tor process, using the
diff --git a/src/util/uiTools.py b/src/util/uiTools.py
index c1f1a86..10f922b 100644
--- a/src/util/uiTools.py
+++ b/src/util/uiTools.py
@@ -12,7 +12,7 @@ import curses
from curses.ascii import isprint
from util import log
-from stem.util import enum
+from stem.util import conf, enum
# colors curses can handle
COLOR_LIST = {"red": curses.COLOR_RED, "green": curses.COLOR_GREEN,
@@ -40,27 +40,26 @@ TIME_UNITS = [(86400.0, "d", " day"), (3600.0, "h", " hour"),
Ending = enum.Enum("ELLIPSE", "HYPHEN")
SCROLL_KEYS = (curses.KEY_UP, curses.KEY_DOWN, curses.KEY_PPAGE, curses.KEY_NPAGE, curses.KEY_HOME, curses.KEY_END)
-CONFIG = {"features.colorInterface": True,
- "features.acsSupport": True,
- "features.printUnicode": True,
- "log.cursesColorSupport": log.INFO,
- "log.configEntryTypeError": log.NOTICE}
+
+def conf_handler(key, value):
+ if key == "features.colorOverride" and value != "none":
+ try: setColorOverride(value)
+ except ValueError, exc:
+ log.log(CONFIG["log.configEntryTypeError"], exc)
+
+CONFIG = conf.config_dict("arm", {
+ "features.colorOverride": "none",
+ "features.colorInterface": True,
+ "features.acsSupport": True,
+ "features.printUnicode": True,
+ "log.cursesColorSupport": log.INFO,
+ "log.configEntryTypeError": log.NOTICE,
+}, conf_handler)
# Flag indicating if unicode is supported by curses. If None then this has yet
# to be determined.
IS_UNICODE_SUPPORTED = None
-def loadConfig(config):
- config.update(CONFIG)
-
- CONFIG["features.colorOverride"] = "none"
- colorOverride = config.get("features.colorOverride", "none")
-
- if colorOverride != "none":
- try: setColorOverride(colorOverride)
- except ValueError, exc:
- log.log(CONFIG["log.configEntryTypeError"], exc)
-
def demoGlyphs():
"""
Displays all ACS options with their corresponding representation. These are
1
0

[translation/vidalia_help] Update translations for vidalia_help
by translation@torproject.org 02 Jan '13
by translation@torproject.org 02 Jan '13
02 Jan '13
commit 7cab278bb648798f99a05972328b67d9eb12f2b4
Author: Translation commit bot <translation(a)torproject.org>
Date: Wed Jan 2 01:15:29 2013 +0000
Update translations for vidalia_help
---
tr/running.po | 4 +---
1 files changed, 1 insertions(+), 3 deletions(-)
diff --git a/tr/running.po b/tr/running.po
index 94ff9e2..b7a7b1f 100644
--- a/tr/running.po
+++ b/tr/running.po
@@ -12,7 +12,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: tr\n"
-"Plural-Forms: nplurals=1; plural=0\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
#. type: Content of: <html><body><h1>
#: en/running.html:16
@@ -147,5 +147,3 @@ msgid ""
"You can also check the <a href=\"log.html\">message log</a> for details "
"about any problems Tor encountered before it exited."
msgstr ""
-
-
1
0

[translation/orbot_completed] Update translations for orbot_completed
by translation@torproject.org 02 Jan '13
by translation@torproject.org 02 Jan '13
02 Jan '13
commit 08c52a777fd1aae2b745630f356bb6fffde943a0
Author: Translation commit bot <translation(a)torproject.org>
Date: Wed Jan 2 01:15:10 2013 +0000
Update translations for orbot_completed
---
values-es/strings.xml | 34 +++++++++++++++++-----------------
1 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/values-es/strings.xml b/values-es/strings.xml
index 8975f26..e8d3415 100644
--- a/values-es/strings.xml
+++ b/values-es/strings.xml
@@ -155,41 +155,41 @@
<string name="bridge_requires_ip">Para utilizar la funcion bridge (repetidor puente, acceso a Tor de publicitación restringida), debe introducir al menos una dirección IP de bridge.</string>
<string name="send_email_for_bridges">Envie un correo a bridges(a)torproject.org incluyendo una línea con \"get bridges\" por si sólo en el cuerpo del mensaje, desde una cuenta con dominio gmail.com, yahoo.com o yahoo.cn (que soportan DKIM)</string>
<string name="error">Error</string>
- <string name="your_reachableaddresses_settings_caused_an_exception_">¡Su configuración ReachableAdresses (direcciones accesibles) ha producido una excepción!</string>
+ <string name="your_reachableaddresses_settings_caused_an_exception_">¡Sus \'Reglas de direcciones accesibles\' han producido una excepción!</string>
<string name="your_relay_settings_caused_an_exception_">¡La configuración de su repetidor (el nodo de Tor que ejecuta) ha producido una excepción!</string>
<string name="exit_nodes">Nodos de salida</string>
<string name="fingerprints_nicks_countries_and_addresses_for_the_last_hop">Reglas de identificación de repetidores de salida de la red Tor, mediante huellas de validación de claves (fingerprints), alias (nicks), códigos de país y direcciones (o rangos)</string>
- <string name="enter_exit_nodes">Introduzca reglas de identificación de repetidores de salida</string>
+ <string name="enter_exit_nodes">Introduzca repetidores de salida</string>
<string name="exclude_nodes">Excluír nodos</string>
- <string name="fingerprints_nicks_countries_and_addresses_to_exclude">Reglas de identificación de repetidores de a evitar en la red tor, mediante huellas de validación de claves (fingerprints), alias (nicks), códigos de país y direcciones (o rangos)</string>
- <string name="enter_exclude_nodes">Introduzca reglas de identificación de s a excluír</string>
+ <string name="fingerprints_nicks_countries_and_addresses_to_exclude">Reglas de identificación de repetidores a evitar en la red Tor, mediante huellas de validación de claves (fingerprints), alias (nicks), códigos de país y direcciones (o rangos)</string>
+ <string name="enter_exclude_nodes">Introduzca repetidores a evitar</string>
<string name="strict_nodes">Hacer estricta la exclusión de nodos (incluso si hay fallos de comunicación)</string>
- <string name="use_only_these_specified_nodes">Usar *sólo* estos nodos especificados</string>
+ <string name="use_only_these_specified_nodes">Usar - sólo - estos nodos especificados</string>
<string name="bridges">Bridges (repetidores puente, accesos a Tor de publicitación restringida) </string>
<string name="use_bridges">Utilizar bridges (prevalece sobre la configuración de nodos de entrada) </string>
<string name="bridges_obfuscated">Bridges ofuscados (contra el análisis DPI de tráfico) </string>
- <string name="enable_alternate_entrance_nodes_into_the_tor_network">Habilita nodos alternativos de entrada en la red Tor (cuyos descriptores propagan las autoridades de repositorios de bridges de forma restringida, o usted mismo)</string>
+ <string name="enable_alternate_entrance_nodes_into_the_tor_network">Habilita el uso de repetidores puente (bridges, entradas alternativas en la red Tor de publicitación restringida)</string>
<string name="enable_if_configured_bridges_are_obfuscated_bridges">Habilítelo si los bridges (repetidores puente, entradas a Tor de publicitación restringida) de su lista de configuración están ofuscados, encapsulando el tráfico SSL para evitar ser detectados. </string>
<string name="ip_address_and_port_of_bridges">Direcciones IP y puertos de los bridges</string>
<string name="enter_bridge_addresses">Introduzca direcciones de bridge</string>
- <string name="relays">Repetidores de tráfico (relays)</string>
+ <string name="relays">Repetidores</string>
<string name="relaying">Repitiendo tráfico</string>
<string name="enable_your_device_to_be_a_non_exit_relay">Deshabilitar el que su dispositivo repetidor lo sea de salida (de la red Tor) </string>
- <string name="relay_port">Puerto de su repetidor</string>
- <string name="listening_port_for_your_tor_relay">Puerto de escucha de su repetidor Tor</string>
- <string name="enter_or_port">Introduzca puerto para OR (Onion Router)</string>
+ <string name="relay_port">Puerto de repetidor</string>
+ <string name="listening_port_for_your_tor_relay">Puerto de escucha para su repetidor Tor</string>
+ <string name="enter_or_port">Introduzca puerto para OR (Onion Routing, repositorio de repetidores)</string>
<string name="relay_nickname">Alias del repetidor</string>
- <string name="the_nickname_for_your_tor_relay">El apodo para su repetidor de tráfico Tor</string>
- <string name="enter_a_custom_relay_nickname">Introduzca un alias personalizado para el repetidor</string>
- <string name="reachable_addresses">Reglas de direcciones accesibles ([accept(default)|reject] IP:port, ...)</string>
+ <string name="the_nickname_for_your_tor_relay">El apodo que identificará a su repetidor en la red Tor</string>
+ <string name="enter_a_custom_relay_nickname">Introduzca un alias personalizado para su repetidor</string>
+ <string name="reachable_addresses">Reglas de direcciones accesibles ([accept(por defecto)|reject] IP:port, etc.)</string>
<string name="run_as_a_client_behind_a_firewall_with_restrictive_policies">Ejecutar Tor sólo como cliente detrás de un cortafuegos (firewall) con políticas restrictivas</string>
<string name="reachable_ports">Puertos accesibles</string>
<string name="ports_reachable_behind_a_restrictive_firewall">Puertos accesibles detrás de un firewall restrictivo (80 y 443 por defecto)</string>
<string name="enter_ports">Introduzca puertos</string>
- <string name="enable_hidden_services">Activar alojamiento de servicios ocultos (que hospedará en la red Tor)</string>
- <string name="run_servers_accessible_via_the_tor_network">Permite el acceso a servidores ocultos por dispositivo (de IP oculta al usuario y con dominio no DNS .onion) a través de, y hospedados en, la red Tor</string>
- <string name="enter_localhost_ports_for_hidden_services">Introduzca puertos para los servicios ocultos de su equipo</string>
- <string name="hidden_service_ports">Puertos de los servicios ocultos (que hospedará en la red Tor)</string>
+ <string name="enable_hidden_services">Activar alojamiento de servicios ocultos (ofrecidos en la red Tor)</string>
+ <string name="run_servers_accessible_via_the_tor_network">Permite el acceso a servidores ocultos por dispositivo (de IP oculta al usuario y con dominio .onion, sin DNS) ofrecidos a través de la red Tor</string>
+ <string name="enter_localhost_ports_for_hidden_services">Introduzca los puertos locales de sus servicios ocultos</string>
+ <string name="hidden_service_ports">Puertos de los servicios ocultos</string>
<string name="the_addressable_name_for_your_hidden_service_generated_automatically_">El nombre direccionable (.onion, sin DNS, generado automáticamente) para su servicio oculto</string>
<string name="enable_debug_log_to_output_must_use_adb_or_alogcat_to_view_">Habilitar el registro de depuración (debug log) a la salida (debe utilizar adb o aLogCat para verlo)</string>
<string name="project_home">Página principal del proyecto:</string>
1
0

02 Jan '13
commit 3881e5b87d978c1ead99cf150310c792f188a9cf
Author: Translation commit bot <translation(a)torproject.org>
Date: Wed Jan 2 01:15:08 2013 +0000
Update translations for orbot
---
values-es/strings.xml | 34 +++++++++++++++++-----------------
1 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/values-es/strings.xml b/values-es/strings.xml
index 8975f26..e8d3415 100644
--- a/values-es/strings.xml
+++ b/values-es/strings.xml
@@ -155,41 +155,41 @@
<string name="bridge_requires_ip">Para utilizar la funcion bridge (repetidor puente, acceso a Tor de publicitación restringida), debe introducir al menos una dirección IP de bridge.</string>
<string name="send_email_for_bridges">Envie un correo a bridges(a)torproject.org incluyendo una línea con \"get bridges\" por si sólo en el cuerpo del mensaje, desde una cuenta con dominio gmail.com, yahoo.com o yahoo.cn (que soportan DKIM)</string>
<string name="error">Error</string>
- <string name="your_reachableaddresses_settings_caused_an_exception_">¡Su configuración ReachableAdresses (direcciones accesibles) ha producido una excepción!</string>
+ <string name="your_reachableaddresses_settings_caused_an_exception_">¡Sus \'Reglas de direcciones accesibles\' han producido una excepción!</string>
<string name="your_relay_settings_caused_an_exception_">¡La configuración de su repetidor (el nodo de Tor que ejecuta) ha producido una excepción!</string>
<string name="exit_nodes">Nodos de salida</string>
<string name="fingerprints_nicks_countries_and_addresses_for_the_last_hop">Reglas de identificación de repetidores de salida de la red Tor, mediante huellas de validación de claves (fingerprints), alias (nicks), códigos de país y direcciones (o rangos)</string>
- <string name="enter_exit_nodes">Introduzca reglas de identificación de repetidores de salida</string>
+ <string name="enter_exit_nodes">Introduzca repetidores de salida</string>
<string name="exclude_nodes">Excluír nodos</string>
- <string name="fingerprints_nicks_countries_and_addresses_to_exclude">Reglas de identificación de repetidores de a evitar en la red tor, mediante huellas de validación de claves (fingerprints), alias (nicks), códigos de país y direcciones (o rangos)</string>
- <string name="enter_exclude_nodes">Introduzca reglas de identificación de s a excluír</string>
+ <string name="fingerprints_nicks_countries_and_addresses_to_exclude">Reglas de identificación de repetidores a evitar en la red Tor, mediante huellas de validación de claves (fingerprints), alias (nicks), códigos de país y direcciones (o rangos)</string>
+ <string name="enter_exclude_nodes">Introduzca repetidores a evitar</string>
<string name="strict_nodes">Hacer estricta la exclusión de nodos (incluso si hay fallos de comunicación)</string>
- <string name="use_only_these_specified_nodes">Usar *sólo* estos nodos especificados</string>
+ <string name="use_only_these_specified_nodes">Usar - sólo - estos nodos especificados</string>
<string name="bridges">Bridges (repetidores puente, accesos a Tor de publicitación restringida) </string>
<string name="use_bridges">Utilizar bridges (prevalece sobre la configuración de nodos de entrada) </string>
<string name="bridges_obfuscated">Bridges ofuscados (contra el análisis DPI de tráfico) </string>
- <string name="enable_alternate_entrance_nodes_into_the_tor_network">Habilita nodos alternativos de entrada en la red Tor (cuyos descriptores propagan las autoridades de repositorios de bridges de forma restringida, o usted mismo)</string>
+ <string name="enable_alternate_entrance_nodes_into_the_tor_network">Habilita el uso de repetidores puente (bridges, entradas alternativas en la red Tor de publicitación restringida)</string>
<string name="enable_if_configured_bridges_are_obfuscated_bridges">Habilítelo si los bridges (repetidores puente, entradas a Tor de publicitación restringida) de su lista de configuración están ofuscados, encapsulando el tráfico SSL para evitar ser detectados. </string>
<string name="ip_address_and_port_of_bridges">Direcciones IP y puertos de los bridges</string>
<string name="enter_bridge_addresses">Introduzca direcciones de bridge</string>
- <string name="relays">Repetidores de tráfico (relays)</string>
+ <string name="relays">Repetidores</string>
<string name="relaying">Repitiendo tráfico</string>
<string name="enable_your_device_to_be_a_non_exit_relay">Deshabilitar el que su dispositivo repetidor lo sea de salida (de la red Tor) </string>
- <string name="relay_port">Puerto de su repetidor</string>
- <string name="listening_port_for_your_tor_relay">Puerto de escucha de su repetidor Tor</string>
- <string name="enter_or_port">Introduzca puerto para OR (Onion Router)</string>
+ <string name="relay_port">Puerto de repetidor</string>
+ <string name="listening_port_for_your_tor_relay">Puerto de escucha para su repetidor Tor</string>
+ <string name="enter_or_port">Introduzca puerto para OR (Onion Routing, repositorio de repetidores)</string>
<string name="relay_nickname">Alias del repetidor</string>
- <string name="the_nickname_for_your_tor_relay">El apodo para su repetidor de tráfico Tor</string>
- <string name="enter_a_custom_relay_nickname">Introduzca un alias personalizado para el repetidor</string>
- <string name="reachable_addresses">Reglas de direcciones accesibles ([accept(default)|reject] IP:port, ...)</string>
+ <string name="the_nickname_for_your_tor_relay">El apodo que identificará a su repetidor en la red Tor</string>
+ <string name="enter_a_custom_relay_nickname">Introduzca un alias personalizado para su repetidor</string>
+ <string name="reachable_addresses">Reglas de direcciones accesibles ([accept(por defecto)|reject] IP:port, etc.)</string>
<string name="run_as_a_client_behind_a_firewall_with_restrictive_policies">Ejecutar Tor sólo como cliente detrás de un cortafuegos (firewall) con políticas restrictivas</string>
<string name="reachable_ports">Puertos accesibles</string>
<string name="ports_reachable_behind_a_restrictive_firewall">Puertos accesibles detrás de un firewall restrictivo (80 y 443 por defecto)</string>
<string name="enter_ports">Introduzca puertos</string>
- <string name="enable_hidden_services">Activar alojamiento de servicios ocultos (que hospedará en la red Tor)</string>
- <string name="run_servers_accessible_via_the_tor_network">Permite el acceso a servidores ocultos por dispositivo (de IP oculta al usuario y con dominio no DNS .onion) a través de, y hospedados en, la red Tor</string>
- <string name="enter_localhost_ports_for_hidden_services">Introduzca puertos para los servicios ocultos de su equipo</string>
- <string name="hidden_service_ports">Puertos de los servicios ocultos (que hospedará en la red Tor)</string>
+ <string name="enable_hidden_services">Activar alojamiento de servicios ocultos (ofrecidos en la red Tor)</string>
+ <string name="run_servers_accessible_via_the_tor_network">Permite el acceso a servidores ocultos por dispositivo (de IP oculta al usuario y con dominio .onion, sin DNS) ofrecidos a través de la red Tor</string>
+ <string name="enter_localhost_ports_for_hidden_services">Introduzca los puertos locales de sus servicios ocultos</string>
+ <string name="hidden_service_ports">Puertos de los servicios ocultos</string>
<string name="the_addressable_name_for_your_hidden_service_generated_automatically_">El nombre direccionable (.onion, sin DNS, generado automáticamente) para su servicio oculto</string>
<string name="enable_debug_log_to_output_must_use_adb_or_alogcat_to_view_">Habilitar el registro de depuración (debug log) a la salida (debe utilizar adb o aLogCat para verlo)</string>
<string name="project_home">Página principal del proyecto:</string>
1
0

[translation/orbot_completed] Update translations for orbot_completed
by translation@torproject.org 02 Jan '13
by translation@torproject.org 02 Jan '13
02 Jan '13
commit 9238a2aa7207b1225a24c7bcba73c42e07afe3ea
Author: Translation commit bot <translation(a)torproject.org>
Date: Wed Jan 2 00:45:12 2013 +0000
Update translations for orbot_completed
---
values-es/strings.xml | 26 +++++++++++++-------------
1 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/values-es/strings.xml b/values-es/strings.xml
index 7f9c4f9..8975f26 100644
--- a/values-es/strings.xml
+++ b/values-es/strings.xml
@@ -120,7 +120,7 @@
<string name="wizard_transproxy_hint">(Marque esta casilla si no tiene idea de qué estamos hablando)</string>
<string name="wizard_transproxy_none">Ninguno</string>
<string name="pref_transparent_tethering_title">Tor tethering</string>
- <string name="pref_transparent_tethering_summary">Habilita la proxyficación transparente de Tor para dispositivos pasarela (tethered, dispositivos inalabricos que hacen de pasarela de salida a Internet para otros dispositivos conectados a ellos a través de Wifi, USB o Bluetooth) -- (requiere reinicio)</string>
+ <string name="pref_transparent_tethering_summary">Habilita la proxyficación transparente de Tor para dispositivos tethered (dispositivos móviles/celuares pasarela a Internet para otros dispositivos conectados a ellos a través de Wifi, USB o Bluetooth) -- (requiere reinicio)</string>
<string name="button_grant_superuser">Solicitar permisos de superusuario</string>
<string name="pref_select_apps">Seleccionar aplicaciones</string>
<string name="pref_select_apps_summary">Escoja las aplicaciones a redirigir través de Tor</string>
@@ -145,24 +145,24 @@
<string name="setting_up_full_transparent_proxying_">Estableciendo proxyficación transparente completa... </string>
<string name="setting_up_app_based_transparent_proxying_">Estableciendo proxyficación transparente por aplicaciones... </string>
<string name="transparent_proxying_enabled">Proxyficación transparente ACTIVADA</string>
- <string name="transproxy_enabled_for_tethering_">¡TransProxy habilitado para tethering! (proxyficación transparente para su pasarela a Internet móvil)</string>
+ <string name="transproxy_enabled_for_tethering_">¡TransProxy (proxyficación transparente) habilitado para tethering (pasarela a Internet móvil)!</string>
<string name="warning_error_starting_transparent_proxying_">ADVERTENCIA: ¡Error al iniciar la proxyficación transparente!</string>
<string name="transproxy_rules_cleared">Reglas de TransProxy borradas</string>
<string name="couldn_t_start_tor_process_">No se pudo iniciar el proceso de Tor: </string>
- <string name="privoxy_is_running_on_port_">Privoxy se está ejecutando en el puerto: </string>
+ <string name="privoxy_is_running_on_port_">Privoxy (proxy web de filtrado) se está ejecutando en el puerto: </string>
<string name="setting_up_port_based_transparent_proxying_">Estableciendo proxyficación transparente por puertos... </string>
- <string name="bridge_error">Error de bridge (repetidor puente, acceso a Tor de publicitación restringida)</string>
- <string name="bridge_requires_ip">Para utilizar la funcion bridge, debe introducir al menos una dirección IP de bridge.</string>
- <string name="send_email_for_bridges">Envie un correo a bridges(a)torproject.org sólo con el texto \"get bridges\" en el cuerpo del mensaje, desde una cuenta con dominio gmail.com, yahoo.com o yahoo.cn (que soportan DKIM)</string>
+ <string name="bridge_error">Error del bridge</string>
+ <string name="bridge_requires_ip">Para utilizar la funcion bridge (repetidor puente, acceso a Tor de publicitación restringida), debe introducir al menos una dirección IP de bridge.</string>
+ <string name="send_email_for_bridges">Envie un correo a bridges(a)torproject.org incluyendo una línea con \"get bridges\" por si sólo en el cuerpo del mensaje, desde una cuenta con dominio gmail.com, yahoo.com o yahoo.cn (que soportan DKIM)</string>
<string name="error">Error</string>
- <string name="your_reachableaddresses_settings_caused_an_exception_">¡Su configuración ReachableAdresses (direcciones alcanzables) ha producido una excepción!</string>
- <string name="your_relay_settings_caused_an_exception_">¡Su configuración de repetidor de tráfico ha producido una excepción!</string>
+ <string name="your_reachableaddresses_settings_caused_an_exception_">¡Su configuración ReachableAdresses (direcciones accesibles) ha producido una excepción!</string>
+ <string name="your_relay_settings_caused_an_exception_">¡La configuración de su repetidor (el nodo de Tor que ejecuta) ha producido una excepción!</string>
<string name="exit_nodes">Nodos de salida</string>
- <string name="fingerprints_nicks_countries_and_addresses_for_the_last_hop">Reglas de identificación de nodos, fingerprints (huellas de validación de claves), nicks (alias), códigos de país y direcciones, para el último salto (de salida de la red Tor)</string>
- <string name="enter_exit_nodes">Introduzca reglas para nodos de salida</string>
- <string name="exclude_nodes">Excluír nodos (evitarlos en la red Tor)</string>
- <string name="fingerprints_nicks_countries_and_addresses_to_exclude">Reglas de identificación de nodos, fingerprints (huellas de validación de claves), nicks (alias), códigos de país y direcciones a excluír (evitar en la red Tor) excepto si provocan fallos de comunicación. Si se aplican prevalecen sobre la configuración de nodos de entrada.</string>
- <string name="enter_exclude_nodes">Introduzca reglas para nodos a excluír</string>
+ <string name="fingerprints_nicks_countries_and_addresses_for_the_last_hop">Reglas de identificación de repetidores de salida de la red Tor, mediante huellas de validación de claves (fingerprints), alias (nicks), códigos de país y direcciones (o rangos)</string>
+ <string name="enter_exit_nodes">Introduzca reglas de identificación de repetidores de salida</string>
+ <string name="exclude_nodes">Excluír nodos</string>
+ <string name="fingerprints_nicks_countries_and_addresses_to_exclude">Reglas de identificación de repetidores de a evitar en la red tor, mediante huellas de validación de claves (fingerprints), alias (nicks), códigos de país y direcciones (o rangos)</string>
+ <string name="enter_exclude_nodes">Introduzca reglas de identificación de s a excluír</string>
<string name="strict_nodes">Hacer estricta la exclusión de nodos (incluso si hay fallos de comunicación)</string>
<string name="use_only_these_specified_nodes">Usar *sólo* estos nodos especificados</string>
<string name="bridges">Bridges (repetidores puente, accesos a Tor de publicitación restringida) </string>
1
0

02 Jan '13
commit ba00ac4fd72ad421794409e87b11c50097040b17
Author: Translation commit bot <translation(a)torproject.org>
Date: Wed Jan 2 00:45:09 2013 +0000
Update translations for orbot
---
values-es/strings.xml | 26 +++++++++++++-------------
1 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/values-es/strings.xml b/values-es/strings.xml
index 7f9c4f9..8975f26 100644
--- a/values-es/strings.xml
+++ b/values-es/strings.xml
@@ -120,7 +120,7 @@
<string name="wizard_transproxy_hint">(Marque esta casilla si no tiene idea de qué estamos hablando)</string>
<string name="wizard_transproxy_none">Ninguno</string>
<string name="pref_transparent_tethering_title">Tor tethering</string>
- <string name="pref_transparent_tethering_summary">Habilita la proxyficación transparente de Tor para dispositivos pasarela (tethered, dispositivos inalabricos que hacen de pasarela de salida a Internet para otros dispositivos conectados a ellos a través de Wifi, USB o Bluetooth) -- (requiere reinicio)</string>
+ <string name="pref_transparent_tethering_summary">Habilita la proxyficación transparente de Tor para dispositivos tethered (dispositivos móviles/celuares pasarela a Internet para otros dispositivos conectados a ellos a través de Wifi, USB o Bluetooth) -- (requiere reinicio)</string>
<string name="button_grant_superuser">Solicitar permisos de superusuario</string>
<string name="pref_select_apps">Seleccionar aplicaciones</string>
<string name="pref_select_apps_summary">Escoja las aplicaciones a redirigir través de Tor</string>
@@ -145,24 +145,24 @@
<string name="setting_up_full_transparent_proxying_">Estableciendo proxyficación transparente completa... </string>
<string name="setting_up_app_based_transparent_proxying_">Estableciendo proxyficación transparente por aplicaciones... </string>
<string name="transparent_proxying_enabled">Proxyficación transparente ACTIVADA</string>
- <string name="transproxy_enabled_for_tethering_">¡TransProxy habilitado para tethering! (proxyficación transparente para su pasarela a Internet móvil)</string>
+ <string name="transproxy_enabled_for_tethering_">¡TransProxy (proxyficación transparente) habilitado para tethering (pasarela a Internet móvil)!</string>
<string name="warning_error_starting_transparent_proxying_">ADVERTENCIA: ¡Error al iniciar la proxyficación transparente!</string>
<string name="transproxy_rules_cleared">Reglas de TransProxy borradas</string>
<string name="couldn_t_start_tor_process_">No se pudo iniciar el proceso de Tor: </string>
- <string name="privoxy_is_running_on_port_">Privoxy se está ejecutando en el puerto: </string>
+ <string name="privoxy_is_running_on_port_">Privoxy (proxy web de filtrado) se está ejecutando en el puerto: </string>
<string name="setting_up_port_based_transparent_proxying_">Estableciendo proxyficación transparente por puertos... </string>
- <string name="bridge_error">Error de bridge (repetidor puente, acceso a Tor de publicitación restringida)</string>
- <string name="bridge_requires_ip">Para utilizar la funcion bridge, debe introducir al menos una dirección IP de bridge.</string>
- <string name="send_email_for_bridges">Envie un correo a bridges(a)torproject.org sólo con el texto \"get bridges\" en el cuerpo del mensaje, desde una cuenta con dominio gmail.com, yahoo.com o yahoo.cn (que soportan DKIM)</string>
+ <string name="bridge_error">Error del bridge</string>
+ <string name="bridge_requires_ip">Para utilizar la funcion bridge (repetidor puente, acceso a Tor de publicitación restringida), debe introducir al menos una dirección IP de bridge.</string>
+ <string name="send_email_for_bridges">Envie un correo a bridges(a)torproject.org incluyendo una línea con \"get bridges\" por si sólo en el cuerpo del mensaje, desde una cuenta con dominio gmail.com, yahoo.com o yahoo.cn (que soportan DKIM)</string>
<string name="error">Error</string>
- <string name="your_reachableaddresses_settings_caused_an_exception_">¡Su configuración ReachableAdresses (direcciones alcanzables) ha producido una excepción!</string>
- <string name="your_relay_settings_caused_an_exception_">¡Su configuración de repetidor de tráfico ha producido una excepción!</string>
+ <string name="your_reachableaddresses_settings_caused_an_exception_">¡Su configuración ReachableAdresses (direcciones accesibles) ha producido una excepción!</string>
+ <string name="your_relay_settings_caused_an_exception_">¡La configuración de su repetidor (el nodo de Tor que ejecuta) ha producido una excepción!</string>
<string name="exit_nodes">Nodos de salida</string>
- <string name="fingerprints_nicks_countries_and_addresses_for_the_last_hop">Reglas de identificación de nodos, fingerprints (huellas de validación de claves), nicks (alias), códigos de país y direcciones, para el último salto (de salida de la red Tor)</string>
- <string name="enter_exit_nodes">Introduzca reglas para nodos de salida</string>
- <string name="exclude_nodes">Excluír nodos (evitarlos en la red Tor)</string>
- <string name="fingerprints_nicks_countries_and_addresses_to_exclude">Reglas de identificación de nodos, fingerprints (huellas de validación de claves), nicks (alias), códigos de país y direcciones a excluír (evitar en la red Tor) excepto si provocan fallos de comunicación. Si se aplican prevalecen sobre la configuración de nodos de entrada.</string>
- <string name="enter_exclude_nodes">Introduzca reglas para nodos a excluír</string>
+ <string name="fingerprints_nicks_countries_and_addresses_for_the_last_hop">Reglas de identificación de repetidores de salida de la red Tor, mediante huellas de validación de claves (fingerprints), alias (nicks), códigos de país y direcciones (o rangos)</string>
+ <string name="enter_exit_nodes">Introduzca reglas de identificación de repetidores de salida</string>
+ <string name="exclude_nodes">Excluír nodos</string>
+ <string name="fingerprints_nicks_countries_and_addresses_to_exclude">Reglas de identificación de repetidores de a evitar en la red tor, mediante huellas de validación de claves (fingerprints), alias (nicks), códigos de país y direcciones (o rangos)</string>
+ <string name="enter_exclude_nodes">Introduzca reglas de identificación de s a excluír</string>
<string name="strict_nodes">Hacer estricta la exclusión de nodos (incluso si hay fallos de comunicación)</string>
<string name="use_only_these_specified_nodes">Usar *sólo* estos nodos especificados</string>
<string name="bridges">Bridges (repetidores puente, accesos a Tor de publicitación restringida) </string>
1
0

[translation/orbot_completed] Update translations for orbot_completed
by translation@torproject.org 02 Jan '13
by translation@torproject.org 02 Jan '13
02 Jan '13
commit e6be6aabab40400989b69371e1a86905989762f3
Author: Translation commit bot <translation(a)torproject.org>
Date: Wed Jan 2 00:15:11 2013 +0000
Update translations for orbot_completed
---
values-es/strings.xml | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/values-es/strings.xml b/values-es/strings.xml
index 375c229..7f9c4f9 100644
--- a/values-es/strings.xml
+++ b/values-es/strings.xml
@@ -137,7 +137,7 @@
<string name="pref_proxy_type_dialog">Introduzca tipo de proxy</string>
<string name="pref_proxy_host_title">Servidor (host) proxy saliente</string>
<string name="pref_proxy_host_summary">Dirección o nombre del servidor (host) proxy saliente.</string>
- <string name="pref_proxy_host_dialog">Introduzca el servidor proxy</string>
+ <string name="pref_proxy_host_dialog">Introduzca el servidor (host) proxy</string>
<string name="pref_proxy_port_title">Puerto del proxy saliente </string>
<string name="pref_proxy_port_summary">Puerto del servidor proxy saliente</string>
<string name="pref_proxy_port_dialog">Introduzca el puerto del proxy</string>
@@ -145,10 +145,10 @@
<string name="setting_up_full_transparent_proxying_">Estableciendo proxyficación transparente completa... </string>
<string name="setting_up_app_based_transparent_proxying_">Estableciendo proxyficación transparente por aplicaciones... </string>
<string name="transparent_proxying_enabled">Proxyficación transparente ACTIVADA</string>
- <string name="transproxy_enabled_for_tethering_">¡TransProxy habilitado para tethering (pasarela a Internet para otros dispositivos)!</string>
+ <string name="transproxy_enabled_for_tethering_">¡TransProxy habilitado para tethering! (proxyficación transparente para su pasarela a Internet móvil)</string>
<string name="warning_error_starting_transparent_proxying_">ADVERTENCIA: ¡Error al iniciar la proxyficación transparente!</string>
<string name="transproxy_rules_cleared">Reglas de TransProxy borradas</string>
- <string name="couldn_t_start_tor_process_">No se pudo iniciar el proceso Tor: </string>
+ <string name="couldn_t_start_tor_process_">No se pudo iniciar el proceso de Tor: </string>
<string name="privoxy_is_running_on_port_">Privoxy se está ejecutando en el puerto: </string>
<string name="setting_up_port_based_transparent_proxying_">Estableciendo proxyficación transparente por puertos... </string>
<string name="bridge_error">Error de bridge (repetidor puente, acceso a Tor de publicitación restringida)</string>
1
0