# Copyright (C) 2021 Max Erenberg # This file is adapted from GNU Mailman. The original copyright notice # is preserved below. # # Copyright (C) 2008-2019 by the Free Software Foundation, Inc. # # This file is part of GNU Mailman. # # GNU Mailman 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 3 of the License, or (at your option) # any later version. # # GNU Mailman 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 # GNU Mailman. If not, see . """ A simple archiver which copies each message into a folder for the current month. """ from contextlib import suppress import datetime from datetime import timedelta from email.utils import parsedate import gzip import logging import os import time from flufl.lock import Lock, TimeOutError from mailbox import Maildir from mailman.config import config from mailman.interfaces.archiver import IArchiver from public import public from zope.interface import implementer log = logging.getLogger('mailman.error') @public @implementer(IArchiver) class MonthlyArchiver: """ A simple archiver which copies each message into a folder for the current month. It is adapted from the `Prototype` archiver. """ name = 'monthly_archiver' is_enabled = False @staticmethod def list_url(mlist): """See `IArchiver`.""" # This archiver is not web-accessible, therefore no URL is returned. return None @staticmethod def permalink(mlist, msg): """See `IArchiver`.""" # This archiver is not web-accessible, therefore no URL is returned. return None @staticmethod def archive_message(mlist, message): """See `IArchiver`. This archiver saves messages into a folder for the current year and month, e.g. '2021-April'. :type mlist: mailman.model.listmanager.ListManager :type message: mailman.email.message.Message """ message_id = message.get('message-id') date_secs = parsedate(message.get('date')) if date_secs is not None: date = time.localtime(time.mktime(date_secs)) else: log.warning('Could not extract date from message %s, using ' 'local time instead' % message_id) date = time.localtime() year_and_month = time.strftime('%Y-%B', date) archive_dir = os.path.join( config.ARCHIVE_DIR, MonthlyArchiver.name, mlist.fqdn_listname, year_and_month ) with suppress(FileExistsError): os.makedirs(archive_dir, 0o775) # Just use the current timestamp as the file name filename = str(round(time.time(), 3)) + '.mail.gz' dst = os.path.join(archive_dir, filename) log.info('MonthlyArchiver archived message %s to %s' % (message_id, dst)) # gzip the file to try to save some disk space with gzip.open(dst, 'wb') as fo: fo.write(message.as_bytes()) return None