[or-cvs] r16929: {projects} Major patch from kaner! Lots of changes to the configuration (projects/gettor)
ioerror at seul.org
ioerror at seul.org
Sat Sep 20 20:54:16 UTC 2008
Author: ioerror
Date: 2008-09-20 16:54:16 -0400 (Sat, 20 Sep 2008)
New Revision: 16929
Added:
projects/gettor/gettor_opt.py
Modified:
projects/gettor/gettor.py
projects/gettor/gettor_blacklist.py
projects/gettor/gettor_config.py
projects/gettor/gettor_requests.py
Log:
Major patch from kaner! Lots of changes to the configuration system.
Modified: projects/gettor/gettor.py
===================================================================
--- projects/gettor/gettor.py 2008-09-19 19:22:43 UTC (rev 16928)
+++ projects/gettor/gettor.py 2008-09-20 20:54:16 UTC (rev 16929)
@@ -55,50 +55,35 @@
antigravity = None
import sys
-import getopt
+import os
import gettext
import gettor_blacklist
import gettor_requests
import gettor_responses
-from gettor_log import gettorLogger
-from gettor_config import gettorConf
+import gettor_log
+import gettor_config
+import gettor_opt
-def usage():
- print "Usage: gettor.py [-c CONFIG|-h]"
- print ""
+# Somewhat poor hack to get what we want: Use different languages for logging
+# and for reply mails
+def switchLocale(newlocale):
+ trans = gettext.translation("gettor", "/usr/share/locale", [newlocale])
+ trans.install()
if __name__ == "__main__":
- # Parse args
- try:
- opts, args = getopt.getopt(sys.argv[1:], 'hc:', ['help', 'config='])
- except getopt.GetoptError:
- usage()
- sys.exit(1)
-
- config = None
- for c, optarg in opts:
- if c in ("-h", "--help"):
- usage()
- sys.exit(0)
- if c in ("-c", "--config"):
- config = optarg
-
- if config != None:
- conf = gettorConf(config)
- else:
- conf = gettorConf()
- log = gettorLogger()
- locale = conf.getLocale()
- trans = gettext.translation("gettor", "/usr/share/locale", [locale])
- trans.install()
+ options, arguments = gettor_opt.parseOpts()
+ conf = gettor_config.gettorConf(options.configfile)
+ log = gettor_log.gettorLogger()
+ logLang = conf.getLocale()
+ switchLocale(logLang)
rawMessage = gettor_requests.getMessage()
parsedMessage = gettor_requests.parseMessage(rawMessage)
if not parsedMessage:
log.log(_("No parsed message. Dropping message."))
- exit(0)
+ exit(1)
signature = False
signature = gettor_requests.verifySignature(rawMessage)
@@ -114,6 +99,10 @@
# vidalia-bundle-0.2.0.29-rc-0.1.6.exe.asc
#
distDir = conf.getDistDir()
+ if not os.path.isdir(distDir):
+ log.log(_("Sorry, %s is not a directory.") % distDir)
+ exit(1)
+
packageList = {
"windows-bundle": distDir + "windows-bundle.z",
"macosx-panther-ppc-bundle": distDir + "macosx-panther-ppc-bundle.z",
@@ -121,24 +110,40 @@
"source-bundle": distDir + "source-bundle.z"
}
+ # Check package list sanity
+ for key, val in packageList.items():
+ # Remove invalid packages
+ if not os.access(val, os.R_OK):
+ log.log(_("Warning: %s not accessable. Removing from list." % val))
+ del packageList[key]
+ if len(packageList) < 1:
+ log.log(_("Sorry, your package list is unusable."))
+ exit(1)
+
# XXX TODO: Ensure we have a proper replyTO or bail out (majorly malformed mail).
replyTo = gettor_requests.parseReply(parsedMessage)
-
+
+ # Get disired reply language, if any
+ replyLang = gettor_requests.parseLocale(parsedMessage)
+ if not replyLang:
+ replyLang = logLang
+
if not signature:
# Check to see if we've helped them to understand that they need DKIM in the past
previouslyHelped = gettor_blacklist.blackList(replyTo)
if not replyTo:
log.log(_("No help dispatched. Invalid reply address for user."))
- exit(0)
+ exit(1)
if not signature and previouslyHelped:
log.log(_("Unsigned messaged to gettor by blacklisted user dropped."))
- exit(0)
+ exit(1)
if not signature and not previouslyHelped:
# Reply with some help and bail out
gettor_blacklist.blackList(replyTo, True)
+ switchLocale(replyLang)
message = _("""
Hello! This is the "get tor" robot.
@@ -154,6 +159,7 @@
a service that doesn't use DKIM, we're sending a short explanation,
and then we'll ignore this email address for the next day or so.
""")
+ switchLocale(logLang)
gettor_responses.sendHelp(message, srcEmail, replyTo)
log.log(_("Unsigned messaged to gettor. We issued some help about using DKIM."))
exit(0)
@@ -175,12 +181,14 @@
gettor_responses.sendPackage(message, srcEmail, replyTo, packageList[package])
exit(0)
else:
+ switchLocale(replyLang)
message = [_("Hello, I'm a robot. ")]
message.append(_("Your request was not understood. Please select one of the following package names:\n"))
for key in packageList.keys():
message.append(key + "\n")
message.append(_("Please send me another email. It only needs a single package name anywhere in the body of your email.\n"))
+ switchLocale(logLang)
gettor_responses.sendHelp(''.join(message), srcEmail, replyTo)
log.log(_("Signed messaged to gettor. We issued some help about proper email formatting."))
exit(0)
Modified: projects/gettor/gettor_blacklist.py
===================================================================
--- projects/gettor/gettor_blacklist.py 2008-09-19 19:22:43 UTC (rev 16928)
+++ projects/gettor/gettor_blacklist.py 2008-09-20 20:54:16 UTC (rev 16929)
@@ -5,9 +5,9 @@
import hashlib
import os
-from gettor_config import gettorConf
+import gettor_config
-conf = gettorConf()
+conf = gettor_config.gettorConf()
stateDir = conf.getStateDir()
blStateDir = conf.getBlStateDir()
Modified: projects/gettor/gettor_config.py
===================================================================
--- projects/gettor/gettor_config.py 2008-09-19 19:22:43 UTC (rev 16928)
+++ projects/gettor/gettor_config.py 2008-09-20 20:54:16 UTC (rev 16929)
@@ -1,8 +1,56 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
'''
-This grabs configurable values from the users' gettor config file
-if that file is not present, it will supply reasonable defaults.
+ gettor_config.py - Parse configuration file for gettor
+
+ Copyright (c) 2008, Jacob Appelbaum <jacob at appelbaum.net>,
+ Christian Fromme <kaner at strace.org>
+
+ This is Free Software. See LICENSE for license information.
+
+
+ We grab configurable values from the users' gettor config file. If that file
+ is not present, we will supply reasonable defaults. Config files are ini-style
+ formatted. We know this is ugly, but we prefer it to XML and also ConfigParser
+ seems handy. ;-)
+
+ A valid config file should look like this:
+
+ [global]
+ stateDir = /var/lib/gettor/
+ blStateDir = /var/lib/gettor/bl/
+ distDir = /var/lib/gettor/pkg/
+ srcEmail = gettor at foo.org
+ locale = en
+ logSubSystem = nothing
+ logFile = /dev/null
+
+ Note that you can set from none to any of these values in your config file.
+ Values you dont provide will be taken from the defaults in 'useConf'.
+
+ Here is what each of them is used for individually:
+
+ blStateDir: Blacklisted (hashed) email addresses go here
+ distDir: Sent-out Tor packages are found here
+ srcEmail: The email containing the Tor package will use this as 'From:'
+ locale: Choose your default mail and log locale
+ logFile: If 'file' logging is chosen, log to this file
+ logSubSystem: This has to be one of the following strings:
+ 'nothing': Nothing is logged anywhere (Recommended)
+ 'syslog': Logmessages will be written to syslog
+ 'file': Logmessages will be written to a file (Not that
+ this needs the 'logFile' option in the config file
+ also set to something useful
+
+ If no valid config file is provided to __init__, gettorConf will try to use
+ '~/.gettorrc' as default config file. If that fails, the default values from
+ useConf will be used.
+
+ Run this module from the commandline to have it print a useful default config
+ like so:
+
+ $ ./gettor_config.py > ~/.gettorrc
+
'''
import os
@@ -11,26 +59,37 @@
class gettorConf:
'''
- Initialize gettor with default values if one or more
- values are missing from the config file.
- This will return entirely default values if the configuration file is
- missing. Our default file location is ~/.gettorrc for the current user.
+ Initialize gettor with default values if one or more values are missing
+ from the config file. This will return entirely default values if the
+ configuration file is missing. Our default file location is ~/.gettorrc
+ of $USER.
'''
- stateDir = "/var/lib/gettor/"
- blStateDir = stateDir + "bl/"
- srcEmail = "gettor at torproject.org"
- distDir = "/var/lib/gettor/pkg/"
- locale = "en"
- logSubSystem = "nothing"
- logFile = "/dev/null"
- configFile = "~/.gettorrc"
- config = ConfigParser.ConfigParser()
+ def __init__(self, path = os.path.expanduser("~/.gettorrc")):
+ '''
+ Most of the work happens here. Parse config, merge with default values,
+ prepare outConf.
+ '''
- def __init__(self, path = os.path.expanduser(configFile)):
-
self.configFile = os.path.expanduser(path)
+ # Variable name | Default value | Section
+ self.useConf = {"stateDir": ("/var/lib/gettor/", "global"),
+ "blStateDir": ("/var/lib/gettor/bl/", "global"),
+ "srcEmail": ("gettor at torproject.org", "global"),
+ "distDir": ("/var/lib/gettor/pkg/", "global"),
+ "locale": ("en", "global"),
+ "logSubSystem": ("nothing", "global"),
+ "logFile": ("/dev/null", "global")}
+
+ # One ConfigParser instance to read the actual values from config
+ self.config = ConfigParser.ConfigParser()
+ # And another to provide a useable default config as output. This is
+ # only because the user may have strange stuff inside his config file.
+ # We're trying to be failsafe here
+ self.outConf = ConfigParser.ConfigParser()
+
+ # See if config file is accessable
try:
if os.access(self.configFile, os.R_OK):
readableConfigFile = True
@@ -46,69 +105,59 @@
# If they make a mistake for now we'll ignore *everything* :-)
self.config.read(self.configFile)
except:
- self.config.add_section("global")
- else:
- self.config.add_section("global")
+ pass
- if self.config.has_option("global", "stateDir"):
- self.stateDir = self.config.get("global", "stateDir")
- else:
- self.config.set("global", "stateDir", self.stateDir)
+ # Main parser loop:
+ # * Merge default values with those from the config file, if there are
+ # any
+ # * Update values from config file into useConf
+ # * Ignore sections and values that are not found in useConf, but in
+ # the config file (wtf?)
+ # * Prepare outConf
+ for dkey, (dval, sec) in self.useConf.items():
+ if not self.outConf.has_section(sec):
+ self.outConf.add_section(sec)
+ try:
+ for key, val in self.config.items(sec):
+ # Unfortunatly, keys from the config are not case-sensitive
+ if key.lower() == dkey.lower():
+ self.useConf[dkey] = val, sec
+ self.outConf.set(sec, dkey, val)
+ break
+ else:
+ # Add default value for dkey
+ self.outConf.set(sec, dkey, dval)
+
+ except:
+ self.outConf.set(sec, dkey, dval)
- if self.config.has_option("global", "blStateDir"):
- self.blStateDir = self.config.get("global", "blStateDir")
- else:
- self.config.set("global", "blStateDir", self.blStateDir)
-
- if self.config.has_option("global", "srcEmail"):
- self.srcEmail = self.config.get("global", "srcEmail")
- else:
- self.config.set("global", "srcEmail", self.srcEmail)
-
- if self.config.has_option("global", "distDir"):
- self.distDir = self.config.get("global", "distDir")
- else:
- self.config.set("global", "distDir", self.distDir)
-
- if self.config.has_option("global", "locale"):
- self.locale = self.config.get("global", "locale")
- else:
- self.config.set("global", "locale", self.locale)
-
- if self.config.has_option("global", "logSubSystem"):
- self.logSubSystem = self.config.get("global", "logSubSystem")
- else:
- self.config.set("global", "logSubSystem", self.logSubSystem)
-
- if self.config.has_option("global", "logFile"):
- self.logFile = self.config.get("global", "logFile")
- else:
- self.config.set("global", "logFile", self.logFile)
-
def printConfiguration(self):
- return self.config.write(sys.stdout)
+ '''
+ Print out config file. This works even if there is none
+ '''
+ return self.outConf.write(sys.stdout)
# All getter routines live below
def getStateDir(self):
- return self.stateDir
+ return self.useConf["stateDir"][0]
def getBlStateDir(self):
- return self.blStateDir
+ return self.useConf["blStateDir"][0]
def getSrcEmail(self):
- return self.srcEmail
+ return self.useConf["srcEmail"][0]
def getDistDir(self):
- return self.distDir
+ return self.useConf["distDir"][0]
def getLocale(self):
- return self.locale
+ return self.useConf["locale"][0]
def getLogSubSystem(self):
- return self.logSubSystem
+ return self.useConf["logSubSystem"][0]
def getLogFile(self):
- return self.logFile
+ return self.useConf["logFile"][0]
if __name__ == "__main__" :
c = gettorConf()
Added: projects/gettor/gettor_opt.py
===================================================================
--- projects/gettor/gettor_opt.py (rev 0)
+++ projects/gettor/gettor_opt.py 2008-09-20 20:54:16 UTC (rev 16929)
@@ -0,0 +1,23 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+'''
+ gettor_config.py: Command line parser for gettor
+
+ Copyright (c) 2008, Jacob Appelbaum <jacob at appelbaum.net>,
+ Christian Fromme <kaner at strace.org>
+
+ This is Free Software. See LICENSE for license information.
+
+
+ This is the option parser module for gettor.
+'''
+
+import optparse
+
+def parseOpts():
+ cmdParser = optparse.OptionParser()
+ cmdParser.add_option("-c", "--config", dest="configfile",
+ default="~/.gettorrc",
+ help="set config file to FILE", metavar="FILE")
+
+ return cmdParser.parse_args()
Modified: projects/gettor/gettor_requests.py
===================================================================
--- projects/gettor/gettor_requests.py 2008-09-19 19:22:43 UTC (rev 16928)
+++ projects/gettor/gettor_requests.py 2008-09-20 20:54:16 UTC (rev 16929)
@@ -53,6 +53,16 @@
# If we get here, we didn't find a package we're currently serving
return None
+def parseLocale(parsedMessage):
+ """Check if the user wants a reply in a certain language"""
+ pattern = re.compile("^Lang:\s+(.*)$")
+ for line in email.Iterators.body_line_iterator(parsedMessage):
+ match = pattern.match(line)
+ if match:
+ return match.group(1)
+ else:
+ return None
+
if __name__ == "__main__" :
""" Give us an email to understand what we think of it. """
packageList = {
More information about the tor-commits
mailing list