[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[or-cvs] r21478: {projects} -Update .pot file to reflect latest changes -Enhance black/w (in projects/gettor: . i18n/templates lib/gettor)



Author: kaner
Date: 2010-01-22 23:13:16 +0000 (Fri, 22 Jan 2010)
New Revision: 21478

Modified:
   projects/gettor/GetTor.py
   projects/gettor/TODO
   projects/gettor/i18n/templates/gettor.pot
   projects/gettor/lib/gettor/blacklist.py
   projects/gettor/lib/gettor/constants.py
   projects/gettor/lib/gettor/requests.py
   projects/gettor/lib/gettor/responses.py
   projects/gettor/lib/gettor/utils.py
Log:
-Update .pot file to reflect latest changes
-Enhance black/whitelist features: Blacklist users per mail routine so that 
 they get each mail only *once* (Spam protection)
-Overall cleanups
-Update TODO file


Modified: projects/gettor/GetTor.py
===================================================================
--- projects/gettor/GetTor.py	2010-01-22 22:14:53 UTC (rev 21477)
+++ projects/gettor/GetTor.py	2010-01-22 23:13:16 UTC (rev 21478)
@@ -23,8 +23,9 @@
 
 log = gettor.gtlog.getLogger()
 
-def processFail(conf, rawMessage, sendFr, sendTo, e):
+def processFail(conf, rawMessage, reqval, failedAction, e=None):
     """This routine gets called when something went wrong with the processing"""
+    log.error("Failing to " + failedAction)
     if e is not None:
         log.error("Here is the exception I saw: %s" % sys.exc_info()[0])
         log.error("Detail: %s" %e)
@@ -32,52 +33,48 @@
     log.info("We'll keep a record of this mail.")
     gettor.utils.dumpMessage(conf, rawMessage)
     # Send out notification to user, if possible
-    if sendFr != "" or sendTo != "":
-        if not gettor.responses.sendNotification(conf, sendFr, sendTo):
-            log.error("Also failed to send the user a proper notification. :-/")
-        else:
-            log.info("Failure notification sent to user %s" % sendTo)
+    #if reqval.toField != "" or reqval.sendTo != "":
+    #    if not gettor.responses.sendNotification(conf, reqval.toField, reqval.sendTo):
+    #        log.error("Also failed to send the user a proper notification. :-/")
+    #    else:
+    #        log.info("Failure notification sent to user %s" % reqval.sendTo)
 
+def dumpInfo(reqval):
+    """Dump some info to the logfile"""
+    log.info("Request From: %s To: %s Package: %s Lang: %s Split: %s Signature: %s Cmdaddr: %s" % (reqval.replyTo, reqval.toField, reqval.pack, reqval.lang, reqval.split, reqval.sign, reqval.cmdAddr))
+
 def processMail(conf):
     """All mail processing happens here. Processing goes as follows:
-    - Parse request. This means: Find out everything we need to reply in 
-      an appropriate manner. Reply address, language, package name.
-      Also try to find out if the user wants split packages and if he has 
-      a valid signature on his mail.
-    - Send reply. Use all information gathered from the request and pass
-      it on to the reply class/method to decide what to do."""
+       - Parse request. This means: Find out everything we need to reply in 
+         an appropriate manner. Reply address, language, package name.
+         Also try to find out if the user wants split packages and if he has 
+         a valid signature on his mail.
+       - Send reply. Use all information gathered from the request and pass
+         it on to the reply class/method to decide what to do."""
         
     rawMessage = ""
-    replyTo = ""
-    sendFr = ""
-    replyTo = ""
+    reqval = None
     log.info("Processing mail..")
-    # Retrieve request from stdin
+    # Retrieve request from stdin and parse it
     try:
         request = gettor.requests.requestMail(conf)
         rawMessage = request.getRawMessage()
-        sendFr, 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)
-        log.info("Mail was sent to %s" % sendFr)
+        # reqval contains all important information we need from the request
+        reqval = request.parseMail()
+        dumpInfo(reqval)
     except Exception, e:
-        log.error("Parsing the request failed.")
-        processFail(conf, rawMessage, sendFr, replyTo, e)
+        processFail(conf, rawMessage, reqval, "process request", e)
         return False
 
-    # Ok, information aquired. Initiate reply sequence
+    # Ok, request information aquired. Initiate reply sequence
     try:
-        reply = gettor.responses.Response(conf, sendFr, replyTo, lang, pack, \
-					  split, sig, cmdAddr)
+        reply = gettor.responses.Response(conf, reqval)
         if not reply.sendReply():
-            log.error("Sending reply failed.")
-            processFail(conf, rawMessage, sendFr, replyTo, None)
+            processFail(conf, rawMessage, reqval, "send reply")
             return False
         return True
     except Exception, e:
-        log.error("Sending the reply failed.")
-        processFail(conf, rawMessage, sendFr, replyTo, e)
+        processFail(conf, rawMessage, reqval, "send reply (got exception)", e)
         return False
 
 def processOptions(options, conf):

Modified: projects/gettor/TODO
===================================================================
--- projects/gettor/TODO	2010-01-22 22:14:53 UTC (rev 21477)
+++ projects/gettor/TODO	2010-01-22 23:13:16 UTC (rev 21478)
@@ -7,6 +7,7 @@
   downloads are available for that specific package (maybe send out the non-
   split version of the package?)
 - Clean distdir and packdir on each fetching/packaging run
+- Update https://www.torproject.org/gettor/ 
 - Write instructions on the website on how to use GetTor. Put that site into
   pootle for translation so for example chinese and iranian users have a
   reference for help

Modified: projects/gettor/i18n/templates/gettor.pot
===================================================================
--- projects/gettor/i18n/templates/gettor.pot	2010-01-22 22:14:53 UTC (rev 21477)
+++ projects/gettor/i18n/templates/gettor.pot	2010-01-22 23:13:16 UTC (rev 21478)
@@ -8,7 +8,7 @@
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-01-04 19:12+0100\n"
+"POT-Creation-Date: 2010-01-21 19:10+0100\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@xxxxxx>\n"
@@ -16,7 +16,7 @@
 "Content-Type: text/plain; charset=CHARSET\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: lib/gettor/constants.py:151
+#: lib/gettor/constants.py:388
 msgid ""
 "\n"
 "    Hello, This is the \"GetTor\" robot.\n"
@@ -26,7 +26,7 @@
 "    "
 msgstr ""
 
-#: lib/gettor/constants.py:157
+#: lib/gettor/constants.py:394
 msgid ""
 "\n"
 "    Unfortunately, we won't answer you at this address. You should make\n"
@@ -36,7 +36,7 @@
 "    "
 msgstr ""
 
-#: lib/gettor/constants.py:163
+#: lib/gettor/constants.py:400
 msgid ""
 "\n"
 "    We only process requests from email services that support \"DKIM\",\n"
@@ -46,7 +46,7 @@
 "    "
 msgstr ""
 
-#: lib/gettor/constants.py:169
+#: lib/gettor/constants.py:406
 msgid ""
 "\n"
 "    (We apologize if you didn't ask for this mail. Since your email is from\n"
@@ -56,7 +56,7 @@
 "    "
 msgstr ""
 
-#: lib/gettor/constants.py:175
+#: lib/gettor/constants.py:412
 msgid ""
 "\n"
 "    Please note that currently, we can't process HTML emails or base 64\n"
@@ -65,7 +65,7 @@
 "    "
 msgstr ""
 
-#: lib/gettor/constants.py:181 lib/gettor/constants.py:261
+#: lib/gettor/constants.py:418 lib/gettor/constants.py:498
 msgid ""
 "\n"
 "    If you have any questions or it doesn't work, you can contact a\n"
@@ -74,7 +74,7 @@
 "    "
 msgstr ""
 
-#: lib/gettor/constants.py:186
+#: lib/gettor/constants.py:423
 msgid ""
 "\n"
 "    I will mail you a Tor package, if you tell me which one you want.\n"
@@ -83,7 +83,7 @@
 "    "
 msgstr ""
 
-#: lib/gettor/constants.py:199
+#: lib/gettor/constants.py:436
 msgid ""
 "\n"
 "    Please reply to this mail (to gettor@xxxxxxxxxxxxxx), and tell me\n"
@@ -92,14 +92,14 @@
 "    "
 msgstr ""
 
-#: lib/gettor/constants.py:204
+#: lib/gettor/constants.py:441
 msgid ""
 "\n"
 "    OBTAINING LOCALIZED VERSIONS OF TOR\n"
 "    "
 msgstr ""
 
-#: lib/gettor/constants.py:211
+#: lib/gettor/constants.py:448
 msgid ""
 "\n"
 "    To get a version of Tor translated into your language, specify the\n"
@@ -108,7 +108,7 @@
 "    "
 msgstr ""
 
-#: lib/gettor/constants.py:220
+#: lib/gettor/constants.py:457
 msgid ""
 "\n"
 "    This example will give you the requested package in a localized\n"
@@ -118,14 +118,14 @@
 "    "
 msgstr ""
 
-#: lib/gettor/constants.py:226
+#: lib/gettor/constants.py:463
 msgid ""
 "\n"
 "    List of supported locales:\n"
 "    "
 msgstr ""
 
-#: lib/gettor/constants.py:233
+#: lib/gettor/constants.py:470
 msgid ""
 "\n"
 "    Here is a list of all available languages:\n"
@@ -133,7 +133,7 @@
 "    "
 msgstr ""
 
-#: lib/gettor/constants.py:237
+#: lib/gettor/constants.py:474
 msgid ""
 "\n"
 "    gettor+ar@xxxxxxxxxxxxxx:     Arabic\n"
@@ -151,7 +151,7 @@
 "    "
 msgstr ""
 
-#: lib/gettor/constants.py:251
+#: lib/gettor/constants.py:488
 msgid ""
 "\n"
 "    If you select no language, you will receive the English version.\n"
@@ -159,14 +159,14 @@
 "    "
 msgstr ""
 
-#: lib/gettor/constants.py:255
+#: lib/gettor/constants.py:492
 msgid ""
 "\n"
 "    SUPPORT\n"
 "    "
 msgstr ""
 
-#: lib/gettor/constants.py:266
+#: lib/gettor/constants.py:503
 msgid ""
 "\n"
 "    Here's your requested software as a zip file. Please unzip the\n"
@@ -175,7 +175,7 @@
 "    "
 msgstr ""
 
-#: lib/gettor/constants.py:271
+#: lib/gettor/constants.py:508
 msgid ""
 "\n"
 "    Hint: If your computer has GnuPG installed, use the gpg\n"
@@ -184,7 +184,7 @@
 "    "
 msgstr ""
 
-#: lib/gettor/constants.py:276
+#: lib/gettor/constants.py:513
 msgid ""
 "\n"
 "       gpg --verify <packagename>.asc <packagename>\n"
@@ -192,7 +192,7 @@
 "    "
 msgstr ""
 
-#: lib/gettor/constants.py:280
+#: lib/gettor/constants.py:517
 msgid ""
 "\n"
 "    The output should look somewhat like this:\n"
@@ -200,7 +200,7 @@
 "    "
 msgstr ""
 
-#: lib/gettor/constants.py:288
+#: lib/gettor/constants.py:525
 msgid ""
 "\n"
 "    If you're not familiar with commandline tools, try looking for\n"
@@ -209,7 +209,7 @@
 "    "
 msgstr ""
 
-#: lib/gettor/constants.py:297
+#: lib/gettor/constants.py:534
 msgid ""
 "\n"
 "    If your Internet connection blocks access to the Tor network, you\n"
@@ -222,7 +222,7 @@
 "    "
 msgstr ""
 
-#: lib/gettor/constants.py:306
+#: lib/gettor/constants.py:543
 msgid ""
 "\n"
 "    You can acquire a bridge by sending an email that contains \"get bridges"
@@ -233,7 +233,7 @@
 "    "
 msgstr ""
 
-#: lib/gettor/constants.py:312
+#: lib/gettor/constants.py:549
 msgid ""
 "\n"
 "    It is also possible to fetch bridges with a web browser at the "
@@ -243,7 +243,7 @@
 "    "
 msgstr ""
 
-#: lib/gettor/constants.py:317
+#: lib/gettor/constants.py:554
 msgid ""
 "\n"
 "    IMPORTANT NOTE:\n"
@@ -255,7 +255,7 @@
 "    "
 msgstr ""
 
-#: lib/gettor/constants.py:325
+#: lib/gettor/constants.py:562
 msgid ""
 "\n"
 "    Packages might come out of order! Please make sure you received\n"
@@ -264,7 +264,7 @@
 "    "
 msgstr ""
 
-#: lib/gettor/constants.py:330
+#: lib/gettor/constants.py:567
 msgid ""
 "\n"
 "    Thank you for your request. It was successfully understood. Your request "
@@ -276,7 +276,7 @@
 "    "
 msgstr ""
 
-#: lib/gettor/constants.py:336
+#: lib/gettor/constants.py:573
 msgid ""
 "\n"
 "    If it doesn't arrive, the package might be too big for your mail "
@@ -288,7 +288,7 @@
 "    "
 msgstr ""
 
-#: lib/gettor/constants.py:343
+#: lib/gettor/constants.py:580
 msgid ""
 "\n"
 "    Unfortunately we are currently experiencing problems and we can't "

Modified: projects/gettor/lib/gettor/blacklist.py
===================================================================
--- projects/gettor/lib/gettor/blacklist.py	2010-01-22 22:14:53 UTC (rev 21477)
+++ projects/gettor/lib/gettor/blacklist.py	2010-01-22 23:13:16 UTC (rev 21478)
@@ -7,54 +7,48 @@
 import hashlib
 import os
 import re
+import glob
 import gettor.config
 import gettor.gtlog
+import gettor.utils
 
 log = gettor.gtlog.getLogger()
 
-conf = gettor.config.Config()
-stateDir = conf.getStateDir()
-blStateDir = conf.getBlStateDir()
+class BWList:
+    def __init__(self, blacklistDir):
+        """A blacklist lives as hash files inside a directory."""
+        self.blacklistDir = blacklistDir
+        # "general" is the main blacklist
+        self.createSublist("general")
 
-# XXX
-def createDir(path):
-    try:
-        log.info("Creating directory %s.." % path)
-        os.makedirs(path)
-    except OSError, e:
-        log.error("Failed to create directory %s: %s" % (path, e))
-        return False
-    return True
-
-class BWList:
-    def __init__(self, listdir):
-        self.listDir = listdir
-        if not os.path.isdir(self.listDir):
-            if not createDir(self.listDir):
+    def createSublist(self, blacklistName):
+        """Create a sub blacklist"""
+        fullDir = os.path.join(self.blacklistDir, blacklistName)
+        if not os.path.isdir(fullDir):
+            if not gettor.utils.createDir(fullDir):
                 # XXX Change this to something more appropriate
-                raise IOError("Bad dir: %s" % self.listDir)
+                raise IOError("Bad dir: %s" % fullDir)
 
-    def lookupListEntry(self, address):
+    def lookupListEntry(self, address, blacklistName="*"):
         """Check to see if we have a list entry for the given address."""
         if address is None:
            log.error("Argument 'address' is None")
            return False
-        emailonly = self.stripEmail(address)
-        entry = self.listDir + "/" + str(hashlib.sha1(emailonly).hexdigest())
-        try:
-            entry = os.stat(entry)
-        except OSError:
-            return False
-        return True
+        hashString = self.getHash(address)
+        globPath = os.path.join(self.blacklistDir, blacklistName)
+        hashVec = glob.glob(os.path.join(globPath, hashString))
+        if len(hashVec) > 0:
+            return True
+        return False
 
-    def createListEntry(self, address):
+    def createListEntry(self, address, blacklistName="general"):
         """ Create a black- or whitelist entry """
-        if address is None:
-           log.error("Argument 'address' is None")
+        if address is None or blacklistName is None:
+           log.error("Bad args in createListEntry()")
            return False
-        emailonly = self.stripEmail(address)
-        entry = self.listDir + "/" + str(hashlib.sha1(emailonly).hexdigest())
         if self.lookupListEntry(address) == False:
+            hashString = self.getHash(address)
+            entry = os.path.join(self.blacklistDir, blacklistName, hashString)
             try:
                 fd = open(entry, 'w')
                 fd.close
@@ -66,31 +60,37 @@
             # List entry already exists
             return False
 
-    def removeListEntry(self, address):
+    def removeListEntry(self, address, blacklistName="*"):
         """ Remove an entry from the black- or whitelist """
         if address is None:
            log.error("Argument 'address' is None")
            return False
-        emailonly = self.stripEmail(address)
-        entry = self.listDir + "/" + str(hashlib.sha1(emailonly).hexdigest())
-        if (self.lookupListEntry(address) == True):
+        globPath = os.path.join(self.blacklistDir, blacklistName)
+        hashVec = glob.glob(os.path.join(globPath, hashString))
+        for entry in hashVec:
             try:
+                log.info("Unlinking %s" % entry)
                 os.unlink(entry)
             except OSError:
                 log.error("Could not unlink entry %s" % entry)
-                return False
+                continue
         else:
-            log.info("Requested removal of non-existing entry %s. Abord." 
-                    % entry)
+            log.info("Requested removal of non-existing entry. Abord.")
             return False
 
     def removeAll(self):
         print "Removing all entries from list!"
-        for root, dirs, files in os.walk(self.listDir):
+        for root, dirs, files in os.walk(self.blacklistDir):
             for file in files:
+                rmfile = os.path.join(root, file)
                 try:
-                    rmfile = os.path.join(root, file)
                     os.remove(rmfile)
+                except OSError:
+                    try:
+                        os.rmdir(rmfile)
+                    except:
+                        log.error("Could not remove %s." % rmfile)
+                        return False
                 except:
                     log.error("Could not remove %s." % rmfile)
                     return False
@@ -102,3 +102,8 @@
         if match is not None:
             return match.group()
         return address
+
+    def getHash(self, address):
+        emailonly = self.stripEmail(address)
+        return str(hashlib.sha1(emailonly).hexdigest())
+

Modified: projects/gettor/lib/gettor/constants.py
===================================================================
--- projects/gettor/lib/gettor/constants.py	2010-01-22 22:14:53 UTC (rev 21477)
+++ projects/gettor/lib/gettor/constants.py	2010-01-22 23:13:16 UTC (rev 21478)
@@ -11,7 +11,7 @@
 """
 
 # Giant multi language help message. Add more translations as they become ready
-multilanghelpmsg = """
+multilangpackagehelpmsg = """
     Hello, This is the "GetTor" robot.
 
     I will mail you a Tor package, if you tell me which one you want.

Modified: projects/gettor/lib/gettor/requests.py
===================================================================
--- projects/gettor/lib/gettor/requests.py	2010-01-22 22:14:53 UTC (rev 21477)
+++ projects/gettor/lib/gettor/requests.py	2010-01-22 23:13:16 UTC (rev 21478)
@@ -23,6 +23,16 @@
 
 log = gettor.gtlog.getLogger()
 
+class RequestVal:
+    def __init__(self, toField, replyTo, lang, pack, split, sign, cmdAddr):
+        self.toField = toField
+        self.replyTo = replyTo
+        self.lang = lang
+        self.pack = pack
+        self.split = split
+        self.sign = sign
+        self.cmdAddr = cmdAddr
+    
 class requestMail:
 
     defaultLang = "en"
@@ -47,8 +57,9 @@
         self.rawMessage = sys.stdin.read()
         self.parsedMessage = email.message_from_string(self.rawMessage)
 
-        # WARNING WARNING *** This next line whitelists all ***
+        # WARNING WARNING *** This next line whitelists all addresses ***
         self.signature = True
+
         self.config = config
         self.gotPlusReq = False
         self.returnPackage = None
@@ -93,7 +104,8 @@
         if self.returnPackage is None:
             log.info("User didn't select any packages")
 
-        return (self.toAddress, self.replytoAddress, self.replyLocale, \
+        return RequestVal(self.toAddress, self.replytoAddress, \
+                self.replyLocale, \
                 self.returnPackage, \
                 self.splitDelivery, self.signature, self.commandAddress)
 

Modified: projects/gettor/lib/gettor/responses.py
===================================================================
--- projects/gettor/lib/gettor/responses.py	2010-01-22 22:14:53 UTC (rev 21477)
+++ projects/gettor/lib/gettor/responses.py	2010-01-22 23:13:16 UTC (rev 21478)
@@ -40,22 +40,23 @@
 
 class Response:
 
-    def __init__(self, config, sendFr, replyto, lang, package, split, signature, caddr):
+    def __init__(self, config, reqval):
         self.config = config
-        if sendFr is None:
+        self.reqval = reqval
+        if reqval.toField is None:
             self.srcEmail = "GetTor <gettor@xxxxxxxxxxxxxx>"
         else:
-            self.srcEmail = sendFr
-        self.replyTo = replyto
+            self.srcEmail = reqval.toField
+        self.replyTo = reqval.replyTo
         assert self.replyTo is not None, "Empty reply address."
         # Default lang is en
-        if lang is None:
-            lang = "en"
-        self.mailLang = lang
-        self.package = package
-        self.splitsend = split
-        self.signature = signature
-        self.cmdAddr = caddr
+        if reqval.lang is None:
+            reqval.lang = "en"
+        self.mailLang = reqval.lang
+        self.package = reqval.pack
+        self.splitsend = reqval.split
+        self.signature = reqval.sign
+        self.cmdAddr = reqval.cmdAddr
         # If cmdAddr is set, we are forwarding mail rather than sending a 
         # reply to someone
         if self.cmdAddr is not None:
@@ -64,23 +65,48 @@
             self.sendTo = self.replyTo
 
         try:
-            trans = gettext.translation("gettor", config.getLocaleDir(), [lang])
+            localeDir = config.getLocaleDir()
+            trans = gettext.translation("gettor", localeDir, [reqval.lang])
             trans.install()
             # OMG TEH HACK!!
             import gettor.constants
-
         except IOError:
             log.error("Translation fail. Trying running with -r.")
             raise
+
+        # Init black & whitelists
         self.whiteList = gettor.blacklist.BWList(config.getWlStateDir())
         self.blackList = gettor.blacklist.BWList(config.getBlStateDir())
-        # Check blacklist & Drop if necessary
-        blacklisted = self.blackList.lookupListEntry(self.replyTo)
+        # Check blacklist section 'general' list & Drop if necessary
+        blacklisted = self.blackList.lookupListEntry(self.replyTo, "general")
         assert blacklisted is not True, \
             "Mail from blacklisted user %s" % self.replyTo 
 
     def sendReply(self):
         """All routing decisions take place here."""
+        if self.isAllowed():
+            # Ok, see what we've got here.
+            # Was this a GetTor control command wanting us to forward a package?
+            if self.cmdAddr is not None:
+                if not self.sendPackage():
+                    log.error("Failed to forward mail to '%s'" % self.cmdAddr)
+                return self.sendForwardReply(success)
+                
+            # Did the user choose a package?
+            if self.package is None:
+                return self.sendPackageHelp()
+            delayAlert = self.config.getDelayAlert()
+            # Be a polite bot and send message that mail is on the way
+            if delayAlert:
+                if not self.sendDelayAlert():
+                    log.error("Failed to sent delay alert.")
+            # Did the user request a split or normal package download?
+            if self.splitsend:
+                return self.sendSplitPackage()
+            else:
+                return self.sendPackage()
+
+    def isAllowed(self):
         # Check we're happy with sending this user a package
         # XXX This is currently useless since we set self.signature = True
         if not self.signature and not self.cmdAddr \
@@ -98,27 +124,30 @@
                 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()
-            if delayAlert:
-                ret = self.sendDelayAlert()
-                if ret != True:
-                    log.error("Failed to sent delay alert.")
-            if self.splitsend:
-                return self.sendSplitPackage()
-            else:
-                return self.sendPackage()
+            return True
 
+    def isBlacklisted(self, fname):
+        """This routine takes care that for each function fname, a given user
+           can access it only once"""
+        # First of all, check if user is whitelisted: Whitelist beats Blacklist
+        if self.whiteList.lookupListEntry(self.replyTo, "general"):
+            log.info("Whitelisted user " + self.replyTo)
+            return False
+        # Create a unique dir name for the requested routine
+        blackList = gettor.blacklist.BWList(self.config.getBlStateDir())
+        blackList.createSublist(fname)
+        if blackList.lookupListEntry(self.replyTo, fname):
+            log.info("User " + self.replyTo + " is blacklisted for " + fname)
+            return True
+        else:
+            blackList.createListEntry(self.replyTo, fname)
+            return False
+
     def sendPackage(self):
         """ Send a message with an attachment to the user"""
+        if self.isBlacklisted("sendPackage"):
+            # Don't send anything
+            return False
         log.info("Sending out %s to %s." % (self.package, self.sendTo))
         packages = gettor.packages.Packages(self.config)
         packageList = packages.getPackageList()
@@ -135,7 +164,11 @@
         return status
 
     def sendSplitPackage(self):
-        splitdir = self.config.getPackDir() + "/" + self.package + ".split"
+        if self.isBlacklisted("sendSplitPackage"):
+            # Don't send anything
+            return False
+        splitpack = self.package + ".split"
+        splitdir = os.path.join(self.config.getPackDir(), splitpack)
         try:
             entry = os.stat(splitdir)
         except OSError, e:
@@ -147,7 +180,7 @@
         nFiles = len(files)
         num = 0
         for filename in files:
-            fullPath = splitdir + "/" + filename
+            fullPath = os.path.join(splitdir, filename)
             num = num + 1
             subj = "[GetTor] Split package [%02d / %02d] " % (num, nFiles) 
             message = gettor.constants.splitpackagemsg
@@ -166,10 +199,16 @@
 
     def sendDelayAlert(self):
         """ Send a delay notification """
+        if self.isBlacklisted("sendDelayAlert"):
+            # Don't send anything
+            return False
         log.info("Sending delay alert to %s" % self.sendTo)
         return self.sendGenericMessage(gettor.constants.delayalertmsg)
             
     def sendHelp(self):
+        if self.isBlacklisted("sendHelp"):
+            # Don't send anything
+            return False
         """ Send a helpful message to the user interacting with us """
         log.info("Sending out help message to %s" % self.sendTo)
         return self.sendGenericMessage(gettor.constants.helpmsg)
@@ -183,8 +222,11 @@
 
     def sendPackageHelp(self):
         """ Send a helpful message to the user interacting with us """
+        if self.isBlacklisted("sendPackageHelp"):
+            # Don't send anything
+            return False
         log.info("Sending package help to %s" % self.sendTo)
-        return self.sendGenericMessage(gettor.constants.multilanghelpmsg)
+        return self.sendGenericMessage(gettor.constants.multilangpackagehelpmsg)
 
     def sendForwardReply(self, status):
         " Send a message to the user that issued the forward command """
@@ -219,7 +261,7 @@
         # Add text part
         message.attach(text)
 
-        # Add a file if we have one
+        # Add a file part only if we have one
         if fileName:
             filePart = MIMEBase("application", "zip")
             fp = open(fileName, 'rb')
@@ -266,7 +308,7 @@
             log.error("General SMTP error caught")
             return False
         except Exception, e:
-            log.error("Unknown SMTP error while trying to send through local MTA")
+            log.error("Unknown SMTP error while trying to send via local MTA")
             log.error("Here is the exception I saw: %s" % sys.exc_info()[0])
             log.error("Detail: %s" %e)
 

Modified: projects/gettor/lib/gettor/utils.py
===================================================================
--- projects/gettor/lib/gettor/utils.py	2010-01-22 22:14:53 UTC (rev 21477)
+++ projects/gettor/lib/gettor/utils.py	2010-01-22 23:13:16 UTC (rev 21478)
@@ -161,7 +161,7 @@
     except IOError, e:
         log.error("Whitelist error: %s" % e)
         return False
-    if not whiteList.createListEntry(address):
+    if not whiteList.createListEntry(prepareAddress(address), "general"):
         log.error("Creating whitelist entry failed.")
         return False
     else:
@@ -175,7 +175,7 @@
     except IOError, e:
         log.error("Blacklist error: %s" % e)
         return False
-    if not blackList.createListEntry(address):
+    if not blackList.createListEntry(prepareAddress(address), "general"):
         log.error("Creating blacklist entry failed.")
         return False
     else:
@@ -191,10 +191,10 @@
     except IOError, e:
         log.error("White/Blacklist error: %s" % e)
         return False
-    if whiteList.lookupListEntry(address):
+    if whiteList.lookupListEntry(address, "general"):
         log.info("Address '%s' is present in the whitelist." % address)
         found = True
-    if blackList.lookupListEntry(address):
+    if blackList.lookupListEntry(address, "general"):
         log.info("Address '%s' is present in the blacklist." % address)
         found = True
     if not found:
@@ -329,3 +329,10 @@
         savedTab += line
     return savedTab
 
+def prepareAddress(address):
+    """We need this because we internally store email addresses in this format
+       in the black- and whitelists"""
+    if address.startswith("<"):
+        return address
+    else:
+        return "<" + address + ">"