Lloyd Zusman <[EMAIL PROTECTED]> writes:

> [ ... ]

I have now attached an updated patch (see below).  If no one has any
problems or issues with this, I'll ask that it be accepted as official.
Here are some follow-up comments to my last message:


> Stephen Warren <[EMAIL PROTECTED]> writes:
>
>> [ ... ]
>>
>> Lloyd Zusman wrote:
>>> +from types import *
>>
>> What's the benefit of this v.s. "import types"?
>
> None.  I had used it during development of this patch, where I had been
> comparing something to StringType.  But I don't use that any more [ ... ]

This line is now gone.


>>> +DefaultVarPat = re.compile('^[A-Z][A-Z0-9_]*$')
>>
>> [ ... ]
>
> Hmm ... actually, the '0-9' part of the pattern might be superfluous.
> [ ... ]

It turns out that the numbers are indeed necessary, in order to match
this variable: ALLOW_MODE_640


>>> +                try:
>>> +                    if v is None:
>>> +                        del os.environ[k]
>>> +                    else:
>>> +                        os.environ[k] = str(v)
>>> +                except:
>>> +                    pass
>>
>> What's the rationale for ignoring exceptions here?

If a variable doesn't exist in the environment, the 'del' raises an
exception.  I'd rather use an exception here than to do an explicit test
for the variable's existence in the environment every time I issue a
'del'.  I have moved the exception test to within the "if v is None:"
block.


>>> +        Util.pipecmd('%s %s' % (hook, pendpath), self.show())
>>
>> Are there any issues that require quoting of these strings to avoid
>> nasty shell escape issues? For some reason, I thought TMDA external
>> commands were executed with a list of arguments, rather than a
>> shell-style string that required parsing?

As I have mentioned, Util.pipecmd is already used in exactly this manner
within Deliver.py and Util.py, so I don't believe that these issues are
any worse here than during TMDA's normal piped delivery of messages.

During further testing, I discovered that there are occasional deadlocks
when using Util.pipecmd() with certain hook function scripts.
Therefore, in the new patch, I replaced this call with an explicit
invocation of os.popen().  That seemed to fix the deadlock problem.

Thanks again for all your feedback.


Here's the patch:

--- bin/tmda-rfilter.orig	2007-04-01 17:59:00.000000000 -0400
+++ bin/tmda-rfilter	2007-04-01 18:00:45.000000000 -0400
@@ -474,4 +474,7 @@
 def release_pending(timestamp, pid, msg):
     """Release a confirmed message from the pending queue."""
+    # If there is a pending confirm hook, attempt to pipe
+    # the message through it.
+    msg.tryActionHook(Defaults.PENDING_CONFIRM_ACTION_HOOK)
     # Remove Return-Path: to avoid duplicates.
     return_path = return_path = parseaddr(msg.get('return-path'))[1]
--- TMDA/Defaults.py.orig	2007-04-01 12:51:53.000000000 -0400
+++ TMDA/Defaults.py	2007-04-01 18:03:12.000000000 -0400
@@ -1213,4 +1213,99 @@
     PENDING_WHITELIST_RELEASE = 1
 
+# PENDING_RELEASE_ACTION_HOOK
+# Path of an optional executable that will be run when a message
+# is being released from the pending queue, right before this
+# release takes place.
+#
+# It will be run as follows:
+#
+# /path/to/executable /path/to/pending-message-file
+#
+# The message text will be available in this executable's stdin.
+#
+# When this executable is invoked, all TMDA configuration
+# variables will be available in the environment in the
+# form of strings.
+#
+# Default is None
+if not vars().has_key('PENDING_RELEASE_ACTION_HOOK'):
+    PENDING_RELEASE_ACTION_HOOK = None
+
+# PENDING_CONFIRM_ACTION_HOOK
+# Path of an optional executable that will be run when a message
+# is being confirmed from the pending queue, right before this
+# confirmation takes place.
+#
+# It will be run as follows:
+#
+# /path/to/executable /path/to/pending-message-file
+#
+# The message text will be available in this executable's stdin.
+#
+# When this executable is invoked, all TMDA configuration
+# variables will be available in the environment in the
+# form of strings.
+#
+# Default is None
+if not vars().has_key('PENDING_CONFIRM_ACTION_HOOK'):
+    PENDING_CONFIRM_ACTION_HOOK = None
+
+# PENDING_DELETE_ACTION_HOOK
+# Path of an optional executable that will be run when a message
+# is being deleted from the pending queue, right before this
+# deletion takes place.
+#
+# It will be run as follows:
+#
+# /path/to/executable /path/to/pending-message-file
+#
+# The message text will be available in this executable's stdin.
+#
+# When this executable is invoked, all TMDA configuration
+# variables will be available in the environment in the
+# form of strings.
+#
+# Default is None
+if not vars().has_key('PENDING_DELETE_ACTION_HOOK'):
+    PENDING_DELETE_ACTION_HOOK = None
+
+# PENDING_WHITELIST_ACTION_HOOK
+# Path of an optional executable that will be run when a message
+# is being whitelisted from the pending queue, right before this
+# whitelisting takes place.
+#
+# It will be run as follows:
+#
+# /path/to/executable /path/to/pending-message-file
+#
+# The message text will be available in this executable's stdin.
+#
+# When this executable is invoked, all TMDA configuration
+# variables will be available in the environment in the
+# form of strings.
+#
+# Default is None
+if not vars().has_key('PENDING_WHITELIST_ACTION_HOOK'):
+    PENDING_WHITELIST_ACTION_HOOK = None
+
+# PENDING_BLACKLIST_ACTION_HOOK
+# Path of an optional executable that will be run when a message
+# is being blacklisted from the pending queue, right before this
+# blacklisting takes place.
+#
+# It will be run as follows:
+#
+# /path/to/executable /path/to/pending-message-file
+#
+# The message text will be available in this executable's stdin.
+#
+# When this executable is invoked, all TMDA configuration
+# variables will be available in the environment in the
+# form of strings.
+#
+# Default is None
+if not vars().has_key('PENDING_BLACKLIST_ACTION_HOOK'):
+    PENDING_BLACKLIST_ACTION_HOOK = None
+
 # ADDED_HEADERS_CLIENT
 # A Python dictionary containing one or more header:value string pairs
