#! /usr/bin/env python
#
# Copyright (C) 1998,1999,2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

"""Attempt redelivery for all messages that had delivery problems.
"""

import sys
import os
import marshal

import paths
from Mailman import mm_cfg
from Mailman import MailList
from Mailman import LockFile
from Mailman import Message
from Mailman import Errors
from Mailman.Handlers import HandlerAPI
from Mailman.Logging.Utils import LogStdErr


# Work around known problems with some RedHat cron daemons
import signal
signal.signal(signal.SIGCHLD, signal.SIG_DFL)

QRUNNER_LOCK_FILE = os.path.join(mm_cfg.LOCK_DIR, 'qrunner.lock')
QRUNNER_LOCK_LIFETIME = 60 * 10                   # seconds

LogStdErr('error', 'qrunner', tee_to_stdout=0)



def main():
    # first, claim the queue runner lock
    lock = LockFile.LockFile(QRUNNER_LOCK_FILE, lifetime=QRUNNER_LOCK_LIFETIME)
    try:
        lock.lock(timeout=0.5)
    except LockFile.TimeOutError:
        # TBD: It is possible that some other process has laid claim to the
        # gate lock for this list, but that said process has exited uncleanly.
        # If that's the case, and it leaves it's lock claim on disk, we will
        # never be able to gate from usenet to the list again, until the stale
        # lock is removed.  For now, we just log this potentially deadlocked
        # situation, but this should really be fixed (probably in LockFile.py
        # though).
        sys.stderr.write('Could not acquire qrunner lock')
        return
    for file in os.listdir(mm_cfg.QUEUE_DIR):
        root, ext = os.path.splitext(os.path.join(mm_cfg.QUEUE_DIR, file))
        if ext == '.db':
            # trigger just off the .msg file
            continue
        try:
            msgfp = open(root + '.msg')
            msgtext = msgfp.read()
            msgfp.close()
            dbfp = open(root + '.db')
            msgdata = marshal.load(dbfp)
            dbfp.close()
        except (EOFError, ValueError, TypeError, IOError), e:
            # For some reason we had trouble getting all the information out
            # of the queued files.  log this and move on (we figure it's a
            # temporary problem)
            sys.stderr.write('Exception reading qfiles: %s' % e)
            continue
        listname = msgdata['listname']
        recips = msgdata['recips']
        msg = Message.OutgoingMessage(msgtext)
        try:
            mlist = MailList.MailList(listname)
        except Errors.MMListError, e:
            sys.stderr.write('Problem opening mailing list %s: %s' %
                             (listname, e))
            continue
        try:
            msg.recips = recips
            HandlerAPI.RedeliverMessage(mlist, msg)
            # check to see if this message needs to be requeued
            if not getattr(msg, 'failedcount', 0):
                # we're done with this message
                os.unlink(root + '.db')
                os.unlink(root + '.msg')
        finally:
            mlist.Save()
            mlist.Unlock()
    # we're done, release the lock
    lock.unlock()



if __name__ == '__main__':
    main()
