CVS: tmda/TMDA Util.py,1.100,1.101 FilterParser.py,1.58,1.59 Defaults.py,1.183,1.184 ChangeLog,1.280,1.281

Timothy Legant <[email protected]>
Newsgroups gmane.mail.spam.tmda.cvs
Message-ID <[email protected]>
Update of /cvsroot/tmda/tmda/TMDA
In directory sc8-pr-cvs1:/tmp/cvs-serv4926/TMDA

Modified Files:
	Util.py FilterParser.py Defaults.py ChangeLog 
Log Message:
Defaults.py: New variables DB_BARE_APPEND and DB_CONFIRM_APPEND.

FilterParser.py: Removed {from,to}-mysql code.  Moved
__create_sql_params method to module-level function create_sql_params.
Removed -domains argument and always add the domains into the keys.
Made the domains list contain only unique domains.

Util.py: New function 'db_insert' used by the DB_BARE_APPEND and
DB_CONFIRM_APPEND code.

tmda-inject: Added code to insert recipient into database using the
SQL code in DB_BARE_APPEND if both DB_BARE_APPEND and DB_CONNECTION
are set.  Mimics BARE_APPEND functionality.

tmda-rfilter: Added code to insert sender into database using the SQL
code in DB_CONFIRM_APPEND if both DB_CONFIRM_APPEND and DB_CONNECTION
are set.  Mimics CONFIRM_APPEND functionality. Made 'sender_list' in
main() contain only unique senders.

filter-sources.ht: Removed {from,to}-mysql documentation, moved
-domains documentation to top, since now it is default behavior.



Index: Util.py
===================================================================
RCS file: /cvsroot/tmda/tmda/TMDA/Util.py,v
retrieving revision 1.100
retrieving revision 1.101
diff -u -r1.100 -r1.101
--- Util.py	9 Jul 2003 18:23:01 -0000	1.100
+++ Util.py	11 Jul 2003 23:02:59 -0000	1.101
@@ -737,6 +737,21 @@
     return object
 
 