@@ -1599,4 +1694,9 @@
     'PENDING_RELEASE_APPEND': None,
     'PENDING_WHITELIST_APPEND': None,
+    'PENDING_RELEASE_ACTION_HOOK' : None,
+    'PENDING_CONFIRM_ACTION_HOOK' : None,
+    'PENDING_DELETE_ACTION_HOOK' : None,
+    'PENDING_WHITELIST_ACTION_HOOK' : None,
+    'PENDING_BLACKLIST_ACTION_HOOK' : None,
     'RESPONSE_DIR': None,
     'SENDMAIL_PROGRAM': None,
--- TMDA/Pending.py.orig	2007-04-01 13:06:15.000000000 -0400
+++ TMDA/Pending.py	2007-04-05 15:37:30.000000000 -0400
@@ -28,4 +28,5 @@
 import email
 import os
+import re
 import sys
 import time
@@ -40,4 +41,5 @@
 Q = Q.init()
 
+DefaultVarPat = re.compile('^[A-Z][A-Z0-9_]*$')
 
 class Queue:
@@ -366,7 +368,41 @@
             self.x_primary_address, self.return_path)
 
+    def tryActionHook(self, hook):
+        """Attempt to run an action hook"""
+        if hook is None:
+            return
+        # Put all appropriate Defaults variables into the environment.
+        for (k, v) in vars(Defaults).items():
+            if DefaultVarPat.search(k):
+                if v is None:
+                    try:
+                        del os.environ[k]
+                    except:
+                        # key not in current environment
+                        pass
+                else:
+                    os.environ[k] = str(v)
+        cmd = '%s %s' % (hook, os.path.join(Defaults.PENDING_DIR, self.msgid + '.msg'))
+        try:
+            # Pipe the message into the hook's stdin and let
+            # the hook's stdout and stderr go out unimpeded.
+            fd = os.popen(cmd, 'w')
+            fd.write(self.show())
+            fd.flush()
+            r = fd.close()
+            if r is None:
+                return 0
+            else:
+                return r
+        except Exception, txt:
+            raise IOError, \
+                  'failure invoking hook "%s" (%s)' % (cmd, txt)
+
     def release(self):
         """Release a message from the pending queue."""
         import Cookie
+        # If there is a pending release hook, attempt to pipe
+        # the message through it.
+        self.tryActionHook(Defaults.PENDING_RELEASE_ACTION_HOOK)
         if Defaults.PENDING_RELEASE_APPEND:
             Util.append_to_file(self.append_address,
@@ -401,4 +437,7 @@
     def delete(self):
         """Delete a message from the pending queue."""
+        # If there is a pending delete hook, attempt to pipe
+        # the message through it.
+        self.tryActionHook(Defaults.PENDING_DELETE_ACTION_HOOK)
         if Defaults.PENDING_DELETE_APPEND:
             Util.append_to_file(self.append_address,
@@ -408,4 +447,7 @@
     def whitelist(self):
         """Whitelist the message sender."""
+        # If there is a pending whitelist hook, attempt to pipe
+        # the message through it.
+        self.tryActionHook(Defaults.PENDING_WHITELIST_ACTION_HOOK)
         if Defaults.PENDING_WHITELIST_APPEND:
             Util.append_to_file(self.append_address,
@@ -419,4 +461,7 @@
     def blacklist(self):
         """Blacklist the message sender."""
+        # If there is a pending blacklist hook, attempt to pipe
+        # the message through it.
+        self.tryActionHook(Defaults.PENDING_BLACKLIST_ACTION_HOOK)
         if Defaults.PENDING_BLACKLIST_APPEND:
             Util.append_to_file(self.append_address,

-- 
 Lloyd Zusman
 [EMAIL PROTECTED]
 God bless you.
_________________________________________________
tmda-workers mailing list ([email protected])
http://tmda.net/lists/listinfo/tmda-workers

Reply via email to