#! @PYTHON@
#
# Copyright (C) 1998-2018 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.

"""Check a list's config database file for integrity.

All of the following files are checked:

    config.pck
    config.pck.last
    config.db
    config.db.last
    config.safety

It's okay if any of these are missing.  config.pck and config.pck.last are
pickled versions of the config database file for 2.1a3 and beyond.  config.db
and config.db.last are used in all earlier versions, and these are Python
marshals.  config.safety is a pickle written by 2.1a3 and beyond when the
primary config.pck file could not be read.

Usage: %(PROGRAM)s [options] [listname [listname ...]]

Options:

    --all / -a
        Check the databases for all lists.  Otherwise only the lists named on
        the command line are checked.

    --verbose / -v
        Verbose output.  The state of every tested file is printed.
        Otherwise only corrupt files are displayed.

    --help / -h
        Print this text and exit.
"""

import sys
import os
import errno
import getopt
import marshal
import cPickle

import paths
from Mailman import mm_cfg
from Mailman import Utils
from Mailman.MailList import MailList
from Mailman.i18n import C_

PROGRAM = sys.argv[0]



def usage(code, msg=''):
    if code:
        fd = sys.stderr
    else:
        fd = sys.stdout
    print >> fd, C_(__doc__)
    if msg:
        print >> fd, msg
    sys.exit(code)



def testfile(dbfile):
    if dbfile.endswith('.db') or dbfile.endswith('.db.last'):
        loadfunc = marshal.load
    elif dbfile.endswith('.pck') or dbfile.endswith('.pck.last'):
        loadfunc = cPickle.load
    else:
        assert 0
    fp = open(dbfile)
    try:
        loadfunc(fp)
    finally:
        fp.close()


def main():
    try:
        opts, args = getopt.getopt(sys.argv[1:], 'ahv',
                                   ['all', 'verbose', 'help'])
    except getopt.error, msg:
        usage(1, msg)

    verbose = 0
    listnames = args

    for opt, arg in opts:
        if opt in ('-h', '--help'):
            usage(0)
        elif opt in ('-v', '--verbose'):
            verbose = 1
        elif opt in ('-a', '--all'):
            listnames = Utils.list_names()

    listnames = [n.lower().strip() for n in listnames]
    if not listnames:
        print C_('Nothing to do.')
        sys.exit(0)

    for listname in listnames:
        if not Utils.list_exists(listname):
            print C_('No list named:'), listname
            continue
        mlist = MailList(listname, lock=0)
        pfile = os.path.join(mlist.fullpath(), 'config.pck')
        plast = pfile + '.last'
        dfile = os.path.join(mlist.fullpath(), 'config.db')
        dlast = dfile + '.last'

        if verbose:
            print C_('List:'), listname

        for file in (pfile, plast, dfile, dlast):
            status = 0
            try:
                testfile(file)
            except IOError, e:
                # Don't report ENOENT unless we're in verbose mode
                if verbose or e.errno <> errno.ENOENT:
                    status = e
            except Exception, e:
                status = e
            # Report errors
            if status:
                if isinstance(status, EnvironmentError):
                    # This already includes the file name
                    print '   ', status
                else:
                    print '    %s: %s' % (file, status)
            elif verbose:
                print C_('   %(file)s: okay')



if __name__ == '__main__':
    main()