+def db_insert(db, insert_sql, params):
+    """Insert (using the 'insert_sql' SQL) an address into a SQL DB."""
+    dbmodule = sys.modules[db.__module__]
+    DatabaseError = getattr(dbmodule, 'DatabaseError')
+    cursor = db.cursor()
+    try:
+        try:
+            cursor.execute(insert_sql, params)
+            db.commit()
+        except DatabaseError:
+            pass
+    finally:
+        cursor.close()
+
+
 def findmatch(list, addrs):
     """Determine whether any of the passed e-mail addresses match a
     Unix shell-style wildcard pattern contained in list.  The

Index: FilterParser.py
===================================================================
RCS file: /cvsroot/tmda/tmda/TMDA/FilterParser.py,v
retrieving revision 1.58
retrieving revision 1.59
diff -u -r1.58 -r1.59
--- FilterParser.py	1 Jul 2003 06:29:51 -0000	1.58
+++ FilterParser.py	11 Jul 2003 23:02:59 -0000	1.59
@@ -262,22 +262,18 @@
     arguments = {
         'from'         : None,
         'to'           : None,
-        'from-file'    : ('autocdb', 'autodbm', 'domains', 'optional'),
-        'to-file'      : ('autocdb', 'autodbm', 'domains', 'optional'),
-        'from-cdb'     : ('domains', 'optional',),
-        'to-cdb'       : ('domains', 'optional',),
-        'from-dbm'     : ('domains', 'optional',),
-        'to-dbm'       : ('domains', 'optional',),
+        'from-file'    : ('autocdb', 'autodbm', 'optional'),
+        'to-file'      : ('autocdb', 'autodbm', 'optional'),
+        'from-cdb'     : ('optional',),
+        'to-cdb'       : ('optional',),
+        'from-dbm'     : ('optional',),
+        'to-dbm'       : ('optional',),
         'from-ezmlm'   : ('optional',),
         'to-ezmlm'     : ('optional',),
         'from-mailman' : ('attr', 'optional' ),
         'to-mailman'   : ('attr', 'optional' ),
-        'from-mysql'   : ('like', 'rlike'),
-        'to-mysql'     : ('like', 'rlike'),
-        'from-sql'     : ('action_column', 'addr_column',
-                          'domains', 'wildcards'),
-        'to-sql'       : ('action_column', 'addr_column',
-                          'domains', 'wildcards'),
+        'from-sql'     : ('action_column', 'addr_column', 'wildcards'),
+        'to-sql'       : ('action_column', 'addr_column', 'wildcards'),
         'body'         : ('case',),
         'headers'      : ('case',),
         'body-file'    : ('case', 'optional'),
@@ -724,44 +720,6 @@
                                   source)
 
 
-    def __search_mysql(self, Table, Args, Keys, Actions, Source):
-        "Search MySQL table."
-        if not self.MySQL:
-            # Connect to the database if we have not yet connected
-            import _mysql
-            self.MySQL = _mysql.connect \
-            (
-                host = Defaults.MYSQL_HOST,
-                db = Defaults.MYSQL_DATABASE,
-                user = Defaults.MYSQL_USER,
-                passwd = Defaults.MYSQL_PASSWORD
-            )
-        # Searches can be for records that are "=", "like", or "rlike" the
-        # keys.  "=" is the fastest and the default, but it does not allow any
-        # wildcarding.  "like" allows "_" to mean any character and "%" to
-        # mean any string.  "rlike" allows regular expressions.
-        Compare = "="
-        if Args.has_key('like'): Compare = "LIKE"
-        elif Args.has_key('rlike'): Compare = "RLIKE"
-        Test = ""
-        for Key in Keys:
-            if Test: Test += "OR "
-            Test += "('%s' %s ADDRESS) " % (Key.replace("'", "\\'"), Compare)
-        # Perform the query
-        self.MySQL.query("SELECT * FROM %s WHERE %s LIMIT 1" % (Table, Test))
-        # Fetch the result
-        Result = self.MySQL.store_result().fetch_row(0, 1)
-        found_match = len(Result)
-
-        # If there is an entry for this key, we consider it an overriding
-        # action specification.
-        if found_match and Result[0]["ACTION"]:
-            Actions.clear()
-            Actions.update(self.__buildactions(Result[0]["ACTION"], Source))
-
-        return found_match
-
-
     def __search_cdb(self, pathname, keys, actions, source):
         """
         Search DJB's constant databases; see <http:/cr.yp.to/cdb.html>.
@@ -842,24 +800,13 @@
         """
         Attempt to extract the domain name from each address in keys.
         """
-        domains = []
+        domains = {}
         for k in keys:
             try:
-                domains.append(k.split('@', 1)[1])
+                domains[k.split('@', 1)[1]] = None
             except IndexError:
                 pass
-        return domains
-
-
-    def __create_sql_params(self, dbkeys):
-        """Return dictionary of parameters for sql statement."""
-        params = { 'recipient': Defaults.USERNAME+'@'+Defaults.HOSTNAME,
-                   'username' : Defaults.USERNAME,
-                   'hostname' : Defaults.HOSTNAME
-                 }
-        for i in range(len(dbkeys)):
-            params['criterion'+str(i)] = dbkeys[i]
-        return params
+        return domains.keys()
 
 
     def __create_sql_criteria(self, dbkeys, addresscolumn):
@@ -889,33 +836,42 @@
         dbkeys = keys
         if args.has_key('wildcards'):
             dbkeys = []
-        params = self.__create_sql_params(dbkeys)
+        _username = Defaults.USERNAME.lower()
+        _hostname = Defaults.HOSTNAME.lower()
+        _recipient = _username + '@' + _hostname
+        params = create_sql_params(dbkeys,
+                                   recipient=_recipient,
+                                   username=_username,
+                                   hostname=_hostname)
         cursor = self.db_instance.cursor()
