Apply 67_update_handle_old_versions.patch
[mspang/vmailman.git] / Mailman / Mailbox.py
1 # Copyright (C) 1998-2003 by the Free Software Foundation, Inc.
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 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software
15 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16
17 """Extend mailbox.UnixMailbox.
18 """
19
20 import sys
21 import mailbox
22
23 import email
24 from email.Parser import Parser
25 from email.Generator import Generator
26 from email.Errors import MessageParseError
27
28 from Mailman import mm_cfg
29 from Mailman.Message import Message
30
31 try:
32     True, False
33 except NameError:
34     True = 1
35     False = 0
36
37
38 \f
39 def _safeparser(fp):
40     try:
41         return email.message_from_file(fp, Message)
42     except MessageParseError:
43         # Don't return None since that will stop a mailbox iterator
44         return ''
45
46
47 \f
48 class Mailbox(mailbox.PortableUnixMailbox):
49     def __init__(self, fp):
50         mailbox.PortableUnixMailbox.__init__(self, fp, _safeparser)
51
52     # msg should be an rfc822 message or a subclass.
53     def AppendMessage(self, msg):
54         # Check the last character of the file and write a newline if it isn't
55         # a newline (but not at the beginning of an empty file).
56         try:
57             self.fp.seek(-1, 2)
58         except IOError, e:
59             # Assume the file is empty.  We can't portably test the error code
60             # returned, since it differs per platform.
61             pass
62         else:
63             if self.fp.read(1) <> '\n':
64                 self.fp.write('\n')
65         # Seek to the last char of the mailbox
66         self.fp.seek(1, 2)
67         # Create a Generator instance to write the message to the file
68         g = Generator(self.fp)
69         g.flatten(msg, unixfrom=True)
70         # Add one more trailing newline for separation with the next message
71         # to be appended to the mbox.
72         print >> self.fp
73
74
75 \f
76 # This stuff is used by pipermail.py:processUnixMailbox().  It provides an
77 # opportunity for the built-in archiver to scrub archived messages of nasty
78 # things like attachments and such...
79 def _archfactory(mailbox):
80     # The factory gets a file object, but it also needs to have a MailList
81     # object, so the clearest <wink> way to do this is to build a factory
82     # function that has a reference to the mailbox object, which in turn holds
83     # a reference to the mailing list.  Nested scopes would help here, BTW,
84     # but we can't rely on them being around (e.g. Python 2.0).
85     def scrubber(fp, mailbox=mailbox):
86         msg = _safeparser(fp)
87         if msg == '':
88             return msg
89         return mailbox.scrub(msg)
90     return scrubber
91
92
93 class ArchiverMailbox(Mailbox):
94     # This is a derived class which is instantiated with a reference to the
95     # MailList object.  It is build such that the factory calls back into its
96     # scrub() method, giving the scrubber module a chance to do its thing
97     # before the message is archived.
98     def __init__(self, fp, mlist):
99         if mm_cfg.ARCHIVE_SCRUBBER:
100             __import__(mm_cfg.ARCHIVE_SCRUBBER)
101             self._scrubber = sys.modules[mm_cfg.ARCHIVE_SCRUBBER].process
102         else:
103             self._scrubber = None
104         self._mlist = mlist
105         mailbox.PortableUnixMailbox.__init__(self, fp, _archfactory(self))
106
107     def scrub(self, msg):
108         if self._scrubber:
109             return self._scrubber(self._mlist, msg)
110         else:
111             return msg