]> mj.ucw.cz Git - mailman-filter.git/commitdiff
Original version by Moskyto
authorMartin Mares <mj@ucw.cz>
Fri, 21 Oct 2011 18:14:35 +0000 (20:14 +0200)
committerMartin Mares <mj@ucw.cz>
Fri, 21 Oct 2011 18:14:35 +0000 (20:14 +0200)
Filter.py [new file with mode: 0644]
README [new file with mode: 0644]

diff --git a/Filter.py b/Filter.py
new file mode 100644 (file)
index 0000000..a4458ee
--- /dev/null
+++ b/Filter.py
@@ -0,0 +1,90 @@
+# Copyright (C) 2011 by Jan Moskyto Matejka <moskyto@atrey.karlin.mff.cuni.cz>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+from Mailman import mm_cfg
+from Mailman import Errors
+from Mailman.Logging.Syslog import syslog
+from Mailman.Handlers import Hold
+from subprocess import Popen, PIPE
+import socket, errno
+
+"""Do custom filtering.
+
+Messages are passed to a custom script for filtering.
+"""
+
+# This is the default location of the filter script
+GLOBAL_FILTER_COMMAND = getattr(mm_cfg, 'GLOBAL_FILTER_COMMAND', '/var/lib/mailman/scripts/filter')
+
+class FilterDiscard(Errors.DiscardMessage):
+       '''The filter wants to discard the message'''
+       def __init__(self, rea, rej):
+               Errors.DiscardMessage.__init__(self)
+               self.reason = rea
+               self.rejection = rej
+
+class FilterHold(Errors.HoldMessage):
+       '''The filter wants to hold the message'''
+       def __init__(self, rea, rej):
+               Errors.HoldMessage.__init__(self)
+               self.reason = rea
+               self.rejection = rej
+
+def process(mlist, msg, msgdata):
+        sender = msg.get_sender(use_envelope=0)
+       if sender.replace('moskyto','') != sender:
+               return
+       def not_a_delimiter(str):
+               if (len(str) == 0):
+                       return False
+               if (len(str) < 4):
+                       return True
+               if (str.replace("=",'') == '\n'):
+                       return False
+               return True
+
+       try:
+               filter = Popen(args=GLOBAL_FILTER_COMMAND, stdin=PIPE, stdout=PIPE)
+               filter.stdin.write(str(msg))
+               filter.stdin.close()
+       except IOError, e:
+               syslog('error', 'We got SIGPIPE from the filter on %s post from %s: %s' % (mlist.real_name, msg.get_sender(), e))
+               Hold.hold_for_approval(mlist, msg, msgdata, FilterHold("Filter dead.", "Your mail is held for moderation because of internal rules."))
+
+       reason = ""
+       r = filter.stdout.readline()
+       while (not_a_delimiter(r)):
+               reason += r
+               r = filter.stdout.readline()
+
+       rejection = ""
+       r = filter.stdout.readline()
+       while (not_a_delimiter(r)):
+               rejection += r
+               r = filter.stdout.readline()
+       
+       reason = reason.strip()
+       rejection = rejection.strip()   
+
+       state = filter.wait()
+       
+       if state == 0:
+               return
+       if state == 1:
+               Hold.hold_for_approval(mlist, msg, msgdata, FilterHold(reason, rejection))
+       elif state == 2:
+               syslog('vette', '%s post from %s discarded: %s' % (mlist.real_name, msg.get_sender(), reason))
+               raise FilterDiscard(reason, rejection)
+
+       else:
+               syslog('error', 'The filter returned on %s post from %s some strange state: %s' % (mlist.real_name, msg.get_sender(), state))
+               Hold.hold_for_approval(mlist, msg, msgdata, FilterHold("The post is hold for UNDEFINED reason.", "The post is  hold for UNDEFINED reason."))
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..cf18569
--- /dev/null
+++ b/README
@@ -0,0 +1,78 @@
+Mailman custom filter plugin.
+(c) 2011 Jan Moskyto Matejka <moskyto@atrey.karlin.mff.cuni.cz>
+
+== Description ==
+This plugin runs your custom script for each message passed in. Your custom
+script should
+- return 0 if the message is to be passed through
+- return 1 if the message is to be hold for moderation
+- return 2 if the message is to be discarded
+
+Your script should also provide the reason message for the moderator (or into
+the 'vette' log file) and the rejection message for the sender.
+
+The script gets the message on its stdin terminated by EOF. It shall read whole
+the message before writing anything to output, otherwise deadlock is possible.
+It shall write the reason message on stdout delimited by a line with at least
+four = and nothing else: ===== is a delimiter, ==x==x== isn't a delimiter.
+
+Example:
+The script returns
+Lorem ipsum
+Dolor sit
+amet.
+=====
+Est consectetur
+Adipiscing
+elit.
+=====
+
+The reason message is
+Lorem ipsum
+Dolor sit
+amet.
+
+The rejection message is
+Est consectetur
+Adipiscing
+elit.
+
+== Usage ==
+Put Filter.py into the Mailman's handler directory, mostly it is
+/usr/lib/mailman/Mailman/Handlers/.
+
+Create your own script wherever you want. It must have the executable bit set
+for the user who runs the list (mostly `list'). It must be also readable for
+that user, obviously. It may be also binary if you want.
+
+Edit your mm_cfg.py (mostly in /etc/mailman) -- append this:
+GLOBAL_PIPELINE.insert(1, 'Filter')
+GLOBAL_FILTER_COMMAND = "/path/to/your/custom/filter/script"
+
+You may also put the provided (or any other) simple `filter' script into
+/var/lib/mailman/scripts/ as this is its default location hard-coded into
+Filter.py.
+
+Restart Mailman.
+
+== Known bugs ==
+On moderation, Mailman in version 2.1.14 sends not the rejection message to
+the sender, but the reason message. It is not a bug of this plugin, it is a bug
+of Mailman. It may occur also in other versions. Patch for 2.1.14 included --
+apply on /usr/lib/mailman/Mailman/Handlers/Hold.py (or similar) and don't
+forget to recompile Hold.pyc (pycompile) and restart Mailman.
+
+== License ==
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software 
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, US