-        cursor.execute(selectstmt, params)
-        rows = cursor.fetchall()
-        if cursor.rowcount <= 0:
-            return 0
-        if args.has_key('wildcards'):
-            if len(cursor.description) > 1:
-                dblist = [' '.join([row[0], row[1] or '']) for row in rows]
+        try:
+            cursor.execute(selectstmt, params)
+            rows = cursor.fetchall()
+            if cursor.rowcount <= 0:
+                return 0
+            if args.has_key('wildcards'):
+                if len(cursor.description) > 1:
+                    dblist = [' '.join([row[0], row[1] or '']) for row in rows]
+                else:
+                    dblist = [row[0] for row in rows]
+                found_match = self.__search_list(dblist, keys, actions, source)
             else:
-                dblist = [row[0] for row in rows]
-            found_match = self.__search_list(dblist, keys, actions, source)
-        else:
-            action_column = args.get('action_column')
-            if action_column:
-                actcolidx = self.__get_column_index(action_column, cursor)
-                if actcolidx == -1:
-                    actcolidx = self.__get_column_index(action_column.lower(),
-                                                        cursor)
+                action_column = args.get('action_column')
+                if action_column:
+                    actcolidx = self.__get_column_index(action_column, cursor)
                     if actcolidx == -1:
-                        err = "no action column (%s)" % (action_column,)
-                        raise MatchError(lineno, err)
-                action = rows[0][actcolidx]
-                if action:
-                    actions.clear()
-                    actions.update(self.__buildactions(action, source))
-            found_match = 1
+                        actcolidx = self.__get_column_index(
+                            action_column.lower(), cursor)
+                        if actcolidx == -1:
+                            err = "no action column (%s)" % (action_column,)
+                            raise MatchError(lineno, err)
+                    action = rows[0][actcolidx]
+                    if action:
+                        actions.clear()
+                        actions.update(self.__buildactions(action, source))
+                found_match = 1
+        finally:
+            cursor.close()
         return found_match
 
 
@@ -945,8 +901,7 @@
             if source in ('from-file', 'to-file'):
                 dbname = os.path.expanduser(match)
                 search_func = self.__search_file
-                if args.has_key('domains'):
-                    keys += self.__extract_domains(keys)
+                keys += self.__extract_domains(keys)
                 # If we have an 'auto*' argument, ensure that the database
                 # is up-to-date.  If the 'optional' argument is also given,
                 # don't die if the file doesn't exist.
@@ -974,8 +929,7 @@
             if source in ('from-dbm', 'to-dbm'):
                 import anydbm
                 match = os.path.expanduser(match)
-                if args.has_key('domains'):
-                    keys += self.__extract_domains(keys)
+                keys += self.__extract_domains(keys)
                 try:
                     found_match = self.__search_dbm(match, keys,
                                                     actions, source)
@@ -988,8 +942,7 @@
             if source in ('from-cdb', 'to-cdb'):
                 import cdb
                 match = os.path.expanduser(match)
-                if args.has_key('domains'):
-                    keys += self.__extract_domains(keys)
+                keys += self.__extract_domains(keys)
                 try:
                     found_match = self.__search_cdb(match, keys,
                                                     actions, source)
@@ -1059,22 +1012,13 @@
                             break
                 if found_match:
 		    break
-            # MySQL-style databases.
-            if source in ('from-mysql', 'to-mysql'):
-                found_match = self.__search_mysql \
-                (
-                    match, args, keys, actions, source
-                )
-                if found_match:
-		    break
             # Generic SQL.  Expects a SELECT statement as the 'match' field.
             # There are two "modes", depending on the presence of TMDA-style
             # wildcards in the database.  See the filter source documentation
             # for more information.
             if source in ('from-sql', 'to-sql'):
                 selectstmt = match
-                if args.has_key('domains'):
-                    keys += self.__extract_domains(keys)
+                keys += self.__extract_domains(keys)
                 addr_column = args.get('addr_column')
                 if args.has_key('wildcards'):
                     if addr_column:
@@ -1235,3 +1179,12 @@
     if len(parts) == 1:
         return (parts[0], None)
     return tuple(parts)
+
+
+def create_sql_params(dbkeys=[], **kwargs):
+    """Return dictionary of parameters for SQL statement."""
+    params = kwargs.copy()
+    for i in range(len(dbkeys)):
+        params['criterion'+str(i)] = dbkeys[i]
+    return params
+

