[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[or-cvs] r20803: {projects} Towards mail forwarding feature (in projects/gettor: . gettor)
Author: kaner
Date: 2009-10-18 10:02:16 -0400 (Sun, 18 Oct 2009)
New Revision: 20803
Modified:
projects/gettor/GetTor.py
projects/gettor/gettor/config.py
projects/gettor/gettor/constants.py
projects/gettor/gettor/opt.py
projects/gettor/gettor/requests.py
projects/gettor/gettor/responses.py
projects/gettor/gettor/utils.py
Log:
Towards mail forwarding feature
Modified: projects/gettor/GetTor.py
===================================================================
--- projects/gettor/GetTor.py 2009-10-18 12:18:44 UTC (rev 20802)
+++ projects/gettor/GetTor.py 2009-10-18 14:02:16 UTC (rev 20803)
@@ -36,9 +36,9 @@
# Retrieve request from stdin
try:
request = gettor.requests.requestMail(conf)
- replyTo, lang, pack, split, sig = request.parseMail()
- log.info("Request from %s package %s, lang %s, split %s" \
- % (replyTo, pack, lang, split))
+ replyTo, lang, pack, split, sig, cmdAddr = request.parseMail()
+ log.info("Request from %s package %s, lang %s, split %s, cmdaddr %s" \
+ % (replyTo, pack, lang, split, cmdAddr))
log.info("Signature is %s" % sig)
except Exception, e:
log.error("Parsing the request failed.")
@@ -48,13 +48,15 @@
# Ok, information aquired. Initiate reply sequence
try:
- reply = gettor.responses.Response(conf, replyTo, lang, pack, split, sig)
+ reply = gettor.responses.Response(conf, replyTo, lang, pack, split, \
+ sig, cmdAddr)
reply.sendReply()
return True
except Exception, e:
log.error("Sending the reply failed.")
log.error("Here is the exception I saw: %s" % sys.exc_info()[0])
log.error("Detail: %s" %e)
+ raise
return False
def processOptions(options, conf):
@@ -80,6 +82,10 @@
gettor.utils.clearWhitelist(conf)
if options.clearbl:
gettor.utils.clearBlacklist(conf)
+ if options.cmdpass:
+ gettor.utils.setCmdPassword(conf, options.cmdpass)
+ test = "haha"
+ gettor.utils.verifyPassword(conf, test)
def main():
# Parse command line, setup config and logging
Modified: projects/gettor/gettor/config.py
===================================================================
--- projects/gettor/gettor/config.py 2009-10-18 12:18:44 UTC (rev 20802)
+++ projects/gettor/gettor/config.py 2009-10-18 14:02:16 UTC (rev 20803)
@@ -95,6 +95,7 @@
"logSubSystem": ("nothing", "global"),
"logFile": ("/dev/null", "global"),
"localeDir": ("/usr/share/locale", "global"),
+ "cmdPassFile": ("/var/lib/gettor/cmdpass", "global"),
"delayAlert": (True, "global")}
# One ConfigParser instance to read the actual values from config
@@ -171,6 +172,9 @@
def getLocaleDir(self):
return self.useConf["localeDir"][0]
+ def getCmdPassFile(self):
+ return self.useConf["cmdPassFile"][0]
+
def getDelayAlert(self):
return self.useConf["delayAlert"][0]
Modified: projects/gettor/gettor/constants.py
===================================================================
--- projects/gettor/gettor/constants.py 2009-10-18 12:18:44 UTC (rev 20802)
+++ projects/gettor/gettor/constants.py 2009-10-18 14:02:16 UTC (rev 20803)
@@ -15,7 +15,7 @@
_ = gettext.gettext
helpmsg = _("""
- Hello! This is the "gettor" robot.
+ Hello! This is the "GetTor" robot.
Unfortunately, we won't answer you at this address. You should make
an account with GMAIL.COM or YAHOO.CN and send the mail from
@@ -37,7 +37,7 @@
""")
packagehelpmsg = _("""
- Hello, This is the "gettor" robot.
+ Hello, This is the "GetTor" robot.
I will mail you a Tor package, if you tell me which one you want.
Please select one of the following package names:
@@ -60,7 +60,7 @@
""")
packagemsg = _("""
- Hello! This is the "gettor" robot.
+ Hello! This is the "GetTor" robot.
Here's your requested software as a zip file. Please unzip the
package and verify the signature.
@@ -99,7 +99,7 @@
""")
splitpackagemsg = _("""
- Hello! This is the "gettor" robot.
+ Hello! This is the "GetTor" robot.
Here's your requested software as a zip file. Please unzip the
package and verify the signature.
@@ -147,7 +147,7 @@
""")
delayalertmsg = _("""
- Hello, This is the "gettor" robot.
+ Hello, This is the "GetTor" robot.
Thank you for your request. It was successfully understood. Your request is
currently being processed. Your package should arrive within the next ten
Modified: projects/gettor/gettor/opt.py
===================================================================
--- projects/gettor/gettor/opt.py 2009-10-18 12:18:44 UTC (rev 20802)
+++ projects/gettor/gettor/opt.py 2009-10-18 14:02:16 UTC (rev 20803)
@@ -58,6 +58,10 @@
cmdParser.add_option("-r", "--install-translations", dest="insttrans",
action="store_true", default=False,
help="Compile and install translation files [check -d]")
+ cmdParser.add_option("-s", "--set-cmdpassword", dest="cmdpass",
+ default="",
+ help="Set the password for mail commands",
+ metavar="CMDPASS")
cmdParser.add_option("-d", "--i18n-dir", dest="i18ndir",
default="./i18n",
help="Set your locale src dir to DIR [default = %default]",
Modified: projects/gettor/gettor/requests.py
===================================================================
--- projects/gettor/gettor/requests.py 2009-10-18 12:18:44 UTC (rev 20802)
+++ projects/gettor/gettor/requests.py 2009-10-18 14:02:16 UTC (rev 20803)
@@ -36,6 +36,7 @@
self.rawMessage = sys.stdin.read()
self.parsedMessage = email.message_from_string(self.rawMessage)
self.signature = False
+ self.config = config
# TODO XXX:
# This should catch DNS exceptions and fail to verify if we have a
# dns timeout
@@ -53,9 +54,11 @@
# If no package name could be recognized, use 'None'
self.returnPackage = None
self.splitDelivery = False
+ self.commandaddress = None
self.replyLocale = "en"
packager = gettor.packages.Packages(config)
self.packages = packager.getPackageList()
+ assert len(self.packages) > 0, "Empty package list"
def parseMail(self):
# Parse line by line
@@ -71,6 +74,7 @@
if match:
self.returnPackage = package
log.info("User requested package %s" % self.returnPackage)
+ break
# If we find 'split' somewhere in the mail, we assume that the user
# wants a split delivery
match = re.match(".*split.*", line)
@@ -82,7 +86,25 @@
if match:
self.replyLocale = match.group(1)
log.info("User requested locale %s" % self.replyLocale)
+ # Check if this is a command
+ match = re.match(".*[Cc]ommand:\s+(.*)$", line)
+ if match:
+ log.info("Command received from %s" % self.replytoAddress)
+ cmd = match.group(1).split()
+ length = len(cmd)
+ assert length == 3, "Wrong command syntax"
+ auth = cmd[0]
+ # Package is parsed by the usual package parsing mechanism
+ package = cmd[1]
+ address = cmd[2]
+ verified = gettor.utils.verifyPassword(self.config, auth)
+ assert verified == True, \
+ "Unauthorized attempt to command from: %s" \
+ % self.replytoAddress
+ self.commandaddress = address
+ if self.returnPackage is None:
+ log.info("User didn't select any packages")
# Actually use a map here later XXX
for (key, lang) in self.supportedLangs.items():
if self.replyLocale == key:
@@ -92,8 +114,8 @@
% (self.replyLocale, self.defaultLang))
self.replyLocale = self.defaultLang
- return (self.replytoAddress, self.replyLocale, \
- self.returnPackage, self.splitDelivery, self.signature)
+ return (self.replytoAddress, self.replyLocale, self.returnPackage, \
+ self.splitDelivery, self.signature, self.commandaddress)
def getRawMessage(self):
return self.rawMessage
Modified: projects/gettor/gettor/responses.py
===================================================================
--- projects/gettor/gettor/responses.py 2009-10-18 12:18:44 UTC (rev 20802)
+++ projects/gettor/gettor/responses.py 2009-10-18 14:02:16 UTC (rev 20803)
@@ -29,18 +29,22 @@
class Response:
- def __init__(self, config, replyto, lang, package, split, signature):
+ def __init__(self, config, replyto, lang, package, split, signature, caddr):
self.config = config
self.srcEmail = "GetTor <gettor@xxxxxxxxxxxxxx>"
self.replyTo = replyto
- if self.replyTo is None:
- log.error("Empty replyto address.")
- # XXX Raise something self-defined
- raise Exception("Empty reply to address")
+ assert self.replyTo is not None, "Empty replyto address."
self.mailLang = lang
self.package = package
self.splitsend = split
self.signature = signature
+ self.cmdAddr = caddr
+ # If cmdAddr is set, we are forwarding mail rather than sending a
+ # reply to someone
+ if self.cmdAddr is not None:
+ self.sendTo = self.cmdAddr
+ else:
+ self.sendTo = self.replyTo
self.whiteList = gettor.blacklist.BWList(config.getWlStateDir())
self.blackList = gettor.blacklist.BWList(config.getBlStateDir())
try:
@@ -53,7 +57,7 @@
def sendReply(self):
"""All routing decisions take place here."""
# Check we're happy with sending this user a package
- if not self.signature \
+ if not self.signature and not self.cmdAddr \
and not self.whiteList.lookupListEntry(self.replyTo) \
and not re.compile(".*@yahoo.com.cn").match(self.replyTo) \
and not re.compile(".*@yahoo.cn").match(self.replyTo) \
@@ -68,6 +72,12 @@
log.info("Unsigned messaged to gettor. We will issue help.")
return self.sendHelp()
else:
+ if self.cmdAddr is not None:
+ success = self.sendPackage()
+ if not success:
+ log.error("Failed to forward mail to '%s'" % self.cmdAddr)
+ return self.sendForwardReply(success)
+
if self.package is None:
return self.sendPackageHelp()
delayAlert = self.config.getDelayAlert()
@@ -82,7 +92,7 @@
def sendPackage(self):
""" Send a message with an attachment to the user"""
- log.info("Sending out %s to %s." % (self.package, self.replyTo))
+ log.info("Sending out %s to %s." % (self.package, self.sendTo))
packages = gettor.packages.Packages(self.config)
packageList = packages.getPackageList()
filename = packageList[self.package]
@@ -128,12 +138,12 @@
def sendDelayAlert(self):
""" Send a delay notification """
- log.info("Sending delay alert to %s" % self.replyTo)
+ log.info("Sending delay alert to %s" % self.sendTo)
return self.sendGenericMessage(gettor.constants.delayalertmsg)
def sendHelp(self):
""" Send a helpful message to the user interacting with us """
- log.info("Sending out help message to %s" % self.replyTo)
+ log.info("Sending out help message to %s" % self.sendTo)
return self.sendGenericMessage(gettor.constants.helpmsg)
## XXX the following line was used below to automatically list the names
@@ -145,16 +155,24 @@
def sendPackageHelp(self):
""" Send a helpful message to the user interacting with us """
- log.info("Sending package help to %s" % self.replyTo)
+ log.info("Sending package help to %s" % self.sendTo)
return self.sendGenericMessage(gettor.constants.packagehelpmsg)
+ def sendForwardReply(self, status):
+ " Send a message to the user that issued the forward command """
+ log.info("Sending reply to forwarder '%s'" % self.replyTo)
+ message = "Forwarding mail to '%s' status: %s" % (self.sendTo, status)
+ # Magic: We're now returning to the original issuer
+ self.sendTo = self.replyTo
+ return self.sendGenericMessage(message)
+
def sendGenericMessage(self, text):
""" Send a message of some sort """
message = self.constructMessage(text, "")
try:
status = self.sendMessage(message)
except:
- log.error("Could not send message to user %s" % self.replyTo)
+ log.error("Could not send message to user %s" % self.sendTo)
status = False
log.info("Send status: %s" % status)
@@ -170,7 +188,7 @@
mime = MimeWriter.MimeWriter(message)
mime.addheader('MIME-Version', '1.0')
mime.addheader('Subject', subj)
- mime.addheader('To', self.replyTo)
+ mime.addheader('To', self.sendTo)
mime.addheader('From', self.srcEmail)
mime.startmultipartbody('mixed')
@@ -192,7 +210,7 @@
def sendMessage(self, message, smtpserver="localhost:25"):
try:
smtp = smtplib.SMTP(smtpserver)
- smtp.sendmail(self.srcEmail, self.replyTo, message.getvalue())
+ smtp.sendmail(self.srcEmail, self.sendTo, message.getvalue())
smtp.quit()
status = True
except smtplib.SMTPAuthenticationError:
Modified: projects/gettor/gettor/utils.py
===================================================================
--- projects/gettor/gettor/utils.py 2009-10-18 12:18:44 UTC (rev 20802)
+++ projects/gettor/gettor/utils.py 2009-10-18 14:02:16 UTC (rev 20803)
@@ -13,6 +13,7 @@
import os
import subprocess
+import hashlib
import gettor.gtlog
import gettor.blacklist
@@ -205,6 +206,36 @@
log.info("Deleting blacklist done.")
return True
+def setCmdPassword(conf, password):
+ log.info("Setting command password")
+ passwordHash = str(hashlib.sha1(password).hexdigest())
+ cmdPassFile = conf.getCmdPassFile()
+ try:
+ fd = open(cmdPassFile, 'w')
+ fd.write(passwordHash)
+ fd.close
+ return True
+ except Exception, e:
+ log.error("Creating list entry %s failed: %s" % (entry, e))
+ return False
+
+def verifyPassword(conf, password):
+ candidateHash = str(hashlib.sha1(password).hexdigest())
+ cmdPassFile = conf.getCmdPassFile()
+ try:
+ fd = open(cmdPassFile, 'r')
+ passwordHash = fd.read()
+ fd.close
+ if candidateHash == passwordHash:
+ log.info("Verification succeeded")
+ return True
+ else:
+ log.info("Verification failed")
+ return False
+ except Exception, e:
+ log.error("Verifying password failed: %s" % e)
+ return False
+
# Helper routines go here ####################################################
def installMo(poFile, targetDir):