]> mj.ucw.cz Git - mailman-filter.git/blob - Filter.py
Debian: Updated debian/compat for Stretch
[mailman-filter.git] / Filter.py
1 # Copyright (C) 2011 by Jan Moskyto Matejka <moskyto@atrey.karlin.mff.cuni.cz>
2 #
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
7
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 # GNU General Public License for more details.
12
13 from Mailman import mm_cfg
14 from Mailman import Errors
15 from Mailman.Logging.Syslog import syslog
16 from Mailman.Handlers import Hold
17 from subprocess import Popen, PIPE
18 import socket, errno
19
20 """Do custom filtering.
21
22 Messages are passed to a custom script for filtering.
23 """
24
25 # This is the default location of the filter script
26 GLOBAL_FILTER_COMMAND = getattr(mm_cfg, 'GLOBAL_FILTER_COMMAND', '/var/lib/mailman/scripts/filter')
27
28 class FilterDiscard(Errors.DiscardMessage):
29         '''The filter wants to discard the message'''
30         def __init__(self, rea, rej):
31                 Errors.DiscardMessage.__init__(self)
32                 self.reason = rea
33                 self.rejection = rej
34
35 class FilterHold(Errors.HoldMessage):
36         '''The filter wants to hold the message'''
37         def __init__(self, rea, rej):
38                 Errors.HoldMessage.__init__(self)
39                 self.reason = rea
40                 self.rejection = rej
41
42 def process(mlist, msg, msgdata):
43         sender = msg.get_sender(use_envelope=0)
44         def not_a_delimiter(str):
45                 if (len(str) == 0):
46                         return False
47                 if (len(str) < 4):
48                         return True
49                 if (str.replace("=",'') == '\n'):
50                         return False
51                 return True
52
53         try:
54                 filter = Popen(args=GLOBAL_FILTER_COMMAND, stdin=PIPE, stdout=PIPE)
55                 filter.stdin.write(str(msg))
56                 filter.stdin.close()
57         except IOError, e:
58                 syslog('error', 'We got SIGPIPE from the filter on %s post from %s: %s' % (mlist.real_name, msg.get_sender(), e))
59                 Hold.hold_for_approval(mlist, msg, msgdata, FilterHold("Filter dead.", "Your mail is held for moderation because of internal rules."))
60
61         reason = ""
62         r = filter.stdout.readline()
63         while (not_a_delimiter(r)):
64                 reason += r
65                 r = filter.stdout.readline()
66
67         rejection = ""
68         r = filter.stdout.readline()
69         while (not_a_delimiter(r)):
70                 rejection += r
71                 r = filter.stdout.readline()
72         
73         reason = reason.strip()
74         rejection = rejection.strip()   
75
76         state = filter.wait()
77         
78         if state == 0:
79                 return
80         if state == 1:
81                 Hold.hold_for_approval(mlist, msg, msgdata, FilterHold(reason, rejection))
82         elif state == 2:
83                 syslog('vette', '%s post from %s discarded: %s' % (mlist.real_name, msg.get_sender(), reason))
84                 raise FilterDiscard(reason, rejection)
85         else:
86                 syslog('error', 'The filter returned on %s post from %s some strange state: %s' % (mlist.real_name, msg.get_sender(), state))
87                 Hold.hold_for_approval(mlist, msg, msgdata, FilterHold("The post is held for UNDEFINED reason.", "The post is held for UNDEFINED reason."))