Index: Defaults.py
===================================================================
RCS file: /cvsroot/tmda/tmda/TMDA/Defaults.py,v
retrieving revision 1.183
retrieving revision 1.184
diff -u -r1.183 -r1.184
--- Defaults.py	1 Jul 2003 06:29:51 -0000	1.183
+++ Defaults.py	11 Jul 2003 23:02:59 -0000	1.184
@@ -1102,6 +1102,59 @@
 if not vars().has_key('DB_CONNECTION'):
     DB_CONNECTION = None
 
+# DB_CONFIRM_APPEND
+# SQL INSERT statement to be used to insert confirmed sender addresses
+# into a SQL database. The Python DB API will take care of properly
+# quoting parameters that are strings.
+# Requires a valid DB_CONNECTION object.
+#
+# Available substition parameters are:
+#
+# %(recipient)s  - USERNAME@HOSTNAME
+# %(username)s   - USERNAME
+# %(hostname)s   - HOSTNAME
+# %(sender)s     - sender's address (envelope sender or X-Primary-Address)
+#
+# Examples:
+#
+# DB_CONFIRM_APPEND = """
+#  INSERT INTO whitelist (user_email, address)
+#       VALUES (%(recipient)s, %(sender)s)"""
+#
+# DB_CONFIRM_APPEND = """
+#  INSERT INTO wildcard_list (uid, address, action)
+#       SELECT uid, %(sender)s, 'accept'
+#         FROM users
+#        WHERE users.email = %(recipient)s"""
+#
+# Default is None
+if not vars().has_key('DB_CONFIRM_APPEND'):
+    DB_CONFIRM_APPEND = None
+
+# DB_BARE_APPEND
+# SQL INSERT statement to be used to insert recipient addresses into
+# a SQL database if the outgoing <action> was 'bare=append'. The Python
+# DB API will take care of properly quoting parameters that are strings.
+# Requires a valid DB_CONNECTION object.
+#
+# Available substition parameters are:
+#
+# %(recipient)s  - recipient's email address
+# %(username)s   - USERNAME (of TMDA user)
+# %(hostname)s   - HOSTNAME (of TMDA user)
+# %(sender)s     - USERNAME@HOSTNAME (address of TMDA user)
+# %(fromheader)s - address of TMDA user in From: header field
+#
+# Examples:
+#
+# DB_BARE_APPEND = """
+#  INSERT INTO whitelist (user_email, address)
+#       VALUES (%(sender)s, %(recipient)s)"""
+#
+# Default is None
+if not vars().has_key('DB_BARE_APPEND'):
+    DB_BARE_APPEND = None
+
 # PENDING_DIR
 # Full path to the directory containing messages pending confirmation
 # (aka, the "pending queue").  If this directory doesn't exist, it

Index: ChangeLog
===================================================================
RCS file: /cvsroot/tmda/tmda/TMDA/ChangeLog,v
retrieving revision 1.280
retrieving revision 1.281
diff -u -r1.280 -r1.281
--- ChangeLog	5 Jul 2003 00:25:19 -0000	1.280
+++ ChangeLog	11 Jul 2003 23:03:00 -0000	1.281
@@ -1,3 +1,17 @@
+2003-07-11  Tim Legant  <[email protected]>
+
+	* Defaults.py: New variables DB_BARE_APPEND and
+	DB_CONFIRM_APPEND.
+
+	* FilterParser.py (FilterParser): Removed {from,to}-mysql code.
+	Moved __create_sql_params method to module-level function
+	create_sql_params.  Removed -domains argument and always add the
+	domains into the keys.  Made the domains list contain only unique
+	domains.
+
+	* Util.py (db_insert): New function, used by the DB_BARE_APPEND
+	and DB_CONFIRM_APPEND code.
+
 2003-07-01  Tim Legant  <[email protected]>
 
 	* Util.py (filter_match): Create FilterParser with DB_CONNECTION.

_______________________________________
tmda-cvs mailing list
http://tmda.net/lists/listinfo/tmda-cvs
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.