diff options
| author | Barry Warsaw | 2008-02-27 01:26:18 -0500 |
|---|---|---|
| committer | Barry Warsaw | 2008-02-27 01:26:18 -0500 |
| commit | a1c73f6c305c7f74987d99855ba59d8fa823c253 (patch) | |
| tree | 65696889450862357c9e05c8e9a589f1bdc074ac /Mailman/database/messagestore.py | |
| parent | 3f31f8cce369529d177cfb5a7c66346ec1e12130 (diff) | |
| download | mailman-a1c73f6c305c7f74987d99855ba59d8fa823c253.tar.gz mailman-a1c73f6c305c7f74987d99855ba59d8fa823c253.tar.zst mailman-a1c73f6c305c7f74987d99855ba59d8fa823c253.zip | |
Diffstat (limited to 'Mailman/database/messagestore.py')
| -rw-r--r-- | Mailman/database/messagestore.py | 132 |
1 files changed, 0 insertions, 132 deletions
diff --git a/Mailman/database/messagestore.py b/Mailman/database/messagestore.py deleted file mode 100644 index 6e0bf57c5..000000000 --- a/Mailman/database/messagestore.py +++ /dev/null @@ -1,132 +0,0 @@ -# Copyright (C) 2007-2008 by the Free Software Foundation, Inc. -# -# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -# USA. - -from __future__ import with_statement - -__metaclass__ = type -__all__ = [ - 'MessageStore', - ] - -import os -import errno -import base64 -import hashlib -import cPickle as pickle - -from zope.interface import implements - -from Mailman import Utils -from Mailman.configuration import config -from Mailman.database.message import Message -from Mailman.interfaces import IMessageStore - -# It could be very bad if you have already stored files and you change this -# value. We'd need a script to reshuffle and resplit. -MAX_SPLITS = 2 -EMPTYSTRING = '' - - - -class MessageStore: - implements(IMessageStore) - - def add(self, message): - # Ensure that the message has the requisite headers. - message_ids = message.get_all('message-id', []) - if len(message_ids) <> 1: - raise ValueError('Exactly one Message-ID header required') - # Calculate and insert the X-Message-ID-Hash. - message_id = message_ids[0] - # Complain if the Message-ID already exists in the storage. - existing = config.db.store.find(Message, - Message.message_id == message_id).one() - if existing is not None: - raise ValueError('Message ID already exists in message store: %s', - message_id) - shaobj = hashlib.sha1(message_id) - hash32 = base64.b32encode(shaobj.digest()) - del message['X-Message-ID-Hash'] - message['X-Message-ID-Hash'] = hash32 - # Calculate the path on disk where we're going to store this message - # object, in pickled format. - parts = [] - split = list(hash32) - while split and len(parts) < MAX_SPLITS: - parts.append(split.pop(0) + split.pop(0)) - parts.append(hash32) - relpath = os.path.join(*parts) - # Store the message in the database. This relies on the database - # providing a unique serial number, but to get this information, we - # have to use a straight insert instead of relying on Elixir to create - # the object. - row = Message(message_id=message_id, - message_id_hash=hash32, - path=relpath) - # Now calculate the full file system path. - path = os.path.join(config.MESSAGES_DIR, relpath) - # Write the file to the path, but catch the appropriate exception in - # case the parent directories don't yet exist. In that case, create - # them and try again. - while True: - try: - with open(path, 'w') as fp: - # -1 says to use the highest protocol available. - pickle.dump(message, fp, -1) - break - except IOError, e: - if e.errno <> errno.ENOENT: - raise - os.makedirs(os.path.dirname(path)) - return hash32 - - def _get_message(self, row): - path = os.path.join(config.MESSAGES_DIR, row.path) - with open(path) as fp: - return pickle.load(fp) - - def get_message_by_id(self, message_id): - row = config.db.store.find(Message, message_id=message_id).one() - if row is None: - return None - return self._get_message(row) - - def get_message_by_hash(self, message_id_hash): - # It's possible the hash came from a message header, in which case it - # will be a Unicode. However when coming from source code, it may be - # an 8-string. Coerce to the latter if necessary; it must be - # US-ASCII. - if isinstance(message_id_hash, unicode): - message_id_hash = message_id_hash.encode('ascii') - row = config.db.store.find(Message, - message_id_hash=message_id_hash).one() - if row is None: - return None - return self._get_message(row) - - @property - def messages(self): - for row in config.db.store.find(Message): - yield self._get_message(row) - - def delete_message(self, message_id): - row = config.db.store.find(Message, message_id=message_id).one() - if row is None: - raise LookupError(message_id) - path = os.path.join(config.MESSAGES_DIR, row.path) - os.remove(path) - config.db.store.remove(row) |
