]> Frank Brehm's Git Trees - my-stuff/py-logrotate.git/commitdiff
Größerer Umbau
authorFrank Brehm <frank@brehm-online.com>
Tue, 12 Jul 2011 21:18:24 +0000 (21:18 +0000)
committerFrank Brehm <frank@brehm-online.com>
Tue, 12 Jul 2011 21:18:24 +0000 (21:18 +0000)
git-svn-id: http://svn.brehm-online.com/svn/my-stuff/python/PyLogrotate/trunk@285 ec8d2aa5-1599-4edb-8739-2b3a1bc399aa

16 files changed:
LogRotate/LogRotateCommon.py [new file with mode: 0755]
LogRotate/LogRotateConfig.py [new file with mode: 0755]
LogRotate/LogRotateGetopts.py [new file with mode: 0755]
LogRotate/LogRotateHandler.py [new file with mode: 0755]
LogRotate/LogRotateMailer.py [new file with mode: 0755]
LogRotate/LogRotateScript.py [new file with mode: 0755]
LogRotate/LogRotateStatusFile.py [new file with mode: 0755]
LogRotate/__init__.py [new file with mode: 0755]
LogRotateCommon.py [deleted file]
LogRotateConfig.py [deleted file]
LogRotateGetopts.py [deleted file]
LogRotateHandler.py [deleted file]
LogRotateMailer.py [deleted file]
LogRotateScript.py [deleted file]
LogRotateStatusFile.py [deleted file]
logrotate.py

diff --git a/LogRotate/LogRotateCommon.py b/LogRotate/LogRotateCommon.py
new file mode 100755 (executable)
index 0000000..af03d1b
--- /dev/null
@@ -0,0 +1,512 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# $Id$
+# $URL$
+
+'''
+@author: Frank Brehm
+@contact: frank@brehm-online.com
+@license: GPL3
+@copyright: (c) 2010-2011 by Frank Brehm, Berlin
+@version: 0.1.0
+@summary: Module for common used functions
+'''
+
+import re
+import sys
+import locale
+import logging
+import gettext
+import csv
+import pprint
+import email.utils
+
+revision = '$Revision$'
+revision = re.sub( r'\$', '', revision )
+revision = re.sub( r'Revision: ', r'r', revision )
+revision = re.sub( r'\s*$', '', revision )
+
+__author__    = 'Frank Brehm'
+__copyright__ = '(C) 2011 by Frank Brehm, Berlin'
+__contact__    = 'frank@brehm-online.com'
+__version__    = '0.1.0 ' + revision
+__license__    = 'GPL3'
+
+
+logger = logging.getLogger('pylogrotate.common')
+locale_dir = None
+
+#========================================================================
+
+def split_parts( text, keep_quotes = False, raise_on_unbalanced = True):
+    '''
+    Split the given text in chunks by whitespaces or
+    single or double quoted strings.
+        
+    @param text:        the text to split in chunks
+    @type text:         str
+    @param keep_quotes: keep quotes of quoted chunks
+    @type keep_quotes:  bool
+    @param raise_on_unbalanced: raise an exception on
+                                unbalanced quotes
+    @type raise_on_unbalanced:  bool
+
+    @return: list of chunks
+    @rtype:  list
+    '''
+
+    chunks = []
+    if text is None:
+        return chunks
+
+    txt = str(text)
+    last_chunk = ''
+
+    # Big loop to split the text - until it is empty
+    while txt != '':
+
+        # add chunk, if there is a chunk left and a whitspace
+        # at the begin of the line
+        match = re.search(r"\s+", txt)
+        if ( last_chunk != '' ) and match:
+            chunks.append(last_chunk)
+            last_chunk = ''
+
+        # clean the line
+        txt = txt.strip()
+        if txt == '':
+            break
+
+        # search for a single quoted string at the begin of the line
+        match = re.search(r"^'((?:\\'|[^'])*)'", txt)
+        if match:
+            chunk = match.group(1)
+            chunk = re.sub(r"\\'", "'", chunk)
+            if keep_quotes:
+                chunk = "'" + chunk + "'"
+            last_chunk += chunk
+            txt = re.sub(r"^'(?:\\'|[^'])*'", "", txt)
+            continue
+
+        # search for a double quoted string at the begin of the line
+        match = re.search(r'^"((?:\\"|[^"])*)"', txt)
+        if match:
+            chunk = match.group(1)
+            chunk = re.sub(r'\\"', '"', chunk)
+            if keep_quotes:
+                chunk = '"' + chunk + '"'
+            last_chunk += chunk
+            txt = re.sub(r'^"(?:\\"|[^"])*"', "", txt)
+            continue
+
+        # search for unquoted, whitespace delimited text
+        # at the begin of the line
+        match = re.search(r'^((?:[^\s\'"]+|\\\'|\\")+)', txt)
+        if match:
+            last_chunk += match.group(1)
+            txt = re.sub(r'^(?:[^\s\'"]+|\\\'|\\")+', "", txt)
+            continue
+
+        # Only whitespaces left
+        match = re.search(r'^\s*$', txt)
+        if match:
+            break
+
+        # Check for unbalanced quotes
+        match = re.search(r'^([\'"].*)\s*', txt)
+        if match:
+            chunk = match.group(1)
+            if raise_on_unbalanced:
+                raise Exception("Unbalanced quotes in »%s«." % ( str(text) ) )
+            else:
+                last_chunk += chunk
+                continue
+
+        # Here we should not come to ...
+        raise Exception("Broken split of »%s«: »%s« left" %( str(text), txt))
+
+    if last_chunk != '':
+        chunks.append(last_chunk)
+
+    return chunks
+
+#------------------------------------------------------------------------
+
+def email_valid(address):
+    '''
+    Simple Check for E-Mail addresses
+
+    @param address: the mail address to check
+    @type address:  str
+
+    @return: Validity of the given mil address
+    @rtype:  bool
+    '''
+
+    if address is None:
+        return False
+
+    adr = str(address)
+    if adr is None or adr == '':
+        return False
+
+    pattern = r'^[a-z0-9._%-+]+@[a-z0-9._%-]+.[a-z]{2,6}$'
+    if re.search(pattern, adr, re.IGNORECASE) is None:
+        return False
+
+    return True
+
+#------------------------------------------------------------------------
+
+def human2bytes(value, si_conform = True, use_locale_radix = False, verbose = 0):
+    '''
+    Converts the given human readable byte value (e.g. 5MB, 8.4GiB etc.)
+    with a prefix into an integer/long value (without a prefix).
+    It raises a ValueError on invalid values.
+
+    Available prefixes are:
+        - kB (1000), KB (1024), KiB (1024)
+        - MB (1000*1000), MiB (1024*1024)
+        - GB (1000³), GiB (1024³)
+        - TB (1000^4), TiB (1024^4)
+        - PB (1000^5), PiB (1024^5)
+
+    @param value:            the value to convert
+    @type value:             str
+    @param si_conform:       use factor 1000 instead of 1024 for kB a.s.o.
+    @type si_conform:        bool
+    @param use_locale_radix: use the locale version of radix instead of the
+                             english decimal dot.
+    @type use_locale_radix:  bool
+    @param verbose:          level of verbosity
+    @type verbose:           int
+
+    @return: amount of bytes
+    @rtype:  long
+    '''
+
+    t = gettext.translation('LogRotateCommon', locale_dir, fallback=True)
+    _ = t.lgettext
+
+    if value is None:
+        msg = _("Given value is 'None'.")
+        raise ValueError(msg)
+
+    radix = '.'
+    if use_locale_radix:
+        radix = locale.RADIXCHAR
+    radix = re.escape(radix)
+    if verbose > 5:
+        msg = _("using radix '%s'.") % (radix)
+        logger.debug(msg)
+
+    value_raw = ''
+    prefix = None
+    pattern = r'^\s*\+?(\d+(?:' + radix + r'\d*)?)\s*(\S+)?'
+    match = re.search(pattern, value)
+    if match is not None:
+        value_raw = match.group(1)
+        prefix = match.group(2)
+    else:
+        msg = _("Could not determine bytes in '%s'.") % (value)
+        raise ValueError(msg)
+
+    if use_locale_radix:
+        value_raw = re.sub(radix, '.', value_raw, 1)
+    value_float = float(value_raw)
+    if prefix is None:
+        prefix = ''
+
+    factor_bin = long(1024)
+    factor_si  = long(1000)
+    if not si_conform:
+        factor_si = factor_bin
+
+    factor = long(1)
+
+    if re.search(r'^\s*(?:b(?:yte)?)?\s*$', prefix, re.IGNORECASE):
+        factor = long(1)
+    elif re.search(r'^\s*k(?:[bB](?:[Yy][Tt][Ee])?)?\s*$', prefix):
+        factor = factor_si
+    elif re.search(r'^\s*Ki?(?:[bB](?:[Yy][Tt][Ee])?)?\s*$', prefix):
+        factor = factor_bin
+    elif re.search(r'^\s*M(?:B(?:yte)?)?\s*$', prefix, re.IGNORECASE):
+        factor = (factor_si * factor_si)
+    elif re.search(r'^\s*MiB(?:yte)?\s*$', prefix, re.IGNORECASE):
+        factor = (factor_bin * factor_bin)
+    elif re.search(r'^\s*G(?:B(?:yte)?)?\s*$', prefix, re.IGNORECASE):
+        factor = (factor_si * factor_si * factor_si)
+    elif re.search(r'^\s*GiB(?:yte)?\s*$', prefix, re.IGNORECASE):
+        factor = (factor_bin * factor_bin * factor_bin)
+    elif re.search(r'^\s*T(?:B(?:yte)?)?\s*$', prefix, re.IGNORECASE):
+        factor = (factor_si * factor_si * factor_si * factor_si)
+    elif re.search(r'^\s*TiB(?:yte)?\s*$', prefix, re.IGNORECASE):
+        factor = (factor_bin * factor_bin * factor_bin * factor_bin)
+    elif re.search(r'^\s*P(?:B(?:yte)?)?\s*$', prefix, re.IGNORECASE):
+        factor = (factor_si * factor_si * factor_si * factor_si * factor_si)
+    elif re.search(r'^\s*PiB(?:yte)?\s*$', prefix, re.IGNORECASE):
+        factor = (factor_bin * factor_bin * factor_bin * factor_bin * factor_bin)
+    else:
+        msg = _("Couldn't detect prefix '%s'.") % (prefix)
+        raise ValueError(msg)
+
+    if verbose > 5:
+        msg = _("Found factor %d.") % (factor)
+        logger.debug(msg)
+
+    return long(factor * value_float)
+
+#------------------------------------------------------------------------
+
+def period2days(period, use_locale_radix = False, verbose = 0):
+    '''
+    Converts the given string of the form »5d 8h« in an amount of days.
+    It raises a ValueError on invalid values.
+
+    Special values of period:
+        - now (returns 0)
+        - never (returns float('inf'))
+
+    Valid units for periods are:
+        - »h[ours]«
+        - »d[ays]«   - default, if bare numbers are given
+        - »w[eeks]«  - == 7 days
+        - »m[onths]« - == 30 days
+        - »y[ears]«  - == 365 days
+
+    @param period:           the period to convert
+    @type period:            str
+    @param use_locale_radix: use the locale version of radix instead of the
+                             english decimal dot.
+    @type use_locale_radix:  bool
+    @param verbose:          level of verbosity
+    @type verbose:           int
+
+    @return: amount of days
+    @rtype:  float
+    '''
+
+    t = gettext.translation('LogRotateCommon', locale_dir, fallback=True)
+    _ = t.lgettext
+
+    if period is None:
+        msg = _("Given period is 'None'.")
+        raise ValueError(msg)
+
+    value = str(period).strip().lower()
+    if period == '':
+        msg = _("Given period was empty")
+        raise ValueError(msg)
+
+    if verbose > 4:
+        msg = _("Called with '%s'.") % (period)
+        logger.debug(msg)
+
+    if period == 'now':
+        return float(0)
+
+    # never - returns a positive infinite value
+    if period == 'never':
+        return float('inf')
+
+    days = float(0)
+    radix = '.'
+    if use_locale_radix:
+        radix = locale.RADIXCHAR
+    radix = re.escape(radix)
+    if verbose > 5:
+        msg = _("Using radix '%s'.") % (radix)
+        logger.debug(msg)
+
+    # Search for hours in value
+    pattern = r'(\d+(?:' + radix + r'\d*)?)\s*h(?:ours?)?'
+    if verbose > 5:
+        msg = _("Pattern '%s'.") % (pattern)
+        logger.debug(msg)
+    match = re.search(pattern, value, re.IGNORECASE)
+    if match:
+        hours_str = match.group(1)
+        if use_locale_radix:
+            hours_str = re.sub(radix, '.', hours_str, 1)
+        hours = float(hours_str)
+        days += (hours/24)
+        if verbose > 4:
+            msg = _("Found %f hours.") % (hours)
+            logger.debug(msg)
+        value = re.sub(pattern, '', value, re.IGNORECASE)
+    if verbose > 5:
+        msg = _("Rest after hours: '%s'." % (value))
+        logger.debug(msg)
+
+    # Search for weeks in value
+    pattern = r'(\d+(?:' + radix + r'\d*)?)\s*w(?:eeks?)?'
+    if verbose > 5:
+        msg = _("Pattern '%s'.") % (pattern)
+        logger.debug(msg)
+    match = re.search(pattern, value, re.IGNORECASE)
+    if match:
+        weeks_str = match.group(1)
+        if use_locale_radix:
+            weeks_str = re.sub(radix, '.', weeks_str, 1)
+        weeks = float(weeks_str)
+        days += (weeks*7)
+        if verbose > 4:
+            msg = _("Found %f weeks.") % (weeks)
+            logger.debug(msg)
+        value = re.sub(pattern, '', value, re.IGNORECASE)
+    if verbose > 5:
+        msg = _("Rest after weeks: '%s'." % (value))
+        logger.debug(msg)
+
+    # Search for months in value
+    pattern = r'(\d+(?:' + radix + r'\d*)?)\s*m(?:onths?)?'
+    if verbose > 5:
+        msg = _("Pattern '%s'.") % (pattern)
+        logger.debug(msg)
+    match = re.search(pattern, value, re.IGNORECASE)
+    if match:
+        months_str = match.group(1)
+        if use_locale_radix:
+            months_str = re.sub(radix, '.', months_str, 1)
+        months = float(months_str)
+        days += (months*30)
+        if verbose > 4:
+            msg = _("Found %f months.") % (months)
+            logger.debug(msg)
+        value = re.sub(pattern, '', value, re.IGNORECASE)
+    if verbose > 5:
+        msg = _("Rest after months: '%s'." % (value))
+        logger.debug(msg)
+
+    # Search for years in value
+    pattern = r'(\d+(?:' + radix + r'\d*)?)\s*y(?:ears?)?'
+    if verbose > 5:
+        msg = _("Pattern '%s'.") % (pattern)
+        logger.debug(msg)
+    match = re.search(pattern, value, re.IGNORECASE)
+    if match:
+        years_str = match.group(1)
+        if use_locale_radix:
+            years_str = re.sub(radix, '.', years_str, 1)
+        years = float(years_str)
+        days += (years*365)
+        if verbose > 4:
+            msg = _("Found %f years.") % (years)
+            logger.debug(msg)
+        value = re.sub(pattern, '', value, re.IGNORECASE)
+    if verbose > 5:
+        msg = _("Rest after years: '%s'." % (value))
+        logger.debug(msg)
+
+    # At last search for days in value
+    pattern = r'(\d+(?:' + radix + r'\d*)?)\s*(?:d(?:ays?)?)?'
+    if verbose > 5:
+        msg = _("Pattern '%s'.") % (pattern)
+        logger.debug(msg)
+    match = re.search(pattern, value, re.IGNORECASE)
+    if match:
+        days_str = match.group(1)
+        if use_locale_radix:
+            days_str = re.sub(radix, '.', days_str, 1)
+        days_float = float(days_str)
+        days += days_float
+        if verbose > 4:
+            msg = _("Found %f days.") % (days_float)
+            logger.debug(msg)
+        value = re.sub(pattern, '', value, re.IGNORECASE)
+    if verbose > 5:
+        msg = _("Rest after days: '%s'." % (value))
+        logger.debug(msg)
+
+    # warn, if there is a rest
+    if re.search(r'^\s*$', value) is None:
+        msg = _("Invalid content for a period: '%s'.") % (value)
+        logger.warning(msg)
+
+    if verbose > 4:
+        msg = _("Total %f days found.") % (days)
+        logger.debug(msg)
+
+    return days
+
+#------------------------------------------------------------------------
+
+def get_address_list(address_str, verbose = 0):
+    '''
+    Retrieves all mail addresses from address_str and give them back
+    as a list of tuples.
+
+    @param address_str: the string with all mail addresses as a comma
+                        separated list
+    @type address_str:  str
+    @param verbose:     level of verbosity
+    @type verbose:      int
+
+    @return: list of tuples in the form of the return value
+             of email.utils.parseaddr()
+    @rtype:  list
+
+    '''
+
+    t = gettext.translation('LogRotateCommon', locale_dir, fallback=True)
+    _ = t.lgettext
+    pp = pprint.PrettyPrinter(indent=4)
+
+    addr_list = []
+    addresses = []
+
+    for row in csv.reader([address_str], doublequote=False, skipinitialspace=True):
+        for address in row:
+            addr_list.append(address)
+
+    if verbose > 2:
+        msg = _("Found address entries:") + "\n" + pp.pformat(addr_list)
+        logger.debug(msg)
+
+    for address in addr_list:
+        address = re.sub(r',', ' ', address)
+        address = re.sub(r'\s+', ' ', address)
+        pair = email.utils.parseaddr(address)
+        if verbose > 2:
+            msg = _("Got mail address pair:") + "\n" + pp.pformat(pair)
+            logger.debug(msg)
+        if not email_valid(pair[1]):
+            msg = _("Found invalid mail address '%s'.") % (address)
+            logger.warning(msg)
+            continue
+        addresses.append(pair)
+
+    return addresses
+
+#------------------------------------------------------------------------
+
+def to_unicode_or_bust(obj, encoding='utf-8'):
+    '''
+    Transforms a string, what is not a unicode string, into a unicode string.
+    All other objects are left untouched.
+
+    @param obj: the object to transform
+    @type obj:  object
+    @param encoding: the encoding to use to decode the object
+                     defaults to 'utf-8'
+    @type encoding:  str
+
+    @return: the maybe decoded object
+    @rtype:  object
+    '''
+
+    if isinstance(obj, basestring):
+        if not isinstance(obj, unicode):
+            obj = unicode(obj, encoding)
+
+    return obj
+
+#========================================================================
+
+if __name__ == "__main__":
+    pass
+
+#========================================================================
+
+# vim: fileencoding=utf-8 filetype=python ts=4 expandtab
diff --git a/LogRotate/LogRotateConfig.py b/LogRotate/LogRotateConfig.py
new file mode 100755 (executable)
index 0000000..ba613de
--- /dev/null
@@ -0,0 +1,2038 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# $Id$
+# $URL$
+
+'''
+@author: Frank Brehm
+@contact: frank@brehm-online.com
+@license: GPL3
+@copyright: (c) 2010-2011 by Frank Brehm, Berlin
+@version: 0.0.2
+@summary: module the configuration parsing object for Python logrotating
+'''
+
+import re
+import sys
+import gettext
+import pprint
+import os
+import os.path
+import pwd
+import grp
+import glob
+import logging
+import email.utils
+
+from LogRotateCommon import split_parts, email_valid, period2days, human2bytes
+from LogRotateCommon import get_address_list
+from LogRotateScript import LogRotateScript
+
+revision = '$Revision$'
+revision = re.sub( r'\$', '', revision )
+revision = re.sub( r'Revision: ', r'r', revision )
+revision = re.sub( r'\s*$', '', revision )
+
+__author__    = 'Frank Brehm'
+__copyright__ = '(C) 2011 by Frank Brehm, Berlin'
+__contact__    = 'frank@brehm-online.com'
+__version__    = '0.1.2 ' + revision
+__license__    = 'GPL3'
+
+
+#========================================================================
+# Module variables
+
+# @var: dict with all valid taboo pattern types as keys
+#       and the resulting regex template for the filename as value
+pattern_types = {
+    'ext':    r'%s$',
+    'file':   r'^%s$',
+    'prefix': r'^%s',
+}
+
+script_directives = [
+    'postrotate',
+    'prerotate',
+    'firstaction',
+    'lastaction',
+]
+
+unsupported_options = (
+    'uncompresscmd',
+    'error',
+)
+
+options_with_values = (
+    'mail',
+    'compresscmd',
+    'statusfile',
+    'pidfile',
+    'compressext',
+    'rotate',
+    'maxage',
+    'mailfrom',
+    'smtphost',
+    'smtpport',
+    'smtptls',
+    'smtpuser',
+    'smtppasswd',
+)
+
+boolean_options = (
+    'compress',
+    'copy',
+    'copytruncate',
+    'ifempty',
+    'missingok',
+    'sharedscripts',
+)
+
+integer_options = (
+    'delaycompress',
+    'rotate',
+    'start',
+)
+
+string_options = (
+    'extension',
+    'compresscmd',
+    'compressext',
+    'compressoptions',
+)
+
+global_options = (
+    'statusfile',
+    'pidfile',
+    'mailfrom',
+    'smtphost',
+    'smtpport',
+    'smtptls',
+    'smtpuser',
+    'smtppasswd',
+)
+
+path_options = (
+    'statusfile',
+    'pidfile',
+)
+
+valid_periods = {
+    'hourly':   (1/24),
+    '2hourly':  (1/12),
+    '4hourly':  (1/6),
+    '6hourly':  (1/4),
+    '12hourly': (1/2),
+    'daily':    1,
+    '2daily':   2,
+    'weekly':   7,
+    'monthly':  30,
+    '2monthly': 60,
+    '4monthly': 120,
+    '6monthly': 182,
+    'yearly':   365,
+}
+
+yes_values = (
+    '1',
+    'on',
+    'y',
+    'yes',
+    'true',
+)
+
+no_values = (
+    '0',
+    'off',
+    'n',
+    'no',
+    'false',
+)
+
+
+#========================================================================
+
+class LogrotateConfigurationError(Exception):
+    '''
+    Base class for exceptions in this module.
+    '''
+
+#========================================================================
+
+class LogrotateConfigurationReader(object):
+    '''
+    Class for reading the configuration for Python logrotating
+
+    @author: Frank Brehm
+    @contact: frank@brehm-online.com
+    '''
+
+    #-------------------------------------------------------
+    def __init__( self, config_file,
+                        verbose   = 0,
+                        local_dir = None,
+                        test_mode = False,
+    ):
+        '''
+        Constructor.
+
+        @param config_file: the configuration file to use
+        @type config_file:  str
+        @param verbose:     verbosity (debug) level
+        @type verbose:      int
+        @param local_dir:   The directory, where the i18n-files (*.mo)
+                            are located. If None, then system default
+                            (/usr/share/locale) is used.
+        @type local_dir:    str or None
+        @param test_mode:   test mode - no write actions are made
+        @type test_mode:    bool
+
+        @return: None
+        '''
+
+        self.local_dir = local_dir
+        '''
+        @ivar: The directory, where the i18n-files (*.mo) are located.
+        @type: str or None
+        '''
+
+        self.t = gettext.translation(
+            'LogRotateConfig',
+            local_dir,
+            fallback = True
+        )
+        '''
+        @ivar: a gettext translation object
+        @type: gettext.translation
+        '''
+
+        _ = self.t.lgettext
+
+        self.verbose = verbose
+        '''
+        @ivar: verbosity level (0 - 9)
+        @type: int
+        '''
+
+        self.config_file = config_file
+        '''
+        @ivar: the initial configuration file to use
+        @type: str
+        '''
+
+        self.test_mode = test_mode
+        '''
+        @ivar: test mode - no write actions are made
+        @type: bool
+        '''
+
+        self.logger = logging.getLogger('pylogrotate.config')
+        '''
+        @ivar: logger object
+        @type: logging.getLogger
+        '''
+
+        self.global_option = {}
+        '''
+        @ivar: all global options
+        @type: dict
+        '''
+        self.global_option['smtphost'] = 'localhost'
+
+        #############################################
+        # the rest of instance variables:
+
+        self.search_path = ['/bin', '/usr/bin']
+        '''
+        @ivar: ordered list with directories, where executables are searched
+        @type: list
+        '''
+        self._init_search_path()
+
+        self.shred_command = '/usr/bin/shred'
+        '''
+        @ivar: the system command to shred aged rotated logfiles, if wanted
+        @type: str
+        '''
+        self.check_shred_command()
+
+        self.default = {}
+        '''
+        @ivar: the default values for  directives
+        @type: dict
+        '''
+        self._reset_defaults()
+
+        self.new_log = None
+        '''
+        @ivar: struct with the current log definition
+        @type: dict or None
+        '''
+
+        self.taboo = []
+        '''
+        @ivar: taboo patterns for including files of whole directories
+        @type: list
+        '''
+        self.add_taboo(r'\.rpmnew',        'ext');
+        self.add_taboo(r'\.rpmorig',       'ext');
+        self.add_taboo(r'\.rpmsave',       'ext');
+        self.add_taboo(r',v',              'ext');
+        self.add_taboo(r'\.swp',           'ext');
+        self.add_taboo(r'~',               'ext');
+        self.add_taboo(r'\.',              'prefix');
+        self.add_taboo(r'\.bak',           'ext');
+        self.add_taboo(r'\.old',           'ext');
+        self.add_taboo(r'\.rej',           'ext');
+        self.add_taboo(r'CVS',             'file');
+        self.add_taboo(r'RCS',             'file');
+        self.add_taboo(r'\.disabled',      'ext');
+        self.add_taboo(r'\.dpkg-old',      'ext');
+        self.add_taboo(r'\.dpkg-dist',     'ext');
+        self.add_taboo(r'\.dpkg-new',      'ext');
+        self.add_taboo(r'\.cfsaved',       'ext');
+        self.add_taboo(r'\.ucf-old',       'ext');
+        self.add_taboo(r'\.ucf-dist',      'ext');
+        self.add_taboo(r'\.ucf-new',       'ext');
+        self.add_taboo(r'\.cfsaved',       'ext');
+        self.add_taboo(r'\.rhn-cfg-tmp-*', 'ext');
+
+        self.config_files = {}
+        '''
+        @ivar: dict with all called and included configuration files
+               to avoid double including
+        @type: dict
+        '''
+
+        self.config_was_read = False
+        '''
+        @ivar: flag whether the configuration file was read.
+        @type: bool
+        '''
+
+        self.config = []
+        '''
+        @ivar: the configuration, how it was read from cofiguration file(s)
+        @type: list
+        '''
+
+        self.scripts = {}
+        '''
+        @ivar: dict of LogRotateScript objects
+               with all named scripts found in configuration
+        @type: dict
+        '''
+
+        self.defined_logfiles = {}
+        '''
+        @ivar: all even defined logfiles after globing of file patterns
+        @type: dict
+        '''
+
+        self.logger.debug( _("Logrotate config reader initialised") )
+
+    #------------------------------------------------------------
+    def __str__(self):
+        '''
+        Typecasting function for translating object structure
+        into a string
+
+        @return: structure as string
+        @rtype:  str
+        '''
+
+        pp = pprint.PrettyPrinter(indent=4)
+        structure = self.as_dict()
+        return pp.pformat(structure)
+
+    #-------------------------------------------------------
+    def as_dict(self):
+        '''
+        Transforms the elements of the object into a dict
+
+        @return: structure as dict
+        @rtype:  dict
+        '''
+
+        res = {
+            'config':           self.config,
+            'config_file':      self.config_file,
+            'config_files':     self.config_files,
+            'config_was_read':  self.config_was_read,
+            'default':          self.default,
+            'defined_logfiles': self.defined_logfiles,
+            'global_option':    self.global_option,
+            'logger':           self.logger,
+            'local_dir':        self.local_dir,
+            'new_log':          self.new_log,
+            'search_path':      self.search_path,
+            'scripts':          {},
+            'shred_command':    self.shred_command,
+            't':                self.t,
+            'taboo':            self.taboo,
+            'test_mode':        self.test_mode,
+            'verbose':          self.verbose,
+        }
+
+        for script_name in self.scripts.keys():
+            res['scripts'][script_name] = self.scripts[script_name].as_dict()
+
+        return res
+
+    #------------------------------------------------------------
+    def _reset_defaults(self):
+        '''
+        Resetting self.default to the hard coded values
+        '''
+
+        _ = self.t.lgettext
+
+        if self.verbose > 3:
+            self.logger.debug( _("Resetting default values for directives to hard coded values"))
+
+        self.default = {}
+
+        self.default['compress']      = False
+        self.default['compresscmd']   = 'internal_gzip'
+        self.default['compressext']   = None
+        self.default['compressoptions']  = None
+        self.default['copy']          = False
+        self.default['copytruncate']  = False
+        self.default['create']        = {
+            'enabled': False,
+            'mode':    None,
+            'owner':   None,
+            'group':   None,
+        }
+        self.default['period']        = 7
+        self.default['dateext']       = False
+        self.default['datepattern']   = '%Y-%m-%d'
+        self.default['delaycompress'] = None
+        self.default['extension']     = ""
+        self.default['ifempty']       = True
+        self.default['mailaddress']   = None
+        self.default['mailfirst']     = None
+        self.default['maxage']        = None
+        self.default['missingok']     = False
+        self.default['olddir']        = {
+            'dirname':    '',
+            'dateformat': False,
+            'enabled':    False,
+            'mode':       None,
+            'owner':      None,
+            'group':      None,
+        }
+        self.default['rotate']        = 4
+        self.default['sharedscripts'] = False
+        self.default['shred']         = False
+        self.default['size']          = None
+        self.default['start']         = 0
+
+    #------------------------------------------------------------
+    def add_taboo(self, pattern, pattern_type = 'file'):
+        '''
+        Add a pattern to the list of taboo patterns self.taboo
+        Raises a general exception, if pattern_type is invalid
+
+        @param pattern:      The patten to append to the taboo list
+        @type pattern:       str
+        @param pattern_type: The type of the taboo pattern
+                            ('ext', 'file' or 'prefix')
+        @type pattern_type:  str
+
+        @return: None
+        '''
+
+        _ = self.t.lgettext
+
+        if not pattern_type in pattern_types:
+            raise Exception( _("Invalid taboo pattern type '%s' given") % (pattern_type) )
+
+        pattern = ( pattern_types[pattern_type] % pattern )
+        if self.verbose > 3:
+            self.logger.debug( _("New taboo pattern: '%s'.") % (pattern) )
+
+        self.taboo.append(pattern)
+
+    #------------------------------------------------------------
+    def _init_search_path(self):
+        '''
+        Initialises the internal list of search pathes
+
+        @return: None
+        '''
+
+        _ = self.t.lgettext
+        dir_included = {}
+
+        # Including default path list from environment $PATH
+        def_path = os.environ['PATH']
+        if not def_path:
+            def_path = ''
+        sep = os.pathsep
+        path_list = []
+        for item in def_path.split(sep):
+            if item:
+                if os.path.isdir(item):
+                    real_dir = os.path.abspath(item)
+                    if not real_dir in dir_included:
+                        path_list.append(real_dir)
+                        dir_included[real_dir] = True
+                else:
+                    self.logger.debug( _("'%s' is not a directory") % (item))
+                        
+        # Including default path list from python
+        def_path = os.defpath
+        for item in def_path.split(sep):
+            if item:
+                if os.path.isdir(item):
+                    real_dir = os.path.abspath(item)
+                    if not real_dir in dir_included:
+                        path_list.append(real_dir)
+                        dir_included[real_dir] = True
+                else:
+                    self.logger.debug( _("'%s' is not a directory") % (item))
+
+        # Including own defined directories
+        for item in ('/usr/local/bin', '/sbin', '/usr/sbin', '/usr/local/sbin'):
+            if os.path.isdir(item):
+                real_dir = os.path.abspath(item)
+                if not real_dir in dir_included:
+                    path_list.append(real_dir)
+                    dir_included[real_dir] = True
+            else:
+                self.logger.debug( _("'%s' is not a directory") % (item))
+
+        self.search_path = path_list
+
+    #------------------------------------------------------------
+    def _get_std_search_path(self, include_current = False):
+        '''
+        Returns a list with all search directories from $PATH and some additionally
+        directiories.
+
+        @param include_current: include the current working directory
+                                at the end of the list
+        @type include_current:  bool
+
+        @return: list of search directories
+        @rtype:  list
+        '''
+
+        #_ = self.t.lgettext
+
+        path_list = self.search_path
+        if include_current:
+            item = os.getcwd()
+            real_dir = os.path.abspath(item)
+            path_list.append(real_dir)
+
+        return path_list
+
+    #------------------------------------------------------------
+    def check_shred_command(self):
+        '''
+        Checks the availability of a check command. Sets self.shred_command to
+        this system command or to None, if not found (including a warning).
+        '''
+
+        _ = self.t.lgettext
+        path_list = self._get_std_search_path(True)
+
+        cmd = None
+        found = False
+        for search_dir in path_list:
+            if os.path.isdir(search_dir):
+                cmd = os.path.join(search_dir, 'shred')
+                if not os.path.isfile(cmd):
+                    continue
+                if os.access(cmd, os.X_OK):
+                    found = True
+                    break
+            else:
+                self.logger.debug( _("Search path '%s' doesn't exists or is not a directory") % (search_dir))
+
+        if found:
+            self.logger.debug( _("Shred command found: '%s'") %(cmd) )
+            self.shred_command = cmd
+            return True
+        else:
+            self.logger.warning( _("Shred command not found, shred disabled") )
+            self.shred_command = None
+            return False
+
+    #------------------------------------------------------------
+    def check_compress_command(self, command):
+        '''
+        Checks the availability of the given compress command.
+
+        'internal_zip, 'internal_gzip' and 'internal_bzip2' are accepted as
+        valid compress commands for compressing with the appropriate python modules.
+
+        @param command: command to validate (absolute or relative for
+                        searching in standard search path)
+        @type command:  str
+
+        @return: absolute path of the compress command, 'internal_gzip',
+                 'internal_bzip2' or None if not found or invalid
+        @rtype:  str or None
+        '''
+
+        _ = self.t.lgettext
+        path_list = self._get_std_search_path(True)
+
+        match = re.search(r'^\s*internal[\-_\s]?zip\s*', command, re.IGNORECASE)
+        if match:
+            return 'internal_zip'
+
+        match = re.search(r'^\s*internal[\-_\s]?gzip\s*', command, re.IGNORECASE)
+        if match:
+            return 'internal_gzip'
+
+        match = re.search(r'^\s*internal[\-_\s]?bzip2\s*', command, re.IGNORECASE)
+        if match:
+            return 'internal_bzip2'
+
+        if os.path.isabs(command):
+            if os.access(command, os.X_OK):
+                return os.path.abspath(command)
+            else:
+                return None
+
+        cmd = None
+        found = False
+        for search_dir in path_list:
+            if os.path.isdir(search_dir):
+                cmd = os.path.join(search_dir, command)
+                if not os.path.isfile(cmd):
+                    continue
+                if os.access(cmd, os.X_OK):
+                    found = True
+                    break
+            else:
+                self.logger.debug( _("Search path '%s' doesn't exists or is not a directory") % (search_dir))
+
+        if found:
+            return os.path.abspath(cmd)
+        else:
+            return None
+
+    #------------------------------------------------------------
+    def get_config(self):
+        '''
+        Returns the configuration, how it was read from configuration file(s)
+
+        @return: configuration
+        @rtype:  dict or None
+        '''
+
+        if not self._read_main_configfile():
+            return None
+
+        return self.config
+
+    #------------------------------------------------------------
+    def get_scripts(self):
+        '''
+        Returns the scriptlist, how it was read from configuration file(s)
+
+        @return: list of scripts
+        @rtype:  list
+        '''
+
+        if not self._read_main_configfile():
+            return None
+
+        return self.scripts
+
+    #------------------------------------------------------------
+    def _read_main_configfile(self):
+        '''
+        Reads the main configuration file (self.config_file).
+
+        @return: success of reading
+        @rtype:  bool
+        '''
+
+        _ = self.t.lgettext
+
+        if self.config_was_read:
+            return True
+
+        if not os.path.exists(self.config_file):
+            raise LogrotateConfigurationError( _("File '%s' doesn't exists.") % (self.config_file))
+
+        self.config_file = os.path.abspath(self.config_file)
+
+        if not self._read(self.config_file):
+            return None
+
+        self.config_was_read = True
+        return True
+
+    #------------------------------------------------------------
+    def _read(self, configfile):
+        '''
+        Reads the configuration from given configuration file and all
+        included files.
+
+        @param configfile: the configfile to read
+        @type configfile:  str
+        '''
+
+        _ = self.t.lgettext
+        pp = pprint.PrettyPrinter(indent=4)
+        self.logger.debug( _("Try reading configuration from '%s' ...") % (configfile) )
+
+        if not os.path.exists(configfile):
+            raise LogrotateConfigurationError( _("File '%s' doesn't exists.") % (configfile))
+
+        if not os.path.isfile(configfile):
+            raise LogrotateConfigurationError( _("'%s' is not a regular file.") % (configfile))
+
+        self.config_files[configfile] = True
+
+        self.logger.info( _("Reading configuration from '%s' ...") % (configfile) )
+
+        cfile = None
+        try:
+            cfile = open(configfile, 'Ur')
+        except IOError, e:
+            raise LogrotateConfigurationError( ( _("Could not read configuration file '%s'") % (configfile) ) + ': ' + str(e))
+        lines = cfile.readlines()
+        cfile.close()
+
+        # defaults for the big loop
+        linenr          = 0
+        in_fd           = False
+        in_script       = False
+        in_logfile_list = False
+        lastrow         = ''
+        newscript       = ''
+
+        # inspect every line of configuration file
+        for line in lines:
+
+            linenr += 1
+            line = line.strip()
+
+            # Perform a backslash at the end of the line
+            line = lastrow + line
+            match = re.search(r'\\$', line)
+            if match:
+                line = re.sub(r'\\$', '', line)
+                lastrow = line
+                continue
+            lastrow = ''
+
+            # delete comments
+            line = re.sub(r'^#.*', '', line)
+            if line == '':
+                continue
+
+            # perform script content
+            if in_script:
+                match = re.search(r'^endscript$', line)
+                if match:
+                    in_script = False
+                    continue
+                #self.scripts[newscript]['cmd'].append(line)
+                self.scripts[newscript].add_cmd(line)
+                continue
+
+            # start of a logfile definition
+            if line == '{':
+
+                if self.verbose > 3:
+                    self.logger.debug( ( _("Starting a logfile definition (file '%(file)s', line %(line)s)") 
+                                        % {'file': configfile, 'line': linenr}))
+
+                self._start_logfile_definition( 
+                    line            = line,
+                    filename        = configfile,
+                    in_fd           = in_fd,
+                    in_logfile_list = in_logfile_list,
+                    linenr          = linenr
+                )
+                in_fd = True
+                in_logfile_list = False
+                continue
+
+            # start of a logfile pattern
+            match = re.search(r'^[\'"]', line)
+            if match or os.path.isabs(line):
+
+                if in_fd:
+                    raise LogrotateConfigurationError(
+                        ( _("Logfile pattern definition not allowed inside a logfile definition (file '%(file)s', line %(line)s)")
+                            % {'file': configfile, 'line': linenr})
+                    )
+                do_start_logfile_definition = False
+
+                # look, whether a start of a logfile definition is necessary
+                match_bracket = re.search(r'\s*{\s*$', line)
+                if match_bracket:
+                    line = re.sub(r'\s*{\s*$', '', line)
+                    do_start_logfile_definition = True
+                if not in_logfile_list:
+                    self._start_new_log(configfile, linenr)
+                in_logfile_list = True
+
+                parts = split_parts(line)
+                if self.verbose > 3:
+                    self.logger.debug(
+                        ( _("Split into parts of: '%s'") % (line))
+                        + ":\n" + pp.pformat(parts)
+                    )
+
+                for pattern in parts:
+                    if pattern == '{':
+                        raise LogrotateConfigurationError(
+                            ( _("Syntax error: open curly bracket inside a logfile pattern definition (file '%(file)s', line %(line)s)")
+                                % {'file': configfile, 'line': linenr})
+                        )
+                    self.new_log['file_patterns'].append(pattern)
+
+                # start of a logfile definition, if necessary
+                if do_start_logfile_definition:
+                    self._start_logfile_definition( 
+                        line            = line,
+                        filename        = configfile,
+                        in_fd           = in_fd,
+                        in_logfile_list = in_logfile_list,
+                        linenr          = linenr
+                    )
+                    in_fd = True
+                    in_logfile_list = False
+
+                continue
+
+            # end of a logfile definition
+            match = re.search(r'^}(.*)', line)
+            if match:
+                if not in_fd:
+                    raise LogrotateConfigurationError(
+                        ( _("Syntax error: unbalanced closing curly bracket found (file '%(file)s', line %(line)s)")
+                            % {'file': configfile, 'line': linenr})
+                    )
+                rest = match.group(1)
+                if self.verbose > 2:
+                    self.logger.debug( ( _("End of a logfile definition (file '%(file)s', line %(line)s)") % {'file': configfile, 'line': linenr}))
+                if rest:
+                    self.logger.warning(
+                        ( _("Needless content found at the end of a logfile definition found: '%(rest)s' (file '%(file)s', line %(line)s)")
+                            % { 'rest': str(rest), 'file': configfile, 'line': linenr})
+                    )
+                # set a compress ext, if Compress is True
+                if self.new_log['compress']:
+                    if not self.new_log['compressext']:
+                        if self.new_log['compresscmd'] == 'internal_gzip':
+                            self.new_log['compressext'] = '.gz'
+                        elif self.new_log['compresscmd'] == 'internal_zip':
+                            self.new_log['compressext'] = '.zip'
+                        elif self.new_log['compresscmd'] == 'internal_bzip2':
+                            self.new_log['compressext'] = '.bz2'
+                        else:
+                            msg = _("No extension for compressed logfiles given " +
+                                    "(File of definition: '%(file)s', start definition: %(rownum)d).") \
+                                  % { 'file': self.new_log['configfile'], 'rownum': self.new_log['configrow']}
+                            raise LogrotateConfigurationError(msg)
+                # set ifempty => True, if a minsize was given
+                if self.new_log['size']:
+                    self.new_log['ifempty'] = False
+                found_files = self._assign_logfiles()
+                if self.verbose > 3:
+                    self.logger.debug( ( _("New logfile definition:") + "\n" + pp.pformat(self.new_log)))
+                if found_files > 0:
+                    if self.new_log['postrotate']:
+                        script = self.new_log['postrotate']
+                        if self.scripts[script]:
+                            self.scripts[script].post_files += found_files
+                        else:
+                            msg = _("Postrotate script '%s' not found.") % (script)
+                            self.logger.error(msg)
+                    if self.new_log['lastaction']:
+                        script = self.new_log['lastaction']
+                        if self.scripts[script]:
+                            self.scripts[script].last_files += found_files
+                        else:
+                            msg = _("Lastaction script '%s' not found.") % (script)
+                            self.logger.error(msg)
+                    self.config.append(self.new_log)
+                in_fd = False
+                in_logfile_list = False
+
+                continue
+
+            # performing includes
+            match = re.search(r'^include(?:\s+(.*))?$', line, re.IGNORECASE)
+            if match:
+                rest = match.group(1)
+                if in_fd or in_logfile_list:
+                    self.logger.warning(
+                        ( _("Syntax error: include may not appear inside of log file definition (file '%(file)s', line %(line)s)")
+                            % {'file': configfile, 'line': linenr})
+                    )
+                    continue
+                self._do_include(line, rest, configfile, linenr)
+                continue
+
+            # start of a (regular) script definition
+            pattern = r'^(' + '|'.join(script_directives) + r')(\s+.*)?$'
+            match = re.search(pattern, line, re.IGNORECASE)
+            if match:
+                script_type = match.group(1).lower()
+                script_name = None
+                if match.group(2) is not None:
+                    values      = split_parts(match.group(2))
+                    if values[0]:
+                        script_name = values[0]
+                if self.verbose > 3:
+                    self.logger.debug(
+                        ( _("Found start of a regular script definition: type: '%(type)s', name: '%(name)s' (file '%(file)s', line %(line)s)")
+                            % {'type': script_type, 'name': script_name, 'file': configfile, 'line': linenr})
+                    )
+                newscript = self._start_log_script_definition(
+                    script_type = script_type,
+                    script_name = script_name,
+                    line        = line,
+                    filename    = configfile,
+                    in_fd       = in_fd,
+                    linenr      = linenr,
+                )
+                if newscript:
+                    in_script = True
+                if self.verbose > 3:
+                    self.logger.debug( ( _("New log script name: '%s'.") % (newscript) ))
+                continue
+
+            # start of an explicite external script definition
+            match = re.search(r'^script(\s+.*)?$', line, re.IGNORECASE)
+            if match:
+                if self.verbose > 3:
+                    self.logger.debug( ( _("Found start of a external script definition. (file '%(file)s', line %(line)s)")
+                                        % {'file': configfile, 'line': linenr})
+                    )
+                rest = match.group(1)
+                if in_fd or in_logfile_list:
+                    self.logger.warning(
+                        ( _("Syntax error: external script definition may not appear inside of a log file definition (file '%(file)s', line %(line)s)")
+                            % {'file': configfile, 'line': linenr})
+                    )
+                    continue
+                newscript = self._ext_script_definition(
+                    line, rest, configfile, linenr
+                )
+                if newscript:
+                    in_script = True
+                if self.verbose > 3:
+                    self.logger.debug( ( _("New external script name: '%s'.") % (newscript) ))
+                continue
+
+            # all other options
+            if not self._option(line, in_fd, configfile, linenr):
+                self.logger.warning( ( _("Syntax error in file '%(file)s', line %(line)s")
+                    % {'file': configfile, 'line': linenr})
+                )
+
+        return True
+
+    #------------------------------------------------------------
+    def _option(self, line, in_fd, filename, linenr):
+        '''
+        Checks the given line as a logrotate option and assign this
+        option on success to the default options or in the current
+        logfile directive
+
+        @param line:     line of current config file
+        @type line:      str
+        @param in_fd:    parsing inside a logfile definition
+        @type in_fd:     bool
+        @param filename: current configuration file
+        @type filename:  str
+        @param linenr:   current line number of configuration file
+        @type linenr:    int
+
+        @return: success of parsing this option
+        @rtype:  bool
+        '''
+
+        _ = self.t.lgettext
+        if self.verbose > 4:
+            self.logger.debug(
+                ( _("Checking line '%(line)s' for a logrotate option. (file '%(file)s', line %(lnr)s)")
+                    % {'line': line, 'file': filename, 'lnr': linenr})
+            )
+
+        # where to insert the option?
+        directive = self.default
+        directive_str = 'default'
+        if in_fd:
+            directive = self.new_log
+            directive_str = 'new_log'
+
+        # extract option from line
+        option = None
+        val    = None
+        match = re.search(r'^(\S+)\s*(.*)', line)
+        if match:
+            option = match.group(1).lower()
+            val    = match.group(2)
+        else:
+            self.logger.warning( ( _("Could not detect option in line '%s'.") % (line)))
+            return False
+        val = re.sub(r'^\s+$', '', val)
+        if self.verbose > 4:
+            msg = _("Found option '%(opt)s' with value '%(val)s'.") \
+                    % {'opt': option, 'val': val}
+            self.logger.debug(msg)
+
+        # Check for unsupported options
+        pattern = r'^(' + '|'.join(unsupported_options) + r')$'
+        match = re.search(pattern, option, re.IGNORECASE)
+        if match:
+            self.logger.info(
+                ( _("Unsupported option '%(option)s'. (file '%(file)s', line %(lnr)s)")
+                    % {'option': match.group(1).lower(), 'file': filename, 'lnr': linenr})
+            )
+            return True
+
+        # Check for boolean option
+        pattern = r'^(not?)?(' + '|'.join(boolean_options) + r')$'
+        match = re.search(pattern, option, re.IGNORECASE)
+        if match:
+            negated = match.group(1)
+            key     = match.group(2).lower()
+            if val:
+                self.logger.warning(
+                    ( _("Found value '%(value)s' behind the boolean option '%(option)s', ignoring. (file '%(file)s', line %(lnr)s)")
+                        % {'value': val, 'option': option, 'file': filename, 'lnr': linenr})
+                )
+            if negated is None:
+                option_value = True
+            else:
+                option_value = False
+            if self.verbose > 4:
+                self.logger.debug(
+                    ( _("Setting boolean option '%(option)s' in '%(directive)s' to '%(value)s'. (file '%(file)s', line %(lnr)s)")
+                        % {'option': key, 'directive': directive_str, 'value': str(option_value), 'file': filename, 'lnr': linenr})
+                )
+            directive[key] = option_value
+            if key == 'copy' and option_value:
+                if directive['copytruncate']:
+                    msg = _("Option 'copy' disables option 'copytruncate'. (file '%(file)s', line %(lnr)s)") \
+                            % {'file': filename, 'lnr': linenr}
+                    self.logger.warning(msg)
+                    directive['copytruncate'] = False
+                if directive['create']['enabled']:
+                    msg = _("Option 'copy' disables option 'create'. (file '%(file)s', line %(lnr)s)") \
+                            % {'file': filename, 'lnr': linenr}
+                    self.logger.warning(msg)
+                    directive['create']['enabled'] = False
+            elif key == 'copytruncate' and option_value:
+                if directive['copy']:
+                    msg = _("Option 'copytruncate' disables option 'copy'. (file '%(file)s', line %(lnr)s)") \
+                            % {'file': filename, 'lnr': linenr}
+                    self.logger.warning(msg)
+                    directive['copy'] = False
+                if directive['create']['enabled']:
+                    msg = _("Option 'copytruncate' disables option 'create'. (file '%(file)s', line %(lnr)s)") \
+                            % {'file': filename, 'lnr': linenr}
+                    self.logger.warning(msg)
+                    directive['create']['enabled'] = False
+            return True
+
+        # Check for integer options
+        pattern = r'^(not?)?(' + '|'.join(integer_options) + r')$'
+        match = re.search(pattern, option, re.IGNORECASE)
+        if match:
+            negated = match.group(1)
+            key     = match.group(2).lower()
+            option_value = 0
+            if negated is None:
+                if key in options_with_values:
+                    if val is None or val == '':
+                        self.logger.warning( ( _("Option '%s' without a necessary value.") % (key)))
+                        return False
+                else:
+                    if val is None or val == '':
+                        val = '1'
+                try:
+                    option_value = long(val)
+                except ValueError, e:
+                    self.logger.warning(
+                        ( _("Option '%(option)s' has no integer value: %(msg)s.")
+                            % {'option': key, 'msg': str(e)})
+                    )
+                    return False
+            if option_value < 0:
+                self.logger.warning(
+                    ( _("Negative value %(value)s for option '%(option)s' is not allowed.")
+                        % {'value': str(option_value), 'option': key})
+                )
+                return False
+            if self.verbose > 4:
+                self.logger.debug(
+                    ( _("Setting integer option '%(option)s' in '%(directive)s' to '%(value)s'. (file '%(file)s', line %(lnr)s)")
+                        % {'option': key, 'directive': directive_str, 'value': str(option_value), 'file': filename, 'lnr': linenr})
+                )
+            directive[key] = option_value
+            return True
+
+        # Check for mail address
+        match = re.search(r'^(not?)?mail$', option, re.IGNORECASE)
+        if match:
+            negated = match.group(1)
+            if negated:
+                directive['mailaddress'] = None
+                if val is not None and val != '':
+                    self.logger.warning(
+                        ( _("Senseless option value '%(value)s' after '%(option)s'.")
+                            % {'value': val, 'option': option.lower()})
+                    )
+                    return False
+                return True
+            address_list = get_address_list(val, self.verbose)
+            if len(address_list):
+                directive['mailaddress'] = address_list
+            else:
+                directive['mailaddress'] = None
+            if self.verbose > 4:
+                pp = pprint.PrettyPrinter(indent=4)
+                msg = _("Setting mail address in '%(directive)s' to '%(addr)s'. (file '%(file)s', line %(lnr)s)") \
+                    % {
+                        'directive': directive_str,
+                        'addr': pp.pformat(directive['mailaddress']),
+                        'file': filename,
+                        'lnr': linenr,
+                    }
+                self.logger.debug(msg)
+            return True
+
+        # Check for mailfirst/maillast
+        match = re.search(r'^mail(first|last)$', option, re.IGNORECASE)
+        if match:
+            when = match.group(1).lower()
+            option_value = False
+            if when == 'first':
+                option_value = True
+            directive['mailfirst'] = option_value
+            if self.verbose > 4:
+                self.logger.debug(
+                    ( _("Setting mailfirst in '%(directive)s' to '%(value)s'. (file '%(file)s', line %(lnr)s)")
+                        % {'directive': directive_str, 'value': str(option_value), 'file': filename, 'lnr': linenr})
+                )
+            if val is not None and val != '':
+                self.logger.warning(
+                    ( _("Senseless option value '%(value)s' after '%(option)s'.")
+                        % {'value': val, 'option': option.lower()})
+                )
+                return False
+            return True
+
+        # Check for string options
+        pattern = r'^(' + '|'.join(string_options) + r')$'
+        match = re.search(pattern, option, re.IGNORECASE)
+        if match:
+            key = match.group(1).lower()
+            if key in options_with_values:
+                if self.verbose > 5:
+                    self.logger.debug( ( _("Option '%s' must have a value.") %(key)))
+                if (val is None) or (val == ''):
+                    self.logger.warning( ( _("Option '%s' without a value") %(key)))
+                    return False
+            if key == 'compresscmd':
+                prog = self.check_compress_command(val)
+                if prog is None:
+                    self.logger.warning( ( _("Compress command '%s' not found.") %(val)))
+                    return False
+                val = prog
+            if key == 'compressoptions' and val is None:
+                val = ''
+            directive[key] = val
+            return True
+
+        # Check for global options
+        pattern = r'^(' + '|'.join(global_options) + r')$'
+        match = re.search(pattern, option, re.IGNORECASE)
+        if match:
+            key = match.group(1).lower()
+            if in_fd:
+                self.logger.warning( ( _("Option '%s' not allowed inside a logfile directive.") %(key)))
+                return False
+            if key in options_with_values:
+                if self.verbose > 5:
+                    self.logger.debug( ( _("Option '%s' must have a value.") %(key)))
+                if (val is None) or (re.search(r'^\s*$', val) is not None):
+                    self.logger.warning( ( _("Option '%s' without a value") %(key)))
+                    return False
+            if key in path_options:
+                if not os.path.abspath(val):
+                    self.logger.warning(
+                        ( _("Value '%(value)s' for option '%(option)s' is not an absolute path.")
+                            % {'value': val, 'option': key} )
+                    )
+                    return False
+            if key == 'mailfrom':
+               pair = email.utils.parseaddr(val)
+               if not email_valid(pair[1]):
+                    msg = _("Invalid mail address for 'mailfrom' given: '%s'.") % (val)
+                    self.logger.warning(msg)
+                    return False
+               val = pair
+            elif key == 'smtpport':
+                port = 25
+                try:
+                    port = int(val)
+                except ValueError, e:
+                    msg = _("Invalid SMTP port '%s' given.") % (val)
+                    self.logger.warning(msg)
+                    return False
+                if port < 1 or port >= 2**15:
+                    msg = _("Invalid SMTP port '%s' given.") % (val)
+                    self.logger.warning(msg)
+                    return False
+                val = port
+            elif key == 'smtptls':
+                use_tls = False
+                match = re.search(r'^\s*(?:0+|false|no?)\s*$', val, re.IGNORECASE)
+                if not match:
+                    match = re.search(r'^\s*(?:1|true|y(?:es)?)\s*$', val, re.IGNORECASE)
+                    if match:
+                        use_tls = True
+                    else:
+                        use_tls = bool(val)
+                val = use_tls
+            if self.verbose > 4:
+                self.logger.debug(
+                    ( _("Setting global option '%(option)s' to '%(value)s'. (file '%(file)s', line %(lnr)s)")
+                        % {'option': key, 'directive': directive_str, 'value': str(val), 'file': filename, 'lnr': linenr})
+                )
+            self.global_option[key] = val
+            return True
+
+        # Check for rotation period
+        pattern = r'^(' + '|'.join(valid_periods.keys()) + r'|period)$'
+        match = re.search(pattern, option, re.IGNORECASE)
+        if match:
+            key = match.group(1).lower()
+            if self.verbose > 4:
+                self.logger.debug(
+                    ( _("Checking 'period': key '%(key)s', value '%(value)s'. (file '%(file)s', line %(lnr)s)")
+                        % {'key': key, 'value': str(val), 'file': filename, 'lnr': linenr})
+                )
+            option_value = 1
+            if key in valid_periods:
+                if (val is not None) and (re.search(r'^\s*$', val) is None):
+                    self.logger.warning(
+                        ( _("Option '%(option)s' may not have a value ('%(value)s'). (file '%(file)s', line %(lnr)s)")
+                            % {'option': key, 'value': val, 'file': filename, 'lnr': linenr})
+                    )
+                option_value = valid_periods[key]
+            else:
+                try:
+                    option_value = period2days(val, verbose = self.verbose)
+                except ValueError, e:
+                    self.logger.warning( ( _("Invalid period definition: '%s'") %(val) ))
+                    return False
+            if self.verbose > 4:
+                self.logger.debug(
+                    ( _("Setting 'period' in '%(directive)s' to %(days)f days. (file '%(file)s', line %(lnr)s)")
+                        % {'directive': directive_str, 'days': option_value, 'file': filename, 'lnr': linenr})
+                )
+            directive['period'] = option_value
+            return True
+
+        # get maximum age of old rotated log files
+        match = re.search(r'^(not?)?maxage$', option, re.IGNORECASE)
+        if match:
+            negated = False
+            if match.group(1) is not None:
+                negated = True
+            if (val is None) or re.search(r'^\s*$', val) is not None:
+                negated = True
+            option_value = 0
+            if not negated:
+                try:
+                    option_value = period2days(val, verbose = self.verbose)
+                except ValueError, e:
+                    self.logger.warning( ( _("Invalid maxage definition: '%s'") %(val) ))
+                    return False
+            if self.verbose > 4:
+                self.logger.debug(
+                    ( _("Setting 'maxage' in '%(directive)s' to %(days)f days. (file '%(file)s', line %(lnr)s)")
+                        % {'directive': directive_str, 'days': option_value, 'file': filename, 'lnr': linenr})
+                )
+            directive['maxage'] = option_value
+            return True
+
+        # Setting date extension of rotated log files
+        match = re.search(r'^(no)?dateext$', option, re.IGNORECASE)
+        if match:
+
+            negated = False
+            if match.group(1) is not None:
+                negated = True
+            use_dateext = False
+            dateext = None
+
+            if self.verbose > 4:
+                self.logger.debug(
+                    ( _("Checking 'dateext', negated: '%(negated)s'. (file '%(file)s', line %(lnr)s)")
+                        % {'negated': str(negated), 'file': filename, 'lnr': linenr})
+                )
+            values = []
+            if val is not None:
+                values = split_parts(val) 
+
+            if not negated:
+                first_val = ''
+                if len(values) > 0:
+                    first_val = values[0].lower()
+                option_value = first_val
+                if first_val is None or \
+                        re.search(r'^\s*$', first_val) is not None:
+                    option_value = 'true'
+                if self.verbose > 5:
+                    self.logger.debug(
+                        ( _("'dateext': first_val: '%(first_val)s', option_value: '%(value)s'. (file '%(file)s', line %(lnr)s)")
+                            % {'first_val': first_val, 'value': option_value, 'file': filename, 'lnr': linenr})
+                    )
+                if option_value in yes_values:
+                    use_dateext = True
+                elif option_value in no_values:
+                    use_dateext = False
+                else:
+                    use_dateext = True
+                    dateext = val
+
+            if self.verbose > 4:
+                self.logger.debug(
+                    ( _("Setting 'dateext' in '%(directive)s' to %(ext)s. (file '%(file)s', line %(lnr)s)")
+                        % {'directive': directive_str, 'ext': str(use_dateext), 'file': filename, 'lnr': linenr})
+                )
+            directive['dateext'] = use_dateext
+
+            if dateext is not None:
+                if self.verbose > 4:
+                    self.logger.debug(
+                        ( _("Setting 'datepattern' in '%(directive)s' to '%(pattern)s'. (file '%(file)s', line %(lnr)s)")
+                            % {'directive': directive_str, 'pattern': dateext, 'file': filename, 'lnr': linenr})
+                    )
+                directive['datepattern'] = dateext
+
+            return True
+
+        # Checking for create options ...
+        match = re.search(r'(not?)?create$', option, re.IGNORECASE)
+        if match:
+
+            negated = False
+            if match.group(1) is not None:
+                negated = True
+
+            if self.verbose > 5:
+                self.logger.debug(
+                    ( _("Checking for 'create' ... (file '%(file)s', line %(lnr)s)")
+                        % {'file': filename, 'lnr': linenr})
+                )
+
+            if negated:
+                if self.verbose > 4:
+                    self.logger.debug(
+                        ( _("Removing 'create'. (file '%(file)s', line %(lnr)s)")
+                            % {'file': filename, 'lnr': linenr})
+                    )
+                directive['create']['enabled'] = False
+                return True
+
+            if directive['copy']:
+                msg = _("Option 'copy' was set, so option 'create' has no effect. (file '%(file)s', line %(lnr)s)") \
+                        % {'file': filename, 'lnr': linenr}
+                self.logger.warning(msg)
+                directive['create']['enabled'] = False
+                return True
+
+            if directive['copytruncate']:
+                msg = _("Option 'copytruncate' was set, so option 'create' has no effect. (file '%(file)s', line %(lnr)s)") \
+                        % {'file': filename, 'lnr': linenr}
+                self.logger.warning(msg)
+                directive['create']['enabled'] = False
+                return True
+
+            values = []
+            if val is not None:
+                values = split_parts(val)
+
+            directive['create']['enabled'] = True
+
+            mode  = None
+            owner = None
+            group = None
+
+            # Check for create mode
+            if len(values) > 0:
+                if self.verbose > 5:
+                    self.logger.debug(
+                        ( _("Trying to determine create mode '%(mode)s'... (file '%(file)s', line %(lnr)s)")
+                            % {'mode': values[0], 'file': filename, 'lnr': linenr})
+                    )
+                mode_octal = values[0]
+                if re.search(r'^0', mode_octal) is None:
+                    mode_octal = '0' + mode_octal
+                try:
+                    mode = int(mode_octal, 8)
+                except ValueError:
+                    self.logger.warning( ( _("Invalid create mode '%s'.") %(values[1])))
+                    return False
+
+            # Check for Owner (user, uid)
+            if len(values) > 1:
+                owner_raw = values[1]
+                if self.verbose > 5:
+                    self.logger.debug(
+                        ( _("Trying to determine create owner '%(owner)s'... (file '%(file)s', line %(lnr)s)")
+                            % {'owner': owner_raw, 'file': filename, 'lnr': linenr})
+                    )
+                if re.search(r'^[1-9]\d*$', owner_raw) is not None:
+                    owner = int(owner_raw)
+                else:
+                    try:
+                        owner = pwd.getpwnam(owner_raw)[2]
+                    except KeyError:
+                        self.logger.warning( ( _("Invalid owner '%s' in 'create'.") %(owner_raw)))
+                        return False
+
+            # Check for Group (gid)
+            if len(values) > 2:
+                group_raw = values[2]
+                if self.verbose > 5:
+                    self.logger.debug(
+                        ( _("Trying to determine create group '%(group)s'... (file '%(file)s', line %(lnr)s)")
+                            % {'group': group_raw, 'file': filename, 'lnr': linenr})
+                    )
+                if re.search(r'^[1-9]\d*$', group_raw) is not None:
+                    group = int(group_raw)
+                else:
+                    try:
+                        group = grp.getgrnam(group_raw)[2]
+                    except KeyError:
+                        self.logger.warning( ( _("Invalid group '%s' in 'create'.") %(group_raw)))
+                        return False
+
+            # Give values back ...
+            directive['create']['mode']  = mode
+            directive['create']['owner'] = owner
+            directive['create']['group'] = group
+            return True
+
+        # checking for olddir ...
+        match = re.search(r'^(not?)?olddir$', option, re.IGNORECASE)
+        if match:
+
+            negated = False
+            if match.group(1) is not None:
+                negated = True
+
+            if self.verbose > 5:
+                self.logger.debug(
+                    ( _("Checking for 'olddir' ... (file '%(file)s', line %(lnr)s)")
+                        % {'file': filename, 'lnr': linenr})
+                )
+
+            if negated:
+                if self.verbose > 4:
+                    self.logger.debug(
+                        ( _("Removing 'olddir'. (file '%(file)s', line %(lnr)s)")
+                            % {'file': filename, 'lnr': linenr})
+                    )
+                directive['olddir']['enabled'] = False
+                return True
+
+            values = []
+            if val is not None:
+                values = split_parts(val)
+
+            # Check for dirname of olddir
+            if len(values) < 1 or values[0] is None or re.search(r'^\s*$', values[0]) is not None:
+                self.logger.warning( ( _("Option 'olddir' without a value given.")))
+                return False
+            directive['olddir']['dirname'] = values[0]
+            directive['olddir']['enabled'] = True
+
+            mode  = None
+            owner = None
+            group = None
+
+            # Check for create mode of olddir
+            if len(values) > 1:
+                if self.verbose > 5:
+                    self.logger.debug(
+                        ( _("Trying to determine olddir create mode '%(mode)s' ... (file '%(file)s', line %(lnr)s)")
+                            % {'mode': values[1], 'file': filename, 'lnr': linenr})
+                    )
+                mode_octal = values[1]
+                if re.search(r'^0', mode_octal) is None:
+                    mode_octal = '0' + mode_octal
+                try:
+                    mode = int(mode_octal, 8)
+                except ValueError:
+                    self.logger.warning( ( _("Invalid create mode '%s' in 'olddir'.") %(values[1])))
+                    return False
+
+            # Check for Owner (user, uid)
+            if len(values) > 2:
+                owner_raw = values[2]
+                if self.verbose > 5:
+                    self.logger.debug(
+                        ( _("Trying to determine olddir owner '%(owner)s' ... (file '%(file)s', line %(lnr)s)")
+                            % {'owner': owner_raw, 'file': filename, 'lnr': linenr})
+                    )
+                if re.search(r'^[1-9]\d*$', owner_raw) is not None:
+                    owner = int(owner_raw)
+                else:
+                    try:
+                        owner = pwd.getpwnam(owner_raw)[2]
+                    except KeyError:
+                        self.logger.warning( ( _("Invalid owner '%s' in 'olddir'.") %(owner_raw)))
+                        return False
+
+            # Check for Group (gid)
+            if len(values) > 3:
+                group_raw = values[3]
+                if self.verbose > 5:
+                    self.logger.debug(
+                        ( _("Trying to determine olddir group '%(group)s' ... (file '%(file)s', line %(lnr)s)")
+                            % {'group': group_raw, 'file': filename, 'lnr': linenr})
+                    )
+                if re.search(r'^[1-9]\d*$', group_raw) is not None:
+                    group = int(group_raw)
+                else:
+                    try:
+                        group = grp.getgrnam(group_raw)[2]
+                    except KeyError:
+                        self.logger.warning( ( _("Invalid group '%s' in 'olddir'.") %(group_raw)))
+                        return False
+
+            # Give values back ...
+            directive['olddir']['mode']  = mode
+            directive['olddir']['owner'] = owner
+            directive['olddir']['group'] = group
+            return True
+
+        # Check for minimum size for ratation
+        match = re.search(r'^size(?:(?:\s*=|\s)|$)', line, re.IGNORECASE)
+        if match:
+            size_str = re.sub(r'^size(?:\s*=\s*|\s+)', '', line)
+            if self.verbose > 5:
+                self.logger.debug(
+                    ( _("Checking for option 'size', value: '%(value)s' ... (file '%(file)s', line %(lnr)s)")
+                        % {'value': size_str, 'file': filename, 'lnr': linenr})
+                )
+            if size_str is None:
+                self.logger.warning( _("Failing size definition."))
+                return False
+            size_bytes = None
+            try:
+                size_bytes = human2bytes(size_str, verbose = self.verbose)
+            except ValueError, e:
+                self.logger.warning( ( _("Invalid definition for 'size': '%s'.") %(size_str)))
+                return False
+            if self.verbose > 4:
+                self.logger.debug(
+                    ( _("Got a rotation size in '%(directive)s' of %(bytes)d bytes. (file '%(file)s', line %(lnr)s)")
+                        % {'directive': directive_str, 'bytes': size_bytes, 'file': filename, 'lnr': linenr})
+                )
+            directive['size'] = size_bytes
+            return True
+
+        # Check for taboo options
+        pattern = r'^taboo(ext|file|prefix)$'
+        match = re.search(pattern, option, re.IGNORECASE)
+        if match:
+            key = match.group(1).lower()
+            if self.verbose > 5:
+                self.logger.debug(
+                    ( _("Checking for option 'taboo%(type)s', value: '%(value)s' ... (file '%(file)s', line %(lnr)s)")
+                        % {'type': key, 'value': val, 'file': filename, 'lnr': linenr})
+                )
+
+            if in_fd:
+                self.logger.warning( ( _("Option 'taboo%s' not allowed inside a logfile directive.") %(key)))
+                return False
+
+            values = []
+            if val is not None:
+                values = split_parts(val)
+
+            extend = False
+            if len(values) > 0 and values[0] is not None and values[0] == '+':
+                extend = True
+                values.pop(0)
+
+            if len(values) < 1:
+                self.logger.warning( ( _("Option 'taboo%s' needs a value.") %(key)))
+                return False
+
+            if not extend:
+                self.taboo = []
+            for extension in values:
+                self.add_taboo(extension, key)
+
+            return True
+
+        # Option not found, I'm angry
+        self.logger.warning( ( _("Unknown option '%s'.") %(option)))
+        return False
+
+    #------------------------------------------------------------
+    def _ext_script_definition(self, line, rest, filename, linenr):
+        '''
+        Starts a new explicite external script definition.
+        It raises a LogrotateConfigurationError on error.
+
+        @param line:     line of current config file
+        @type line:      str
+        @param rest:     rest of the current line after »script«
+        @type rest:      str
+        @param filename: current configuration file
+        @type filename:  str
+        @param linenr:   current line number of configuration file
+        @type linenr:    int
+
+        @return: name of the script (if a new script definition) or None
+        @rtype:  str or None
+        '''
+
+        _ = self.t.lgettext
+
+        # split the rest in chunks
+        values = split_parts(rest)
+
+        # insufficient arguments to include ...
+        if len(values) < 1:
+            self.logger.warning(
+                ( _("No script name given in a script directive. (file '%(file)s', line %(lnr)s)")
+                    % {'file': filename, 'lnr': linenr})
+            )
+            return None
+
+        # to much arguments to include ...
+        if len(values) > 1:
+            self.logger.warning(
+                ( _("Only one script name is allowed in a script directive, the first one is used. (file '%(file)s', line %(lnr)s)")
+                    % {'file': filename, 'lnr': linenr})
+            )
+
+        script_name = values[0]
+
+        if script_name in self.scripts:
+            self.logger.warning(
+                ( _("Script name '%(name)s' is allready declared, it will be overwritten. (file '%(file)s', line %(lnr)s)")
+                    % {'name': script_name, 'file': filename, 'lnr': linenr})
+            )
+
+        self.scripts[script_name] = LogRotateScript(
+            name      = script_name,
+            local_dir = self.local_dir,
+            verbose   = self.verbose,
+            test_mode = self.test_mode,
+        )
+        #self.scripts[script_name]['cmd'] = []
+        #self.scripts[script_name]['post_files'] = 0
+        #self.scripts[script_name]['last_files'] = 0
+        #self.scripts[script_name]['first'] = False
+        #self.scripts[script_name]['prerun'] = False
+        #self.scripts[script_name]['donepost'] = False
+        #self.scripts[script_name]['donelast'] = False
+
+        return script_name
+
+    #------------------------------------------------------------
+    def _do_include( self, line, rest, filename, linenr):
+        '''
+        Starts a new logfile definition.
+        It raises a LogrotateConfigurationError on error.
+
+        @param line:     line of current config file
+        @type line:      str
+        @param rest:     rest of the current line after »include«
+        @type rest:      str
+        @param filename: current configuration file
+        @type filename:  str
+        @param linenr:   current line number of configuration file
+        @type linenr:    int
+
+        @return: Success of include
+        @rtype:  bool
+        '''
+
+        _ = self.t.lgettext
+
+        # split the rest in chunks
+        values = split_parts(rest)
+
+        # insufficient arguments to include ...
+        if len(values) < 1:
+            self.logger.warning(
+                ( _("No file or directory given in a include directive (file '%(file)s', line %(lnr)s)")
+                    % {'file': filename, 'lnr': linenr})
+            )
+            return False
+
+        # to much arguments to include ...
+        if len(values) > 1:
+            self.logger.warning(
+                ( _("Only one declaration of a file or directory is allowed in a include directive, the first one is used. (file '%(file)s', line %(lnr)s)")
+                    % {'file': filename, 'lnr': linenr})
+            )
+
+        include = values[0]
+
+        # including object doesn't exists
+        if not os.path.exists(include):
+            self.logger.warning(
+                ( _("Including object '%(include)s' doesn't exists. (file '%(file)s', line %(lnr)s)")
+                    % {'include': include, 'file': filename, 'lnr': linenr})
+            )
+            return False
+
+        include = os.path.abspath(include)
+
+        # including object is neither a regular file nor a directory
+        if not (os.path.isfile(include) or os.path.isdir(include)):
+            self.logger.warning(
+                ( _("Including object '%(include)s' is neither a regular file  nor a directory. (file '%(file)s', line %(lnr)s)")
+                    % {'include': include, 'file': filename, 'lnr': linenr})
+            )
+            return False
+
+        if self.verbose > 1:
+            self.logger.debug( ( _("Trying to include object '%s' ...") % (include) ))
+
+        # including object is a regular file
+        if os.path.isfile(include):
+            if include in self.config_files:
+                self.logger.warning(
+                    ( _("Recursive including of '%(include)s'. (file '%(file)s', line %(lnr)s)")
+                        % {'include': include, 'file': filename, 'lnr': linenr})
+                )
+                return False
+            return self._read(include)
+
+        # This should never happen ...
+        if not os.path.isdir(include):
+            raise Exception(
+                ( _("What the hell is this: '%(include)s'. (file '%(file)s', line %(lnr)s)")
+                    % {'include': include, 'file': filename, 'lnr': linenr})
+            )
+
+        # including object is a directory - include all files
+        if self.verbose > 1:
+            self.logger.debug( ( _("Including directory '%s' ...") % (include) ))
+
+        dir_list = os.listdir(include)
+        for item in sorted(dir_list, key=str.lower):
+
+            item_path = os.path.abspath(os.path.join(include, item))
+            if self.verbose > 2:
+                self.logger.debug( ( _( "Including item '%(item)s' ('%(path)s') ..." )
+                    % {'item': item, 'path': item_path} )
+                )
+
+            # Skip directories
+            if os.path.isdir(item_path):
+                if self.verbose > 1:
+                    self.logger.debug( ( _("Skip subdirectory '%s' in including.") % (item_path)))
+                continue
+
+            # Skip non regular files
+            if not os.path.isfile(item_path):
+                self.logger.debug( ( _("Item '%s' is not a regular file.") % (item_path)))
+                continue
+
+            # Check for taboo pattern
+            taboo_found = False
+            for pattern in self.taboo:
+                match = re.search(pattern, item)
+                if match:
+                    if self.verbose > 1:
+                        self.logger.debug(
+                            ( _("Item '%(item)s' is matching pattern '%(pattern)s', skiping.")
+                                % {'item': item, 'pattern': pattern})
+                        )
+                    taboo_found = True
+                    break
+            if taboo_found:
+                continue
+
+            # Check, whther it was former included
+            if item_path in self.config_files:
+                self.logger.warning(
+                    ( _("Recursive including of '%(include)s' (file '%(file)s', line %(lnr)s)")
+                        % {'include': item_path, 'file': filename, 'lnr': linenr})
+                )
+                return False
+            self._read(item_path)
+
+    #------------------------------------------------------------
+    def _start_logfile_definition(
+        self, line, filename, in_fd, in_logfile_list, linenr
+    ):
+        '''
+        Starts a new logfile definition.
+        It raises a LogrotateConfigurationError on error.
+
+        @param line:            line of current config file
+        @type line:             str
+        @param filename:        current configuration file
+        @type filename:         str
+        @param in_fd:           parsing inside a logfile definition
+        @type in_fd:            bool
+        @param in_logfile_list: logfile pattern list was started
+        @type in_logfile_list:  bool
+        @param linenr:          current line number of configuration file
+        @type linenr:           int
+
+        @return: name of the script (if a new script definition) or None
+        @rtype:  str or None
+        '''
+
+        _ = self.t.lgettext
+
+        if in_fd:
+            raise LogrotateConfigurationError(
+                ( _("Nested logfile definitions are not allowed. (file '%(file)s', line %(lnr)s)")
+                    % {'file': filename, 'lnr': linenr})
+            )
+
+        if not in_logfile_list:
+            raise LogrotateConfigurationError(
+                ( _("No logfile pattern defined on starting a logfile definition. (file '%(file)s', line %(lnr)s)")
+                    % {'file': filename, 'lnr': linenr})
+            )
+
+    #------------------------------------------------------------
+    def _start_log_script_definition( self, script_type, script_name, line, filename, in_fd, linenr):
+        '''
+        Starts a new logfile definition or logfile refrence
+        inside a logfile definition.
+        It raises a LogrotateConfigurationError outside a logfile definition.
+
+        @param script_type: postrotate, prerotate, firstaction
+                            or lastaction
+        @type script_type:  str
+        @param script_name: name of refernced script
+        @type script_name:  str or None
+        @param line:        line of current config file
+        @type line:         str
+        @param filename:    current configuration file
+        @type filename:     str
+        @param in_fd:       parsing inside a logfile definition
+        @type in_fd:        bool
+        @param linenr:      current line number of configuration file
+        @type linenr:       int
+
+        @return: name of the script (if a new script definition) or None
+        @rtype:  str or None
+        '''
+
+        _ = self.t.lgettext
+
+        if not in_fd:
+            raise LogrotateConfigurationError(
+                ( _("Directive '%(directive)s' is not allowed outside of a logfile definition. (file '%(file)s', line %(lnr)s)")
+                    % {'directive': script_type, 'file': filename, 'lnr': linenr})
+            )
+
+        if script_name:
+            self.new_log[script_type] = script_name
+            return None
+
+        new_script_name = self._new_scriptname(script_type)
+
+        self.scripts[new_script_name] = LogRotateScript(
+            name      = new_script_name,
+            local_dir = self.local_dir,
+            verbose   = self.verbose,
+            test_mode = self.test_mode,
+        )
+        #self.scripts[new_script_name] = {}
+        #self.scripts[new_script_name]['cmd'] = []
+        #self.scripts[new_script_name]['post_files'] = 0
+        #self.scripts[new_script_name]['last_files'] = 0
+        #self.scripts[new_script_name]['first'] = False
+        #self.scripts[new_script_name]['prerun'] = False
+        #self.scripts[new_script_name]['donepost'] = False
+        #self.scripts[new_script_name]['donelast'] = False
+
+        self.new_log[script_type] = new_script_name
+
+        return new_script_name
+
+    #------------------------------------------------------------
+    def _new_scriptname(self, script_type = 'script'):
+        '''
+        Retrieves a new, unique script name.
+
+        @param script_type: prefix of the script name
+        @type script_type:  str
+
+        @return: a new, unique script name
+        @rtype:  str
+        '''
+
+        i = 0
+        template = script_type + "_%02d"
+        name = template % (i)
+
+        while True:
+
+            if name in self.scripts:
+                cmd = self.scripts[name].cmd
+                if cmd is not None:
+                    if len(cmd):
+                        i += 1
+                        name = template % (i)
+                    else:
+                        break
+                else:
+                    break
+            else:
+                break
+
+        return name
+
+    #------------------------------------------------------------
+    def _start_new_log(self, config_file, rownum):
+        '''
+        Starting a new log definition in self.new_log and filling it
+        with the current default values.
+
+        @param config_file: the configuration file with the start
+                            of the logfile definition
+        @type config_file:  str
+        @param rownum:      the row number of the configuration file
+                            with the start of the logfile definition
+        @type rownum:       int
+        '''
+
+        _ = self.t.lgettext
+
+        if self.verbose > 3:
+            self.logger.debug( _("Starting a new log directive with default values."))
+
+        self.new_log = {}
+
+        self.new_log['files'] = []
+        self.new_log['file_patterns'] = []
+
+        self.new_log['compress']      = self.default['compress']
+        self.new_log['compresscmd']   = self.default['compresscmd']
+        self.new_log['compressext']   = self.default['compressext']
+        self.new_log['compressoptions']  = self.default['compressoptions']
+        self.new_log['configfile']    = config_file
+        self.new_log['configrow']     = rownum
+        self.new_log['copy']          = self.default['copy']
+        self.new_log['copytruncate']  = self.default['copytruncate']
+        self.new_log['create']        = {
+            'enabled': self.default['create']['enabled'],
+            'mode':    self.default['create']['mode'],
+            'owner':   self.default['create']['owner'],
+            'group':   self.default['create']['group'],
+        }
+        self.new_log['period']        = self.default['period']
+        self.new_log['dateext']       = self.default['dateext']
+        self.new_log['datepattern']   = self.default['datepattern']
+        self.new_log['delaycompress'] = self.default['delaycompress']
+        self.new_log['extension']     = self.default['extension']
+        self.new_log['ifempty']       = self.default['ifempty']
+        self.new_log['mailaddress']   = self.default['mailaddress']
+        self.new_log['mailfirst']     = self.default['mailfirst']
+        self.new_log['maxage']        = self.default['maxage']
+        self.new_log['missingok']     = self.default['missingok']
+        self.new_log['olddir']        = {
+            'dirname':    self.default['olddir']['dirname'],
+            'dateformat': self.default['olddir']['dateformat'],
+            'enabled':    self.default['olddir']['enabled'],
+            'mode':       self.default['olddir']['mode'],
+            'owner':      self.default['olddir']['owner'],
+            'group':      self.default['olddir']['group'],
+        }
+        self.new_log['rotate']        = self.default['rotate']
+        self.new_log['sharedscripts'] = self.default['sharedscripts']
+        self.new_log['shred']         = self.default['shred']
+        self.new_log['size']          = self.default['size']
+        self.new_log['start']         = self.default['start']
+
+        for script_type in script_directives:
+            self.new_log[script_type] = None
+
+    #------------------------------------------------------------
+    def _assign_logfiles(self):
+        '''
+        Finds all existing logfiles of self.new_log according to the
+        shell matching patterns in self.new_log['file_patterns'].
+        If a logfile was even defined, a warning is omitted and the
+        new definition will thrown away.
+
+        @return: number of found logfiles according to self.new_log['file_patterns']
+        @rtype:  int
+        '''
+
+        _ = self.t.lgettext
+
+        if len(self.new_log['file_patterns']) <= 0:
+            msg = _("No logfile pattern defined.")
+            self.logger.warning(msg)
+            return 0
+
+        for pattern in self.new_log['file_patterns']:
+            if self.verbose > 1:
+                msg = _("Find all logfiles for shell matching pattern '%s' ...") \
+                       % (pattern)
+                self.logger.debug(msg)
+            logfiles = glob.glob(pattern)
+            if len(logfiles) <= 0:
+                msg = _("No logfile found for pattern '%s'.") % (pattern)
+                if self.new_log['missingok']:
+                    self.logger.debug(msg)
+                else:
+                    self.logger.warning(msg)
+                continue
+            for logfile in logfiles:
+                if self.verbose > 1:
+                    msg = _("Found logfile '%(file)s for pattern '%(pattern)s'.") \
+                           % {'file': logfile, 'pattern': pattern }
+                    self.logger.debug(msg)
+                if logfile in self.defined_logfiles:
+                    f = self.defined_logfiles[logfile]
+                    msg = ( _("Logfile '%(logfile)s' is even defined (file '%(cfgfile)s', " +
+                              "row %(rownum)d) and so not taken a second time.") 
+                             % {'logfile': logfile,
+                                'cfgfile': f['file'],
+                                'rownum': f['rownum']}
+                    )
+                    self.logger.warning(msg)
+                    continue
+                if self.verbose > 1:
+                    msg = _("Logfile '%s' will taken.") \
+                            % (logfile)
+                self.defined_logfiles[logfile] = {
+                        'file': self.new_log['configfile'],
+                        'rownum': self.new_log['configrow'],
+                }
+                self.new_log['files'].append(logfile)
+
+        return len(self.new_log['files'])
+
+#========================================================================
+
+if __name__ == "__main__":
+    pass
+
+
+#========================================================================
+
+# vim: fileencoding=utf-8 filetype=python ts=4 expandtab
diff --git a/LogRotate/LogRotateGetopts.py b/LogRotate/LogRotateGetopts.py
new file mode 100755 (executable)
index 0000000..e74bde7
--- /dev/null
@@ -0,0 +1,317 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# $Id$
+# $URL$
+
+'''
+@author: Frank Brehm
+@contact: frank@brehm-online.com
+@license: GPL3
+@copyright: (c) 2010-2011 by Frank Brehm, Berlin
+@version: 0.0.1
+@summary: Option parser for Python logrotating
+'''
+
+import re
+import sys
+import gettext
+
+from optparse import OptionError
+from optparse import OptionParser
+from optparse import OptionGroup
+from optparse import OptionConflictError
+
+
+revision = '$Revision$'
+revision = re.sub( r'\$', '', revision )
+revision = re.sub( r'Revision: ', r'r', revision )
+revision = re.sub( r'\s*$', '', revision )
+
+__author__    = 'Frank Brehm'
+__copyright__ = '(C) 2011 by Frank Brehm, Berlin'
+__contact__    = 'frank@brehm-online.com'
+__version__    = '0.0.1 ' + revision
+__license__    = 'GPL3'
+
+
+#========================================================================
+
+class LogrotateOptParserError(Exception):
+    '''
+    Class for exceptions in this module, escpacially
+    due to false commandline options.
+    '''
+
+#========================================================================
+
+class LogrotateOptParser(object):
+    '''
+    Class for parsing commandline options of Python logrotating.
+
+    @author: Frank Brehm
+    @contact: frank@brehm-online.com
+    '''
+
+    #-------------------------------------------------------
+    def __init__( self, prog = '%prog',
+                        version = None,
+                        local_dir = None,
+    ):
+        '''
+        Constructor.
+
+        @param prog:      The name of the calling process (e.g. sys.argv[0])
+        @type prog:       str
+        @param version:   The version string to use
+        @type version:    str
+        @param local_dir: The directory, where the i18n-files (*.mo)
+                          are located. If None, then system default
+                          (/usr/share/locale) is used.
+        @type local_dir:  str or None
+
+        @return: None
+        '''
+
+        self.prog = prog
+        '''
+        @ivar: The name of the calling process
+        @type: str
+        '''
+
+        self.version = version
+        '''
+        @ivar: The version string to use
+        @type: str
+        '''
+
+        self.local_dir = local_dir
+        '''
+        @ivar: The directory, where the i18n-files (*.mo) are located.
+        @type: str or None
+        '''
+
+        self.t = gettext.translation(
+            'LogRotateGetopts',
+            local_dir,
+            fallback = True
+        )
+        '''
+        @ivar: a gettext translation object
+        @type: gettext.translation
+        '''
+
+        _ = self.t.lgettext
+
+        self.description = _('Rotates, compresses and mails system logs.')
+        '''
+        @ivar: description of the program
+        @type: str
+        '''
+
+        self.usage = ( _("%s [options] <configfile>") + "\n" ) %(prog)
+        '''
+        @ivar: the usage string in getopt help output
+        @type: str
+        '''
+        self.usage += ( '       %s [-h|-?|--help]\n' %(prog) )
+        self.usage += ( '       %s --usage\n' %(prog) )
+        self.usage += ( '       %s --version' %(prog) )
+
+        self.options = None
+        '''
+        @ivar: a dict with all given commandline options
+               after calling getOpts()
+        @type: dict or None
+        '''
+
+        self.args = None
+        '''
+        @ivar: a list with all commandline parameters, what are not options
+        @type: list or None
+        '''
+
+        self.parsed = False
+        '''
+        @ivar: flag, whether the parsing was done
+        @type: bool
+        '''
+
+        if version:
+            self.version = version
+
+        self.parser = OptionParser(
+                prog             = self.prog,
+                version          = self.version,
+                description      = self.description,
+                usage            = self.usage,
+                conflict_handler = "resolve",
+        )
+        '''
+        @ivar: the working OptionParser Object
+        @type: optparse.OptionParser
+        '''
+
+        self._add_options()
+
+    #-------------------------------------------------------
+    def _add_options(self):
+        '''
+        Private function to add all necessary options
+        to the OptionParser object
+        '''
+
+        _ = self.t.ugettext
+        __ = self.t.ungettext
+
+        if self.parser.has_option('--help'):
+            self.parser.remove_option('--help')
+
+        if self.parser.has_option('--version'):
+            self.parser.remove_option('--version')
+
+        self.parser.add_option(
+            '--simulate',
+            '--test',
+            '-T',
+            default = False,
+            action  = 'store_true',
+            dest    = 'test',
+            help    = _('set this do simulate commands'),
+        )
+
+        self.parser.add_option(
+            '--verbose',
+            '-v',
+            default = False,
+            action  = 'count',
+            dest    = 'verbose',
+            help    = _('set the verbosity level'),
+        )
+
+        self.parser.add_option(
+            '--debug',
+            '-d',
+            default = False,
+            action  = 'store_true',
+            dest    = 'debug',
+            help    = _("Don't do anything, just test (implies -v and -T)"),
+        )
+
+        self.parser.add_option(
+            '--force',
+            '-f',
+            default = False,
+            action  = 'store_true',
+            dest    = 'force',
+            help    = _("Force file rotation"),
+        )
+
+        self.parser.add_option(
+            '--config-check',
+            '-c',
+            default = False,
+            action  = 'store_true',
+            dest    = 'configcheck',
+            help    = _("Checks only the given configuration file and does "
+                      + "nothing. Conflicts with -f."),
+        )
+
+        self.parser.add_option(
+            '--state',
+            '-s',
+            dest    = "statefile",
+            metavar = 'FILE',
+            help    = _('Path of state file (different to configuration)'),
+        )
+
+        self.parser.add_option(
+            '--pid-file',
+            '-P',
+            dest    = "pidfile",
+            metavar = 'FILE',
+            help    = _('Path of PID file (different to configuration)'),
+        )
+
+        self.parser.add_option(
+            '--mail',
+            '-m',
+            dest    = "mailcmd",
+            metavar = 'CMD',
+            help    = _('Command to send mail (instead of using '
+                        + 'the Phyton email package)'),
+        )
+
+        ######
+        # Option group for common options
+
+        group = OptionGroup(self.parser, _("Common options"))
+
+        group.add_option(
+            '-h',
+            '-?',
+            '--help',
+            default = False,
+            action  = 'help',
+            dest    = 'help',
+            help    = _('Shows a help message and exit.'),
+        )
+
+        group.add_option(
+            '--usage',
+            default = False,
+            action  = 'store_true',
+            dest    = 'usage',
+            help    = _('Display brief usage message and exit.'),
+        )
+
+        group.add_option(
+            '-V',
+            '--version',
+            default = False,
+            action  = 'version',
+            dest    = 'version',
+            help    = _('Shows the version number of the program and exit.'),
+        )
+
+        self.parser.add_option_group(group)
+
+    #----------------------------------------------------------------------
+    def getOpts(self):
+        '''
+        Wrapper function to OptionParser.parse_args().
+        Sets self.options and self.args with the appropriate values.
+        @return: None
+        '''
+
+        _ = self.t.ugettext
+
+        if not self.parsed:
+            self.options, self.args = self.parser.parse_args()
+            self.parsed = True
+
+        if self.options.usage:
+            self.parser.print_usage()
+            sys.exit(0)
+
+        if self.options.force and self.options.configcheck:
+            raise LogrotateOptParserError( _('Invalid usage of --force and '
+                + '--config-check.') )
+
+        if self.args is None or len(self.args) < 1:
+            raise LogrotateOptParserError( _('No configuration file given.') )
+
+        if len(self.args) != 1:
+            raise LogrotateOptParserError(
+                _('Only one configuration file is allowed.')
+            )
+
+#========================================================================
+
+if __name__ == "__main__":
+    pass
+
+
+#========================================================================
+
+# vim: fileencoding=utf-8 filetype=python ts=4 expandtab
diff --git a/LogRotate/LogRotateHandler.py b/LogRotate/LogRotateHandler.py
new file mode 100755 (executable)
index 0000000..dda1852
--- /dev/null
@@ -0,0 +1,2390 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# $Id$
+# $URL$
+
+'''
+@author: Frank Brehm
+@contact: frank@brehm-online.com
+@license: GPL3
+@copyright: (c) 2010-2011 by Frank Brehm, Berlin
+@version: 0.4.0
+@summary: Application handler module for Python logrotating
+'''
+
+# Für Terminal-Dinge: http://code.activestate.com/recipes/475116/
+
+import re
+import sys
+import gettext
+import logging
+import pprint
+import os
+import os.path
+import errno
+import socket
+import subprocess
+import shutil
+import glob
+from datetime import datetime, timedelta
+import time
+import gzip
+import bz2
+import zipfile
+
+from LogRotateConfig import LogrotateConfigurationError
+from LogRotateConfig import LogrotateConfigurationReader
+
+from LogRotateStatusFile import LogrotateStatusFileError
+from LogRotateStatusFile import LogrotateStatusFile
+from LogRotateStatusFile import utc
+
+from LogRotateMailer import LogRotateMailerError
+from LogRotateMailer import LogRotateMailer
+
+revision = '$Revision$'
+revision = re.sub( r'\$', '', revision )
+revision = re.sub( r'Revision: ', r'r', revision )
+revision = re.sub( r'\s*$', '', revision )
+
+__author__    = 'Frank Brehm'
+__copyright__ = '(C) 2011 by Frank Brehm, Berlin'
+__contact__    = 'frank@brehm-online.com'
+__version__    = '0.4.0 ' + revision
+__license__    = 'GPL3'
+
+
+#========================================================================
+
+class LogrotateHandlerError(Exception):
+    '''
+    Base class for exceptions in this module.
+    '''
+
+#========================================================================
+
+class StdoutFilter(logging.Filter):
+    '''
+    Class, that filters all logrecords
+    '''
+
+    def filter(self, record):
+        '''
+        Filtering log records and let through messages
+        except them with the level names 'WARNING', 'ERROR' or 'CRITICAL'.
+
+        @param record: the record to filter
+        @type record:  logging.LogRecord
+
+        @return: pass the record or not
+        '''
+        if record.levelname == 'WARNING':
+            return False
+        if record.levelname == 'ERROR':
+            return False
+        if record.levelname == 'CRITICAL':
+            return False
+        return True
+
+#========================================================================
+
+class LogrotateHandler(object):
+    '''
+    Class for application handler for Python logrotating
+
+    @author: Frank Brehm
+    @contact: frank@brehm-online.com
+    '''
+
+    #-------------------------------------------------------
+    def __init__( self, config_file,
+                        test         = False,
+                        verbose      = 0,
+                        force        = False,
+                        config_check = False,
+                        state_file   = None,
+                        pid_file     = None,
+                        mail_cmd     = None,
+                        local_dir    = None,
+                        version      = None,
+    ):
+        '''
+        Constructor.
+
+        @param config_file:  the configuration file to use
+        @type config_file:   str
+        @param test:         testmode, no real actions are made
+        @type test:          bool
+        @param verbose:      verbosity (debug) level
+        @type verbose:       int
+        @param force:        Force file rotation
+        @type force:         bool
+        @param config_check: Checks only the configuration and does nothing
+        @type config_check:  bool
+        @param state_file:   Path of state file (different to configuration)
+        @type state_file:    str or None
+        @param pid_file:     Path of PID file (different to configuration)
+        @type pid_file:      str or None
+        @param mail_cmd:     command to send mail (instead of using
+                             the Phyton email package)
+        @type mail_cmd:      str or None
+        @param local_dir:    The directory, where the i18n-files (*.mo)
+                             are located. If None, then system default
+                             (/usr/share/locale) is used.
+        @type local_dir:     str or None
+        @param version:      version number to show
+        @type version:       str
+
+        @return: None
+        '''
+
+        self.local_dir = local_dir
+        '''
+        @ivar: The directory, where the i18n-files (*.mo) are located.
+        @type: str or None
+        '''
+
+        self.t = gettext.translation(
+            'LogRotateHandler',
+            local_dir,
+            fallback = True
+        )
+        '''
+        @ivar: a gettext translation object
+        @type: gettext.translation
+        '''
+
+        _ = self.t.lgettext
+
+        self.verbose = verbose
+        '''
+        @ivar: verbosity level (0 - 9)
+        @type: int
+        '''
+
+        self.version = __version__
+        '''
+        @ivar: version number to show, e.g. as the X-Mailer version
+        @type: str
+        '''
+        if version is not None:
+            self.version = version
+
+        self.test = test
+        '''
+        @ivar: testmode, no real actions are made
+        @type: bool
+        '''
+
+        self.force = force
+        '''
+        @ivar: Force file rotation
+        @type: bool
+        '''
+
+        self.state_file = None
+        '''
+        @ivar: the state file object after his initialisation
+        @type: LogRotateStateFile or None
+        '''
+
+        self.state_file_name = state_file
+        '''
+        @ivar: Path of state file (from commandline or from configuration)
+        @type: str
+        '''
+
+        self.pid_file = pid_file
+        '''
+        @ivar: Path of PID file (from commandline or from configuration)
+        @type: str
+        '''
+
+        self.pidfile_created = False
+        '''
+        @ivar: Is a PID file created by this instance and should removed
+               on destroying this object.
+        @type: bool
+        '''
+
+        self.mail_cmd = mail_cmd
+        '''
+        @ivar: command to send mail (instead of using the Phyton email package)
+        @type: str or None
+        '''
+
+        self.config_file = config_file
+        '''
+        @ivar: the initial configuration file to use
+        @type: str
+        '''
+
+        self.config = []
+        '''
+        @ivar: the configuration, how it was read from cofiguration file(s)
+        @type: dict
+        '''
+
+        self.scripts = {}
+        '''
+        @ivar: list of LogRotateScript objects with all named scripts found in configuration
+        @type: list
+        '''
+
+        self.template = {}
+        '''
+        @ivar: things to do in olddir stuff
+        @type: dict
+        '''
+        self._prepare_templates()
+
+        self.logfiles = []
+        '''
+        @ivar: list of all rotated logfiles. Each entry is a dict with
+               three keys:
+                - 'original': str with the name of the unrotated file
+                - 'rotated':  str with the name of the rotated file
+                - 'oldfiles:  list with all old rotated files of this file
+                - 'desc_index': index of list self.config for appropriate
+                                logfile definition
+        @type: list
+        '''
+
+        self.files_delete = {}
+        '''
+        @ivar: dictionary with all files, they have to delete
+        @type: dict
+        '''
+
+        self.files_compress = {}
+        '''
+        @ivar: dictionary with all files, they have to compress
+               keys are the filenames, values are the index number
+               of the list self.config (for compress options)
+        @type: dict
+        '''
+
+        self.files2send = {}
+        '''
+        @ivar: dictionary with all all rotated logfiles to send via
+               mail to one or more recipients.
+               Keys are the file names of the (even existing) rotated
+               and maybe compressed logfiles.
+               Values are a tuple of (mailaddress, original_logfile), where
+               mailaddress is a comma separated list of mail addresses of
+               the recipients of the mails, and original_logfile is the name
+               of unrotated logfile.
+               This dict will filled by _do_rotate_file(), and will performed
+               by send_logfiles().
+        @type: dict
+        '''
+
+        #################################################
+        # Create a logger object
+        self.logger = logging.getLogger('pylogrotate')
+        '''
+        @ivar: logger object
+        @type: logging.getLogger
+        '''
+
+        self.logger.setLevel(logging.DEBUG)
+
+        # create formatter
+        format_str = '[%(asctime)s]: %(levelname)-8s - %(message)s'
+        if test:
+            format_str = '%(levelname)-8s - %(message)s'
+        if verbose:
+            if verbose > 1:
+                format_str = '[%(asctime)s]: %(name)s %(funcName)s() %(levelname)-8s - %(message)s'
+                if test:
+                    format_str = '%(name)s %(funcName)s() %(levelname)-8s - %(message)s'
+            else:
+                format_str = '[%(asctime)s]: %(name)s %(levelname)-8s - %(message)s'
+                if test:
+                    format_str = '%(name)s %(levelname)-8s - %(message)s'
+        formatter = logging.Formatter(format_str)
+
+        # create console handler for error messages
+        console_stderr = logging.StreamHandler(sys.stderr)
+        console_stderr.setLevel(logging.WARNING)
+        console_stderr.setFormatter(formatter)
+        self.logger.addHandler(console_stderr)
+
+        # create console handler for other messages
+        console_stdout = logging.StreamHandler(sys.stdout)
+        if verbose:
+            console_stdout.setLevel(logging.DEBUG)
+        else:
+            console_stdout.setLevel(logging.INFO)
+        fltr = StdoutFilter()
+        console_stdout.addFilter(fltr)
+        console_stdout.setFormatter(formatter)
+        self.logger.addHandler(console_stdout)
+
+        # define a mailer object
+        self.mailer = LogRotateMailer(
+            local_dir = self.local_dir,
+            verbose = self.verbose,
+            test_mode = self.test,
+            mailer_version = self.version,
+        )
+        if mail_cmd:
+            self.mailer.sendmail = mail_cmd
+
+        # end of init properties
+        self.logger.debug( _("Logrotating initialised") )
+
+        if not self.read_configuration():
+            self.logger.error( _('Could not read configuration') )
+            sys.exit(1)
+
+        if config_check:
+            return
+
+        if not self._check_pidfile():
+            sys.exit(3)
+
+        if not self._write_pidfile():
+            sys.exit(3)
+
+        self.logger.debug( _("Logrotating ready for work") )
+
+        # Create status file object
+        self.state_file = LogrotateStatusFile(
+            file_name = self.state_file_name,
+            local_dir = self.local_dir,
+            verbose   = self.verbose,
+            test_mode = self.test,
+        )
+
+    #------------------------------------------------------------
+    def __str__(self):
+        '''
+        Typecasting function for translating object structure
+        into a string
+
+        @return: structure as string
+        @rtype:  str
+        '''
+
+        pp = pprint.PrettyPrinter(indent=4)
+        structure = self.as_dict()
+        return pp.pformat(structure)
+
+    #-------------------------------------------------------
+    def as_dict(self):
+        '''
+        Transforms the elements of the object into a dict
+
+        @return: structure as dict
+        @rtype:  dict
+        '''
+
+        res = {
+            'config':          self.config,
+            'config_file':     self.config_file,
+            'files_delete':    self.files_delete,
+            'files_compress':  self.files_compress,
+            'files2send':      self.files2send,
+            'force':           self.force,
+            'local_dir':       self.local_dir,
+            'logfiles':        self.logfiles,
+            'logger':          self.logger,
+            'mail_cmd':        self.mail_cmd,
+            'mailer':          self.mailer.as_dict(),
+            'scripts':         {},
+            'state_file':      None,
+            'state_file_name': self.state_file_name,
+            'pid_file':        self.pid_file,
+            'pidfile_created': self.pidfile_created,
+            't':               self.t,
+            'test':            self.test,
+            'template':        self.template,
+            'verbose':         self.verbose,
+            'version':         self.version,
+        }
+        if self.state_file:
+            res['state_file'] = self.state_file.as_dict()
+
+        for script_name in self.scripts.keys():
+            res['scripts'][script_name] = self.scripts[script_name].as_dict()
+
+        return res
+
+    #------------------------------------------------------------
+    def __del__(self):
+        '''
+        Destructor.
+        No parameters, no return value.
+        '''
+
+        _ = self.t.lgettext
+
+        if self.pidfile_created:
+            if os.path.exists(self.pid_file):
+                self.logger.debug( _("Removing PID file '%s' ...") % (self.pid_file) )
+                try:
+                    os.remove(self.pid_file)
+                except OSError, e:
+                    self.logger.error( _("Error removing PID file '%(file)s': %(msg)")
+                        % { 'file': self.pid_file, 'msg': str(e) }
+                    )
+
+    #------------------------------------------------------------
+    def _prepare_templates(self):
+        '''
+        Preparing self.template with values for placeholders
+        in olddir stuff.
+        '''
+
+        self.template = {}
+
+        hostname = socket.getfqdn()
+        self.template['nodename'] = hostname
+        self.template['domain'] = ''
+
+        match = re.search(r'^([^\.]+)\.(.*)', hostname)
+        if match:
+            self.template['nodename'] = match.group(1)
+            self.template['domain'] = match.group(2)
+
+        uname = os.uname()
+        self.template['sysname'] = uname[0]
+        self.template['release'] = uname[2]
+        self.template['version'] = uname[3]
+        self.template['machine'] = uname[4]
+
+    #------------------------------------------------------------
+    def read_configuration(self):
+        '''
+        Reads the configuration from self.config_file
+
+        @return: Success of reading
+        @rtype:  bool
+        '''
+
+        _ = self.t.lgettext
+
+        config_reader = LogrotateConfigurationReader(
+            config_file = self.config_file,
+            verbose     = self.verbose,
+            local_dir   = self.local_dir,
+            test_mode   = self.test,
+        )
+
+        if self.verbose > 2:
+            msg = _("Configuration reader object structure") + ':\n' + str(config_reader)
+            self.logger.debug(msg)
+
+        try:
+            self.config  = config_reader.get_config()
+            self.scripts = config_reader.get_scripts()
+        except LogrotateConfigurationError, e:
+            self.logger.error( str(e) )
+            sys.exit(10)
+
+        if self.verbose > 2:
+            pp = pprint.PrettyPrinter(indent=4)
+            msg = _("Found global options:") + "\n" + pp.pformat(config_reader.global_option)
+            self.logger.debug(msg)
+
+        # Get and set mailer options
+        if 'mailfrom' in config_reader.global_option and \
+                config_reader.global_option['mailfrom']:
+            self.mailer.from_address = config_reader.global_option['mailfrom']
+        if config_reader.global_option['smtphost'] and \
+                config_reader.global_option['smtphost'] != 'localhost':
+            self.mailer.smtp_host = config_reader.global_option['smtphost']
+        if 'smtpport' in config_reader.global_option:
+            self.mailer.smtp_port = config_reader.global_option['smtpport']
+        if 'smtptls' in config_reader.global_option:
+            self.mailer.smtp_tls = config_reader.global_option['smtptls']
+        if 'smtpuser' in config_reader.global_option:
+            self.mailer.smtp_user = config_reader.global_option['smtpuser']
+        if 'smtppasswd' in config_reader.global_option:
+            self.mailer.smtp_passwd = config_reader.global_option['smtppasswd']
+
+        if self.state_file_name is None:
+            if 'statusfile' in config_reader.global_option and \
+                    config_reader.global_option['statusfile'] is not None:
+                self.state_file_name = config_reader.global_option['statusfile']
+            else:
+                self.state_file_name = os.sep + os.path.join('var', 'lib', 'py-logrotate.status')
+        self.logger.debug( _("Name of state file: '%s'") % (self.state_file_name) )
+
+        if self.pid_file is None:
+            if 'pidfile' in config_reader.global_option and \
+                    config_reader.global_option['pidfile'] is not None:
+                self.pid_file = config_reader.global_option['pidfile']
+            else:
+                self.pid_file = os.sep + os.path.join('var', 'run', 'py-logrotate.pid')
+        self.logger.debug( _("PID file: '%s'") % (self.pid_file) )
+
+        return True
+
+    #------------------------------------------------------------
+    def _check_pidfile(self):
+        '''
+        Checks the existence and consistence of self.pid_file.
+
+        Exit, if there is a running process with a PID from this file.
+        Doesn't exit in test mode.
+
+        Writes on success (no other process) this PID file.
+
+        @return: Success
+        @rtype:  bool
+        '''
+
+        _ = self.t.lgettext
+
+        if not os.path.exists(self.pid_file):
+            if self.verbose > 1:
+                self.logger.debug( _("PID file '%s' doesn't exists.") % (self.pid_file) )
+            return True
+
+        if self.test:
+            self.logger.info( _("Testmode, skip test of PID file '%s'.") % (self.pid_file) )
+            return True
+
+        self.logger.debug( _("Reading PID file '%s' ...") % (self.pid_file) )
+        f = None
+        try:
+            f = open(self.pid_file, 'r')
+        except IOError, e:
+            raise LogrotateHandlerError(
+                _("Couldn't open PID file '%(file)s' for reading: %(msg)s")
+                % { 'file': self.pid_file, 'msg': str(e) }
+            )
+
+        line = f.readline()
+        f.close()
+
+        pid = None
+        line = line.strip()
+        match = re.search(r'^\s*(\d+)\s*$', line)
+        if match:
+            pid = int(match.group(1))
+        else:
+            self.logger.warn( _("No useful information found in PID file '%(file)s': '%(line)s'")
+                % { 'file': self.pid_file, 'line': line }
+            )
+            return False
+
+        if self.verbose > 1:
+            self.logger.debug( _("Trying check for process with PID %d ...") % (pid) )
+        try:
+            os.kill(pid, 0)
+        except OSError, err:
+            if err.errno == errno.ESRCH:
+                self.logger.info( _("Process with PID %d anonymous died.") % (pid) )
+                return True
+            elif err.errno == errno.EPERM:
+                self.logger.warn( _("No permission to signal the process %d ...") % (pid) )
+                return True
+            else:
+                self.logger.warn( _("Unknown error: '%s'") % (str(err)) )
+                return False
+        else:
+            self.logger.error( _("Process with PID %d is allready running.") % (pid) )
+            return False
+
+        return False
+
+    #------------------------------------------------------------
+    def _write_pidfile(self):
+        '''
+        Writes the PID of the current process in self.pid_file.
+
+        Exit with an error, if it's not possible to write.
+        Doesn't exit in test mode.
+
+        Writes on success (no other process) this PID file.
+
+        @return: Success
+        @rtype:  bool
+        '''
+
+        _ = self.t.lgettext
+
+        if self.test:
+            self.logger.info( _("Testmode, skip writing of PID file '%s'.") % (self.pid_file) )
+            return True
+
+        self.logger.debug( _("Writing PID file '%s' ...") % (self.pid_file) )
+
+        f = None
+        try:
+            f = open(self.pid_file, 'w')
+            f.write(str(os.getppid()) + "\n")
+            f.close()
+        except IOError, e:
+            raise LogrotateHandlerError(
+                _("Couldn't open PID file '%(file)s' for writing: %(msg)s")
+                % { 'file': self.pid_file, 'msg': str(e) }
+            )
+
+        self.pidfile_created = True
+
+        return True
+
+    #------------------------------------------------------------
+    def rotate(self):
+        '''
+        Starting the underlying rotating.
+
+        @return: None
+        '''
+
+        _ = self.t.lgettext
+
+        if len(self.config) < 1:
+            msg = _("No logfile definitions found.")
+            self.logger.info(msg)
+            return
+
+        msg = _("Starting underlying rotation ...")
+        self.logger.info(msg)
+
+        cur_desc_index = 0
+        for d in self.config:
+            self._rotate_definition(cur_desc_index)
+            cur_desc_index += 1
+
+        if self.verbose > 1:
+            line = 60 * '-'
+            print line + "\n\n"
+
+        # Check for left over scripts to execute
+        for scriptname in self.scripts.keys():
+            if self.verbose >= 4:
+                msg = ( _("State of script '%s':") % (scriptname) ) \
+                        + "\n" + str(self.scripts[scriptname])
+                self.logger.debug(msg)
+            del self.scripts[scriptname]
+
+        return
+
+    #------------------------------------------------------------
+    def _rotate_definition(self, cur_desc_index):
+        '''
+        Rotation of a logfile definition from a configuration file.
+
+        @param cur_desc_index: index of self.config for definition
+                               of logfile from configuration file
+        @type cur_desc_index:  int
+
+        @return: None
+        '''
+
+        definition = self.config[cur_desc_index]
+
+        _ = self.t.lgettext
+
+        if self.verbose > 1:
+            line = 60 * '-'
+            print line + "\n\n"
+
+        if self.verbose >= 4:
+            pp = pprint.PrettyPrinter(indent=4)
+            msg = _("Rotating of logfile definition:") + \
+                    "\n" + pp.pformat(definition)
+            self.logger.debug(msg)
+
+        # re-reading of status file
+        self.state_file.read()
+
+        for logfile in definition['files']:
+            if self.verbose > 1:
+                line = 30 * '-'
+                print (line + "\n")
+                msg = ( _("Performing logfile '%s' ...") % (logfile))
+                self.logger.debug(msg)
+            should_rotate = self._should_rotate(logfile, cur_desc_index)
+            if self.verbose > 1:
+                if should_rotate:
+                    msg = _("logfile '%s' WILL rotated.")
+                else:
+                    msg = _("logfile '%s' will NOT rotated.")
+                self.logger.debug(msg % (logfile))
+            if not should_rotate:
+                continue
+            self._rotate_file(logfile, cur_desc_index)
+
+        if self.verbose > 1:
+            print "\n"
+
+        return
+
+    #------------------------------------------------------------
+    def _rotate_file(self, logfile, cur_desc_index):
+        '''
+        Rotates a logfile with all with all necessary actions before
+        and after rotation.
+
+        Throughs an LogrotateHandlerError on error.
+
+        @param logfile: the logfile to rotate
+        @type logfile:  str
+        @param cur_desc_index: index of self.config for definition
+                               of logfile from configuration file
+        @type cur_desc_index:  int
+
+        @return: None
+        '''
+
+        definition = self.config[cur_desc_index]
+
+        _ = self.t.lgettext
+
+        sharedscripts = definition['sharedscripts']
+        firstscript   = definition['firstaction']
+        prescript     = definition['prerotate']
+        postscript    = definition['postrotate']
+        lastscript    = definition['lastaction']
+
+        # Executing of the firstaction script, if it wasn't executed
+        if firstscript:
+            if self.verbose > 2:
+                msg = _("Looking, whether the firstaction script should be executed.")
+                self.logger.debug(msg)
+            if not self.scripts[firstscript].done_firstrun:
+                msg = _("Executing firstaction script '%s' ...") % (firstscript)
+                self.logger.info(msg)
+                if not self.scripts[firstscript].execute():
+                    return
+                self.scripts[firstscript].done_firstrun = True
+
+        # Executing prerotate scripts, if not sharedscripts or even not executed
+        if prescript:
+            if self.verbose > 2:
+                msg = _("Looking, whether the prerun script should be executed.")
+                self.logger.debug(msg)
+            do_it = False
+            if sharedscripts:
+                if not self.scripts[prescript].done_prerun:
+                    do_it = True
+            else:
+                do_it = True
+            if do_it:
+                msg = _("Executing prerun script '%s' ...") % (prescript)
+                self.logger.info(msg)
+                if not self.scripts[prescript].execute():
+                    return
+                self.scripts[prescript].done_prerun = True
+
+        olddir = self._create_olddir(logfile, cur_desc_index)
+        if olddir is None:
+            return
+
+        if not self._do_rotate_file(logfile, cur_desc_index, olddir):
+            return
+
+        # Looking for postrotate script in a similar way like for the prerotate
+        if postscript:
+            if self.verbose > 2:
+                msg = _("Looking, whether the postrun script should be executed.")
+                self.logger.debug(msg)
+            do_it = False
+            self.scripts[postscript].post_files -= 1
+            self.scripts[postscript].do_post = True
+            if sharedscripts:
+                if self.scripts[postscript].post_files <= 0:
+                    do_it = True
+                    self.scripts[postscript].do_post = False
+            else:
+                do_it = True
+            if do_it:
+                msg = _("Executing postrun script '%s' ...") % (postscript)
+                self.logger.info(msg)
+                if not self.scripts[postscript].execute():
+                    return
+                self.scripts[postscript].done_postrun = True
+
+        # Looking for lastaction script
+        if lastscript:
+            if self.verbose > 2:
+                msg = _("Looking, whether the lastaction script should be executed.")
+                self.logger.debug(msg)
+            do_it = False
+            self.scripts[lastscript].last_files -= 1
+            self.scripts[lastscript].do_last = True
+            if self.scripts[lastscript].done_lastrun:
+                self.scripts[lastscript].do_last = False
+            else:
+                if self.scripts[lastscript].last_files <= 0:
+                    do_it = True
+                    self.scripts[lastscript].do_last = False
+            if do_it:
+                msg = _("Executing lastaction script '%s' ...") % (lastscript)
+                self.logger.info(msg)
+                if not self.scripts[lastscript].execute():
+                    return
+                self.scripts[lastscript].done_lastrun = True
+
+    #------------------------------------------------------------
+    def _do_rotate_file(self, logfile, cur_desc_index, olddir = None):
+        '''
+        The underlaying unconditionally rotation of a logfile.
+
+        After the successful rotation 
+
+        @param logfile: the logfile to rotate
+        @type logfile:  str
+        @param cur_desc_index: index of self.config for definition
+                               of logfile from configuration file
+        @type cur_desc_index:  int
+        @param olddir: the directory of the rotated logfile
+                       if "." or None, store the rotated logfile
+                       in their original directory
+        @type olddir: str or None
+
+        @return: successful or not
+        @rtype:  bool
+        '''
+
+        definition = self.config[cur_desc_index]
+
+        if (olddir is not None) and (olddir == "."):
+            olddir = None
+
+        _ = self.t.lgettext
+
+        uid = os.geteuid()
+        gid = os.getegid()
+
+        msg = _("Do rotate logfile '%s' ...") % (logfile)
+        self.logger.debug(msg)
+
+        target = self._get_rotation_target(logfile, cur_desc_index, olddir)
+        rotations = self._get_rotations(logfile, target, cur_desc_index)
+
+        extension = rotations['extension']
+        compress_extension = rotations['compress_extension']
+
+        # First move all cyclic stuff
+        for pair in rotations['move']:
+            file_from = pair['from']
+            file_to = pair['to']
+            if pair['compressed']:
+                file_from += compress_extension
+                file_to += compress_extension
+            msg = _("Moving file '%(from)s' => '%(to)s'.") \
+                    % {'from': file_from, 'to': file_to }
+            self.logger.info(msg)
+            if not self.test:
+                try:
+                    shutil.move(file_from, file_to)
+                except OSError:
+                    msg = _("Error on moving '%(from)s' => '%(to)s': %(err)s") \
+                            % {'from': file_from, 'to': file_to, 'err': e.strerror}
+                    self.logger.error(msg)
+                    return False
+
+        # Now the underlaying rotation
+        file_from = rotations['rotate']['from']
+        file_to = rotations['rotate']['to']
+
+        # First check for an existing mail address
+        if definition['mailaddress'] and definition['mailfirst']:
+            self.mailer.send_file(file_from, definition['mailaddress'])
+
+        # separate between copy(truncate) and move (and create)
+        if definition['copytruncate'] or definition['copy']:
+            # Copying logfile to target
+            msg = _("Copying file '%(from)s' => '%(to)s'.") \
+                    % {'from': file_from, 'to': file_to }
+            self.logger.info(msg)
+            if not self.test:
+                try:
+                    shutil.copy2(file_from, file_to)
+                except OSError:
+                    msg = _("Error on copying '%(from)s' => '%(to)s': %(err)s") \
+                            % {'from': file_from, 'to': file_to, 'err': e.strerror}
+                    self.logger.error(msg)
+                    return False
+            if definition['copytruncate']: 
+                msg = _("Truncating file '%s'.") % (file_from)
+                self.logger.info(msg)
+                if not self.test:
+                    try:
+                        fd = open(file_from, 'w')
+                        fd.close()
+                    except IOError, e:
+                        msg = _("Error on truncing file '%(from)s': %(err)s") \
+                                % {'from': file_from, 'err': str(e)}
+                        self.logger.error(msg)
+                        return False
+
+        else:
+
+            # Moving logfile to target
+            msg = _("Moving file '%(from)s' => '%(to)s'.") \
+                    % {'from': file_from, 'to': file_to }
+            self.logger.info(msg)
+
+            # get old permissions of logfile
+            statinfo = os.stat(file_from)
+
+            if not self.test:
+                try:
+                    shutil.move(file_from, file_to)
+                except OSError:
+                    msg = _("Error on moving '%(from)s' => '%(to)s': %(err)s") \
+                            % {'from': file_from, 'to': file_to, 'err': e.strerror}
+                    self.logger.error(msg)
+                    return False
+    
+            if definition['create']['enabled']:
+
+                # Recreate logfile
+                msg = _("Recreating file '%s'.") % (file_from)
+                self.logger.info(msg)
+                if not self.test:
+                    try:
+                        fd = open(file_from, 'w')
+                        fd.close()
+                    except IOError, e:
+                        msg = _("Error on creating file '%(from)s': %(err)s") \
+                                % {'from': file_from, 'err': str(e)}
+                        self.logger.error(msg)
+                        return False
+
+                # Setting permissions and ownership
+                new_mode = statinfo.st_mode
+                new_uid  = statinfo.st_uid
+                new_gid  = statinfo.st_gid
+
+                if not definition['create']['mode'] is None:
+                    new_mode = definition['create']['mode']
+                if not definition['create']['owner'] is None:
+                    new_uid = definition['create']['owner']
+                if not definition['create']['group'] is None:
+                    new_gid = definition['create']['group']
+
+                statinfo = os.stat(file_from)
+                old_mode = statinfo.st_mode
+                old_uid  = statinfo.st_uid
+                old_gid  = statinfo.st_gid
+
+                # Check and set permissions of new logfile
+                if new_mode != old_mode:
+                    msg = _("Setting permissions of '%(file)s' to %(mode)4o.") \
+                            % {'file': file_from, 'mode': new_mode}
+                    self.logger.info(msg)
+                    if not self.test:
+                        try:
+                            os.chmod(file_from, new_mode)
+                        except OSError, e:
+                            msg = _("Error on chmod of '%(file)s': %(err)s") \
+                                    % {'file': file_from, 'err': e.strerror}
+                            self.logger.warning(msg)
+
+                # Check and set ownership of new logfile
+                if (new_uid != old_uid) or (new_gid != old_gid):
+                    myuid = os.geteuid()
+                    if myuid != 0:
+                        msg = _("Only root may execute chown().")
+                        if self.test:
+                            self.logger.info(msg)
+                        else:
+                            self.logger.warning(msg)
+                    else:
+                        msg = _("Setting ownership of '%(file)s' to uid %(uid)d and gid %(gid)d.") \
+                                % {'file': file_from, 'uid': new_uid, 'gid': new_gid}
+                        self.logger.info(msg)
+                        if not self.test:
+                            try:
+                                os.chown(file_from, new_uid, new_gid)
+                            except OSError, e:
+                                msg = _("Error on chown of '%(file)s': %(err)s") \
+                                        % {'file': file_from, 'err': e.strerror}
+                                self.logger.warning(msg)
+
+        oldfiles = self._collect_old_logfiles(logfile, extension, compress_extension, cur_desc_index)
+
+        # get files to delete and save them back in self.files_delete
+        files_delete = self._collect_files_delete(oldfiles, cur_desc_index)
+        if len(files_delete):
+            for oldfile in files_delete:
+                self.files_delete[oldfile] = True
+                if definition['mailaddress'] and not definition['mailfirst']:
+                    self.files2send[oldfile] = (definition['mailaddress'], logfile)
+
+        # get files to compress save them back in self.files_compress
+        files_compress = self._collect_files_compress(oldfiles, compress_extension, cur_desc_index)
+        if len(files_compress):
+            for oldfile in files_compress:
+                self.files_compress[oldfile] = cur_desc_index
+
+        # write back date of rotation into state file
+        self.state_file.set_rotation_date(logfile)
+        self.state_file.write()
+
+        return True
+
+    #------------------------------------------------------------
+    def _collect_files_compress(self, oldfiles, compress_extension, cur_desc_index):
+        '''
+        Collects a list with all old logfiles, they have to compress.
+
+        @param oldfiles: a dict whith all found old logfiles as keys and
+                         their modification time as values
+        @type oldfiles:  dict
+        @param compress_extension: file extension for rotated and
+                                   compressed logfiles
+        @type compress_extension:  str
+        @param cur_desc_index: index of self.config for definition
+                               of logfile from configuration file
+        @type cur_desc_index:  int
+
+        @return: all old (and compressed) logfiles to delete
+        @rtype:  list
+        '''
+
+        definition = self.config[cur_desc_index]
+        _ = self.t.lgettext
+
+        if self.verbose > 2:
+            msg = _("Retrieving logfiles to compress ...")
+            self.logger.debug(msg)
+
+        result = []
+
+        if not definition['compress']:
+            if self.verbose > 3:
+                msg = _("No compression defined.")
+                self.logger.debug(msg)
+            return result
+
+        if not oldfiles.keys():
+            if self.verbose > 3:
+                msg = _("No old logfiles available.")
+                self.logger.debug(msg)
+            return result
+
+        no_compress = definition['delaycompress']
+        if no_compress is None:
+            no_compress = 0
+
+        ce = re.escape(compress_extension)
+        for oldfile in sorted(oldfiles.keys(), key=lambda x: oldfiles[x], reverse=True):
+
+            match = re.search(ce + r'$', oldfile)
+            if match:
+                if self.verbose > 2:
+                    msg = _("File '%s' seems to be compressed, skip it.") % (oldfile)
+                    self.logger.debug(msg)
+                continue
+
+            if oldfile in self.files_delete:
+                if self.verbose > 2:
+                    msg = _("File '%s' will be deleted, compression unnecessary.") % (oldfile)
+                    self.logger.debug(msg)
+                continue
+
+            if no_compress:
+                if self.verbose > 2:
+                    msg = _("Compression of file '%s' will be delayed.") % (oldfile)
+                    self.logger.debug(msg)
+                no_compress -= 1
+                continue
+
+            result.append(oldfile)
+
+        if self.verbose > 3:
+            if len(result):
+                pp = pprint.PrettyPrinter(indent=4)
+                msg = _("Found logfiles to compress:") + "\n" + pp.pformat(result)
+                self.logger.debug(msg)
+            else:
+                msg = _("No old logfiles to compress found.")
+                self.logger.debug(msg)
+        return result
+
+    #------------------------------------------------------------
+    def _collect_files_delete(self, oldfiles, cur_desc_index):
+        '''
+        Collects a list with all old (and compressed) logfiles, they have to delete.
+
+        @param oldfiles: a dict whith all found old logfiles as keys and
+                        their modification time as values
+        @type oldfiles:  dict
+        @param cur_desc_index: index of self.config for definition
+                               of logfile from configuration file
+        @type cur_desc_index:  int
+
+        @return: all old (and compressed) logfiles to delete
+        @rtype:  list
+        '''
+
+        definition = self.config[cur_desc_index]
+        _ = self.t.lgettext
+
+        if self.verbose > 2:
+            msg = _("Retrieving logfiles to delete ...")
+            self.logger.debug(msg)
+
+        result = []
+
+        if not oldfiles.keys():
+            if self.verbose > 3:
+                msg = _("No old logfiles available.")
+                self.logger.debug(msg)
+            return result
+
+        # Maxage in seconds or None
+        maxage = definition['maxage']
+        if maxage is None:
+            if self.verbose >= 4:
+                msg = _("No maxage given.")
+                self.logger.debug(msg)
+        else:
+            maxage *= (24 * 60 * 60)
+            if self.verbose >= 4:
+                msg = _("Maxage: %d seconds") % (maxage)
+                self.logger.debug(msg)
+
+        # Number of rotations or Zero
+        rotate = definition['rotate']
+        if rotate is None:
+            rotate = 0
+        if self.verbose >= 4:
+            msg = _("Max. count rotations: %d") % (rotate)
+            self.logger.debug(msg)
+
+        count = len(oldfiles.keys())
+        for oldfile in sorted(oldfiles.keys(), key=lambda x: oldfiles[x]):
+            count -= 1
+            age = int(time.time() - oldfiles[oldfile])
+            if self.verbose > 3:
+                msg = _("Checking file '%s' for deleting ...") % (oldfile)
+                self.logger.debug(msg)
+            if self.verbose >= 4:
+                msg = _("Current count: %(count)d, current age: %(age)d seconds") \
+                        % {'count': count, 'age': age}
+                self.logger.debug(msg)
+
+            # Delete all files, their count is more than the rotate option
+            if rotate:
+                if count >= rotate:
+                    if self.verbose >= 3:
+                        msg = _("Deleting '%s' because of too much.") % (oldfile)
+                        self.logger.debug(msg)
+                    result.append(oldfile)
+                    continue
+
+            # Now checking for maximum age
+            if maxage:
+                if age >= maxage:
+                    if self.verbose >= 3:
+                        msg = _("Deleting '%s' because of too old.") % (oldfile)
+                        self.logger.debug(msg)
+                    result.append(oldfile)
+
+        if self.verbose > 3:
+            if len(result):
+                pp = pprint.PrettyPrinter(indent=4)
+                msg = _("Found logfiles to delete:") + "\n" + pp.pformat(result)
+                self.logger.debug(msg)
+            else:
+                msg = _("No old logfiles to delete found.")
+                self.logger.debug(msg)
+        return result
+
+    #------------------------------------------------------------
+    def _collect_old_logfiles(self, logfile, extension, compress_extension, cur_desc_index):
+        '''
+        Collect all rotated versions of this logfile and gives back the
+        information about.
+
+        @param logfile: the logfile to rotate
+        @type logfile:  str
+        @param extension: additional fix file extension for rotated logfiles
+        @type extension:  str
+        @param compress_extension: file extension for rotated and
+                                   compressed logfiles
+        @type compress_extension:  str
+        @param cur_desc_index: index of self.config for definition
+                               of logfile from configuration file
+        @type cur_desc_index:  int
+
+        @return: all found old rotated logfiles as keys
+                 and the last modification timestamp of these files as values
+        @rtype:  dict
+        '''
+
+        definition = self.config[cur_desc_index]
+        _ = self.t.lgettext
+
+        if self.verbose > 2:
+            msg = _("Retrieving all old logfiles for file '%s' ...") % (logfile)
+            self.logger.debug(msg)
+
+        result = {}
+
+        basename = os.path.basename(logfile)
+        dirname  = os.path.dirname(logfile)
+
+        if definition['dateext']:
+            basename += '.*'
+
+        if definition['olddir']['dirname']:
+            # Create a file pattern depending on olddir definition
+
+            olddir = definition['olddir']['dirname']
+
+            # Substitution of $dirname
+            olddir = re.sub(r'(?:\${dirname}|\$dirname(?![a-zA-Z0-9_]))', dirname, olddir)
+
+            # Substitution of $basename
+            olddir = re.sub(r'(?:\${basename}|\$basename(?![a-zA-Z0-9_]))', basename, olddir)
+
+            # Substitution of $nodename
+            olddir = re.sub(r'(?:\${nodename}|\$nodename(?![a-zA-Z0-9_]))', self.template['nodename'], olddir)
+
+            # Substitution of $domain
+            olddir = re.sub(r'(?:\${domain}|\$domain(?![a-zA-Z0-9_]))', self.template['domain'], olddir)
+
+            # Substitution of $machine
+            olddir = re.sub(r'(?:\${machine}|\$machine(?![a-zA-Z0-9_]))', self.template['machine'], olddir)
+
+            # Substitution of $release
+            olddir = re.sub(r'(?:\${release}|\$release(?![a-zA-Z0-9_]))', self.template['release'], olddir)
+
+            # Substitution of $sysname
+            olddir = re.sub(r'(?:\${sysname}|\$sysname(?![a-zA-Z0-9_]))', self.template['sysname'], olddir)
+
+            if not os.path.isabs(olddir):
+                olddir = os.path.join(dirname, olddir)
+            olddir = os.path.normpath(olddir)
+
+            ####
+            # Substituting all datetime.strftime() placeholders by shell pattern
+
+            # weekday
+            olddir = re.sub(r'%[aA]', '*', olddir)
+            # name of month
+            olddir = re.sub(r'%[bBh]', '*', olddir)
+            # complete date
+            olddir = re.sub(r'%c', '*', olddir)
+            # century
+            olddir = re.sub(r'%C', '[0-9][0-9]', olddir)
+            # day of month
+            olddir = re.sub(r'%d', '[0-9][0-9]', olddir)
+            # date as %m/%d/%y
+            olddir = re.sub(r'%[Dx]', '[0-9][0-9]/[0-9][0-9]/[0-9][0-9]', olddir)
+            # Hour in 24-hours format
+            olddir = re.sub(r'%H', '[012][0-9]', olddir)
+            # Hour in 12-hours format
+            olddir = re.sub(r'%J', '[01][0-9]', olddir)
+            # number of month
+            olddir = re.sub(r'%m', '[01][0-9]', olddir)
+            # minute
+            olddir = re.sub(r'%M', '[0-5][0-9]', olddir)
+            # AM/PM
+            olddir = re.sub(r'%p', '[AP]M', olddir)
+            # complete time in 12-hours format with AM/PM
+            olddir = re.sub(r'%r', '[01][0-9]:[0-5][0-9]:[0-5][0-9] [AP]M', olddir)
+            # time in format %H:%M
+            olddir = re.sub(r'%R', '[012][0-9]:[0-5][0-9]', olddir)
+            # seconds
+            olddir = re.sub(r'%S', '[0-5][0-9]', olddir)
+            # complete time in 24-hours format
+            olddir = re.sub(r'%[TX]', '[012][0-9]:[0-5][0-9]:[0-5][0-9]', olddir)
+            # weekday as a number (0-7)
+            olddir = re.sub(r'%[uw]', '[0-7]', olddir)
+            # number of week in year (00-53)
+            olddir = re.sub(r'%[UVW]', '[0-5][0-9]', olddir)
+            # last two digits of the year
+            olddir = re.sub(r'%y', '[0-9][0-9]', olddir)
+            # year complete
+            olddir = re.sub(r'%Y', '[12][0-9][0-9][0-9]', olddir)
+            # time zone numeric
+            olddir = re.sub(r'%z', '[-+][0-9][0-9][0-9][0-9]', olddir)
+            # time zone name
+            olddir = re.sub(r'%Z', '*', olddir)
+
+            dirname = olddir
+
+        # composing file pattern
+        file_pattern = os.path.join(dirname, basename)
+        pattern_list = []
+        pattern_list.append(file_pattern + extension)
+        pattern_list.append(file_pattern + '.[0-9]' + extension)
+        pattern_list.append(file_pattern + '.[0-9][0-9]' + extension)
+        pattern_list.append(file_pattern + '.[0-9][0-9][0-9]' + extension)
+        pattern_list.append(file_pattern + '.[0-9][0-9][0-9][0-9]' + extension)
+        pattern_list.append(file_pattern + '.[0-9][0-9][0-9][0-9][0-9]' + extension)
+
+        if definition['compress']:
+            ext = extension + compress_extension
+            pattern_list.append(file_pattern + ext)
+            pattern_list.append(file_pattern + '.[0-9]' + ext)
+            pattern_list.append(file_pattern + '.[0-9][0-9]' + ext)
+            pattern_list.append(file_pattern + '.[0-9][0-9][0-9]' + ext)
+            pattern_list.append(file_pattern + '.[0-9][0-9][0-9][0-9]' + ext)
+            pattern_list.append(file_pattern + '.[0-9][0-9][0-9][0-9][0-9]' + ext)
+
+        for pattern in pattern_list:
+            if self.verbose > 2:
+                msg = _("Search for pattern '%s' ...") % (pattern)
+                self.logger.debug(msg)
+            found_files = glob.glob(pattern) 
+            for oldfile in found_files:
+                oldfile = os.path.abspath(oldfile)
+                if oldfile == logfile:
+                    continue
+                statinfo = os.stat(oldfile)
+                result[oldfile] = statinfo.st_mtime
+
+        if self.verbose > 3:
+            pp = pprint.PrettyPrinter(indent=4)
+            msg = _("Found old logfiles:") + "\n" + pp.pformat(result)
+            self.logger.debug(msg)
+        return result
+
+    #------------------------------------------------------------
+    def _get_rotations(self, logfile, target, cur_desc_index):
+        '''
+        Retrieves all files to move and to rotate and gives them back
+        as a dict.
+
+        @param logfile: the logfile to rotate
+        @type logfile:  str
+        @param target:  name of the rotated logfile
+        @type target:   str
+        @param cur_desc_index: index of self.config for definition
+                               of logfile from configuration file
+        @type cur_desc_index:  int
+
+        @return: dict in the form::
+                    {
+                        'compress_extension': '.gz',
+                        'extension': '',
+                        'rotate': {
+                            'from': <file>,
+                            'to': <target>
+                        },
+                        'move': [
+                            ...
+                            { 'from': <file2>, 'to': <file3>, 'compressed': True},
+                            { 'from': <file1>, 'to': <file2>, 'compressed': True},
+                            { 'from': <file0>, 'to': <file1>, 'compressed': False},
+                        ],
+                    }
+
+                 the order in the list 'move' is the order, how the
+                 files have to rename.
+        @rtype: dict
+        '''
+
+        definition = self.config[cur_desc_index]
+        _ = self.t.lgettext
+
+        if self.verbose > 2:
+            msg = _("Retrieving all movings and rotations for logfile '%(file)s' to target '%(target)s' ...") \
+                    % {'file': logfile, 'target': target}
+            self.logger.debug(msg)
+
+        result = { 'rotate': {}, 'move': [] }
+
+        # retrieve additional file extension of logfile after rotation
+        # without compress extension
+        extension = definition['extension']
+        if extension is None:
+            extension = ''
+        match = re.search(r'^\s*$', extension)
+        if match:
+            extension = ''
+        if extension != '':
+            match = re.search(r'^\.', extension)
+            if not match:
+                extension = "." + extension
+        result['extension'] = extension
+        extension_wo_compress = extension
+
+        # retrieve additional file extension of logfile after rotation
+        # for compress extension
+        compress_extension = ''
+        if definition['compress']:
+            compress_extension = definition['compressext']
+            match = re.search(r'^\.', compress_extension)
+            if not match:
+                compress_extension = "." + compress_extension
+        result['compress_extension'] = compress_extension
+
+        # appending a trailing '.0', if there are no other differences
+        # between logfile and target
+        i = definition['start']
+        if i is None:
+            i = 0
+        resulting_target = target + extension_wo_compress
+        target_wo_number = resulting_target
+        if resulting_target == logfile:
+            resulting_target = resulting_target + "." + str(i)
+
+        result['rotate']['from'] = logfile
+        result['rotate']['to']   = resulting_target
+
+        # resulting target exists, retrieve cyclic rotation
+        if os.path.exists(resulting_target):
+            if self.verbose > 3:
+                msg = _("Resulting target '%s' exists, retrieve cyclic rotation ...") \
+                        % (resulting_target)
+                self.logger.debug(msg)
+            target_wo_cext_old = target_wo_number + "." + str(i)
+            target_with_cext_old = target_wo_cext_old + compress_extension
+            while os.path.exists(target_wo_cext_old) or os.path.exists(target_with_cext_old):
+                i += 1
+                target_wo_cext_new = target_wo_number + "." + str(i)
+                target_with_cext_new = target_wo_cext_new + compress_extension
+                if self.verbose > 4:
+                    msg = _("Cyclic rotation from '%(from)s' to '%(to)s'.") \
+                            % {'from': target_wo_cext_old, 'to': target_wo_cext_new}
+                    self.logger.debug(msg)
+                pair = {
+                    'from': target_wo_cext_old,
+                    'to': target_wo_cext_new,
+                    'compressed': False,
+                }
+                if definition['compress']:
+                    if os.path.exists(target_with_cext_old):
+                        pair['compressed'] = True
+                result['move'].insert(0, pair)
+                target_wo_cext_old = target_wo_cext_new
+                target_with_cext_old = target_with_cext_new
+
+        if self.verbose > 3:
+            pp = pprint.PrettyPrinter(indent=4)
+            msg = _("Found rotations:") + "\n" + pp.pformat(result)
+            self.logger.debug(msg)
+        return result
+
+    #------------------------------------------------------------
+    def _get_rotation_target(self, logfile, cur_desc_index, olddir = None):
+        '''
+        Retrieves the name of the rotated logfile and gives it back.
+
+        @param logfile: the logfile to rotate
+        @type logfile:  str
+        @param cur_desc_index: index of self.config for definition
+                               of logfile from configuration file
+        @type cur_desc_index:  int
+        @param olddir: the directory of the rotated logfile
+                       if None, store the rotated logfile
+                       in their original directory
+        @type olddir: str or None
+
+        @return: name of the rotated logfile
+        @rtype:  str
+        '''
+
+        definition = self.config[cur_desc_index]
+
+        _ = self.t.lgettext
+
+        if self.verbose > 2:
+            msg = _("Retrieving the name of the rotated file of '%s' ...") % (logfile)
+            self.logger.debug(msg)
+
+        target = logfile
+        if olddir is not None:
+            basename = os.path.basename(logfile)
+            target = os.path.join(olddir, basename)
+
+        if definition['dateext']:
+            pattern = definition['datepattern']
+            if pattern is None:
+                pattern = '%Y-%m-%d'
+            dateext = datetime.utcnow().strftime(pattern)
+            if self.verbose > 3:
+                msg = _("Using date extension '.%(ext)s' from pattern '%(pattern)s'.") \
+                        % {'ext': dateext, 'pattern': pattern}
+                self.logger.debug(msg)
+            target += "." + dateext
+
+        if self.verbose > 1:
+            msg = _("Using '%(target)s' as target for rotation of logfile '%(logfile)s'.") \
+                    % {'target': target, 'logfile': logfile}
+            self.logger.debug(msg)
+        return target
+
+    #------------------------------------------------------------
+    def _create_olddir(self, logfile, cur_desc_index):
+        '''
+        Creating the olddir, if necessary.
+
+        @param logfile: the logfile to rotate
+        @type logfile:  str
+        @param cur_desc_index: index of self.config for definition
+                               of logfile from configuration file
+        @type cur_desc_index:  int
+
+        @return: Name of the retrieved olddir, ".", if storing
+                 the rotated logfiles in their original directory or
+                 None in case of some minor errors (olddir couldn't
+                 created a.s.o.)
+        @rtype:  str or None
+        '''
+
+        definition = self.config[cur_desc_index]
+
+        _ = self.t.lgettext
+
+        uid = os.geteuid()
+        gid = os.getegid()
+
+        o = definition['olddir']
+        if not o['dirname']:
+            if self.verbose > 1:
+                msg = _("No dirname directive for olddir given.")
+                self.logger.debug(msg)
+            return "."
+        olddir = o['dirname']
+
+        mode = o['mode']
+        if mode is None:
+            mode = int('0755', 8)
+        owner = o['owner']
+        if not owner:
+            owner = uid
+        group = o['group']
+        if not group:
+            group = gid
+
+        basename = os.path.basename(logfile)
+        dirname  = os.path.dirname(logfile)
+
+        match = re.search(r'%', olddir)
+        if match:
+            o['dateformat'] = True
+            olddir = datetime.utcnow().strftime(olddir)
+
+        # Substitution of $dirname
+        olddir = re.sub(r'(?:\${dirname}|\$dirname(?![a-zA-Z0-9_]))', dirname, olddir)
+
+        # Substitution of $basename
+        olddir = re.sub(r'(?:\${basename}|\$basename(?![a-zA-Z0-9_]))', basename, olddir)
+
+        # Substitution of $nodename
+        olddir = re.sub(r'(?:\${nodename}|\$nodename(?![a-zA-Z0-9_]))', self.template['nodename'], olddir)
+
+        # Substitution of $domain
+        olddir = re.sub(r'(?:\${domain}|\$domain(?![a-zA-Z0-9_]))', self.template['domain'], olddir)
+
+        # Substitution of $machine
+        olddir = re.sub(r'(?:\${machine}|\$machine(?![a-zA-Z0-9_]))', self.template['machine'], olddir)
+
+        # Substitution of $release
+        olddir = re.sub(r'(?:\${release}|\$release(?![a-zA-Z0-9_]))', self.template['release'], olddir)
+
+        # Substitution of $sysname
+        olddir = re.sub(r'(?:\${sysname}|\$sysname(?![a-zA-Z0-9_]))', self.template['sysname'], olddir)
+
+        if not os.path.isabs(olddir):
+            olddir = os.path.join(dirname, olddir)
+        olddir = os.path.normpath(olddir)
+
+        if self.verbose > 1:
+            msg = _("Olddir name is now '%s'") % (olddir)
+            self.logger.debug(msg)
+
+        # Check for Existence and Consistence
+        if os.path.exists(olddir):
+            if os.path.isdir(olddir):
+                if os.access(olddir, (os.W_OK | os.X_OK)):
+                    if self.verbose > 2:
+                        msg = _("Olddir '%s' allready exists, not created.") % (olddir)
+                        self.logger.debug(msg)
+                    olddir = os.path.realpath(olddir)
+                    return olddir
+                else:
+                    msg = _("No write and execute access to olddir '%s'.") % (olddir)
+                    if self.test:
+                        self.logger.warning(msg)
+                        return olddir
+                    raise LogrotateHandlerError(msg)
+                    return None
+            else:
+                msg = _("Olddir '%s' exists, but is not a valid directory.") % (olddir)
+                raise LogrotateHandlerError(msg)
+                return None
+
+        dirs = []
+        dir_head = olddir
+        while dir_head != os.sep:
+            (dir_head, dir_tail) = os.path.split(dir_head)
+            dirs.insert(0, dir_tail)
+        if self.verbose > 2:
+            msg = _("Directory chain to create: '%s'") % (str(dirs))
+            self.logger.debug(msg)
+
+        # Create olddir recursive, if necessary
+        msg = _("Creating olddir '%s' recursive ...") % (olddir)
+        self.logger.info(msg)
+        create_dir = None
+        parent_statinfo = os.stat(os.sep)
+        parent_mode = parent_statinfo.st_mode
+        parent_uid  = parent_statinfo.st_uid
+        parent_gid  = parent_statinfo.st_gid
+        while len(dirs):
+            dir_head = dirs.pop(0)
+            if create_dir:
+                create_dir = os.path.join(create_dir, dir_head)
+            else:
+                create_dir = os.sep + dir_head
+            if self.verbose > 3:
+                msg = _("Try to create directory '%s' ...") % (create_dir)
+                self.logger.debug(msg)
+            if os.path.exists(create_dir):
+                if os.path.isdir(create_dir):
+                    if self.verbose > 3:
+                        msg = _("Directory '%s' allready exists, not created.") % (create_dir)
+                        self.logger.debug(msg)
+                    parent_statinfo = os.stat(create_dir)
+                    parent_mode = parent_statinfo.st_mode
+                    parent_uid  = parent_statinfo.st_uid
+                    parent_gid  = parent_statinfo.st_gid
+                    continue
+                else:
+                    msg = _("Directory '%s' exists, but is not a valid directory.") % (create_dir)
+                    self.logger.error(msg)
+                    return None
+            msg = _("Creating directory '%s' ...") % (create_dir)
+            self.logger.debug(msg)
+            create_mode = parent_mode
+            if o['mode'] is not None:
+                create_mode = o['mode']
+            create_uid = parent_uid
+            if o['owner'] is not None:
+                create_uid = o['owner']
+            create_gid = parent_gid
+            if o['group'] is not None:
+                create_gid = o['group']
+            if self.verbose > 1:
+                msg = _("Create permissions: %(mode)4o, Owner-UID: %(uid)d, Group-GID: %(gid)d") \
+                        % {'mode': create_mode, 'uid': create_uid, 'gid': create_gid}
+                self.logger.debug(msg)
+            if not self.test:
+                if self.verbose > 2:
+                    msg = "os.mkdir('%s', %4o)" % (create_dir, create_mode)
+                    self.logger.debug(msg)
+                try:
+                    os.mkdir(create_dir, create_mode)
+                except OSError, e:
+                    msg = _("Error on creating directory '%(dir)s': %(err)s") \
+                            % {'dir': create_dir, 'err': e.strerror}
+                    self.logger.error(msg)
+                    return None
+                if (create_uid != uid) or (create_gid != gid):
+                    myuid = os.geteuid()
+                    if myuid != 0:
+                        msg = _("Only root may execute chown().")
+                        if self.test:
+                            self.logger.info(msg)
+                        else:
+                            self.logger.warning(msg)
+                    else:
+                        if self.verbose > 2:
+                            msg = "os.chown('%s', %d, %d)" % (create_dir, create_uid, create_gid)
+                            self.logger.debug(msg)
+                        try:
+                            os.chown(create_dir, create_uid, create_gid)
+                        except OSError, e:
+                            msg = _("Error on chowning directory '%(dir)s': %(err)s") \
+                                    % {'dir': create_dir, 'err': e.strerror}
+                            self.logger.error(msg)
+                            return None
+
+        olddir = os.path.realpath(olddir)
+        return olddir
+
+    #------------------------------------------------------------
+    def _execute_command(self, command, force=False, expected_retcode=0):
+        '''
+        Executes the given command as an OS command in a shell.
+
+        @param command: the command to execute
+        @type command:  str
+        @param force:   force executing command even if self.test == True
+        @type force:    bool
+        @param expected_retcode: expected returncode of the command
+                                 (should be 0)
+        @type expected_retcode:  int
+
+        @return: Success of the comand (shell returncode == 0)
+        @rtype:  bool
+        '''
+
+        _ = self.t.lgettext
+        if self.verbose > 3:
+            msg = _("Executing command: '%s'") % (command)
+            self.logger.debug(msg)
+        if not force:
+            if self.test:
+                return True
+        try:
+            retcode = subprocess.call(command, shell=True)
+            if self.verbose > 3:
+                msg = _("Got returncode: '%s'") % (retcode)
+                self.logger.debug(msg)
+            if retcode < 0:
+                msg = _("Child was terminated by signal %d") % (-retcode)
+                self.logger.error(msg)
+                return False
+            if retcode != expected_retcode:
+                return False
+            return True
+        except OSError, e:
+            msg = _("Execution failed: %s") % (str(e))
+            self.logger.error(msg)
+            return False
+
+        return False
+
+    #------------------------------------------------------------
+    def _should_rotate(self, logfile, cur_desc_index):
+        '''
+        Determines, whether a logfile should rotated dependend on
+        the informations in the definition.
+
+        Throughs an LogrotateHandlerError on harder errors.
+
+        @param logfile: the logfile to inspect
+        @type logfile:  str
+        @param cur_desc_index: index of self.config for definition
+                               of logfile from configuration file
+        @type cur_desc_index:  int
+
+        @return: to rotate or not
+        @rtype:  bool
+        '''
+
+        definition = self.config[cur_desc_index]
+
+        _ = self.t.lgettext
+
+        if self.verbose > 2:
+            msg = _("Check, whether logfile '%s' should rotated.") % (logfile)
+            self.logger.debug(msg)
+
+        if not os.path.exists(logfile):
+            msg = _("logfile '%s' doesn't exists, not rotated") % (logfile)
+            if not definition['missingok']:
+                self.logger.error(msg)
+            else:
+                if self.verbose > 1:
+                    self.logger.debug(msg)
+            return False
+
+        if not os.path.isfile(logfile):
+            msg = _("logfile '%s' is not a regular file, not rotated") % (logfile)
+            self.logger.warning(msg)
+            return False
+
+        filesize = os.path.getsize(logfile)
+        if self.verbose > 2:
+            msg = _("Filesize of '%(file)s': %(size)d") % {'file': logfile, 'size': filesize}
+            self.logger.debug(msg)
+
+        if not filesize:
+            if not definition['ifempty']:
+                if self.verbose > 1:
+                    msg = _("Logfile '%s' has a filesize of Zero, not rotated") % (logfile)
+                    self.logger.debug(msg)
+                return False
+
+        if self.force:
+            if self.verbose > 1:
+                msg = _("Rotating of '%s' because of force mode.") % (logfile)
+                self.logger.debug(msg)
+            return True
+
+        maxsize = definition['size']
+        if maxsize is None:
+            maxsize = 0
+
+        last_rotated = self.state_file.get_rotation_date(logfile)
+        if self.verbose > 2:
+            msg = _("Date of last rotation: %s") %(last_rotated.isoformat(' '))
+            self.logger.debug(msg)
+        next_rotation = last_rotated + timedelta(days = definition['period'])
+        if self.verbose > 2:
+            msg = _("Date of next rotation: %s") %(next_rotation.isoformat(' '))
+            self.logger.debug(msg)
+
+        if filesize < maxsize:
+            if self.verbose > 1:
+                msg = _("Filesize %(filesize)d is less than %(maxsize)d, rotation not necessary.") \
+                        % {'filesize': filesize, 'maxsize': maxsize}
+                self.logger.debug(msg)
+            return False
+
+        curdate = datetime.utcnow().replace(tzinfo = utc)
+        if next_rotation > curdate:
+            if self.verbose > 1:
+                msg = _("Date of next rotation '%(next)s' is in future, rotation not necessary.") \
+                        % {'next': next_rotation.isoformat(' ')}
+                self.logger.debug(msg)
+            return False
+
+        return True
+
+    #------------------------------------------------------------
+    def delete_oldfiles(self):
+        '''
+        Deleting of all logfiles in self.files_delete
+
+        @return: None
+        '''
+
+        _ = self.t.lgettext
+
+        msg = _("Deletion of all superfluid logfiles ...")
+        self.logger.debug(msg)
+
+        if not len(self.files_delete.keys()):
+            msg = _("No logfiles to delete found.")
+            self.logger.info(msg)
+
+        for logfile in sorted(self.files_delete.keys(), key=str.lower):
+            msg = _("Deleting file '%s' ...") % (logfile)
+            self.logger.info(msg)
+            if not self.test:
+                try:
+                    os.remove(logfile)
+                except OSError, e:
+                    msg = _("Error on removing file '%(file)s': %(err)s") \
+                            % {'file': logfile, 'err': e.strerror}
+                    self.logger.error(msg)
+
+        return
+
+    #------------------------------------------------------------
+    def compress(self):
+        '''
+        Compressing all logfiles in self.files_compress
+
+        @return: None
+        '''
+
+        _ = self.t.lgettext
+
+        msg = _("Compression of all uncompressed logfiles ...")
+        self.logger.debug(msg)
+
+        if not len(self.files_compress.keys()):
+            msg = _("No logfiles to compress found.")
+            self.logger.info(msg)
+
+        for logfile in sorted(self.files_compress.keys(), key=str.lower):
+
+            cur_desc_index = self.files_compress[logfile]
+            definition = self.config[cur_desc_index]
+            command = definition['compresscmd']
+            compress_extension = definition['compressext']
+            compress_opts = definition['compressoptions']
+
+            match = re.search(r'^\.', compress_extension)
+            if not match:
+                compress_extension = "." + compress_extension
+            target = logfile + compress_extension
+
+            # Check existence source logfile
+            if not os.path.exists(logfile):
+                msg = _("Source file '%s' for compression doesn't exists.") % (logfile)
+                raise LogrotateHandlerError(msg)
+                return
+
+            # Check existence target (compressed file)
+            if os.path.exists(target):
+                if os.path.samefile(logfile, target):
+                    msg = _("Source file '%(source)s' and target file '%(target)s' are the same file.") \
+                            % {'source': logfile, 'target': target}
+                    raise LogrotateHandlerError(msg)
+                    return
+                msg = _("Target file '%s' for compression allready exists.") %(target)
+                self.logger.warning(msg)
+
+            # Check for filesize Zero => not compressed
+            filesize = os.path.getsize(logfile)
+            if filesize <= 0:
+                msg = _("File '%s' has a size of 0, skip compressing.") % (logfile)
+                self.logger.info(msg)
+                continue
+
+            # Execute compressing ...
+            msg = _("Compressing file '%(file)s' to '%(target)s' with '%(cmd)s' ...") \
+                    % {'file': logfile, 'target': target, 'cmd': command}
+            self.logger.info(msg)
+
+            if command == 'internal_gzip':
+                self._compress_internal_gzip(logfile, target)
+            elif command == 'internal_bzip2':
+                self._compress_internal_bzip2(logfile, target)
+            elif command == 'internal_zip':
+                self._compress_internal_zip(logfile, target)
+            else:
+                self._compress_external(logfile, target, command, compress_opts)
+
+        return
+
+    #------------------------------------------------------------
+    def _compress_external(self, source, target, command, options):
+        '''
+        Compression of the given source file to the target file
+        with an external command.
+
+        It raises a LogrotateHandlerError on uncoverable errors.
+
+        @param source: the source file to compress
+        @type source:  str
+        @param target: the filename of the compressed file.
+        @type target:  str
+        @param command: the OS command to use to compress
+        @type command:  str
+        @param options: additional options to the compress command
+                        possible placeholders inside the options:
+                            - {}: placeholder for sourcefile
+                            - []: placeholder for targetfile
+        @type options:  str
+
+        @return: success or not
+        @rtype:  bool
+        '''
+
+        _ = self.t.lgettext
+
+        if self.verbose > 1:
+            msg = _("Compressing source '%(source)s' to target'%(target)s' with command '%(cmd)s'.") \
+                    % {'source': source, 'target': target, 'cmd': command}
+            self.logger.debug(msg)
+
+        if options is None:
+            options = ''
+
+        # substituting [] in compressoptions with qouted target file name
+        match = re.search(r'\[\]', options)
+        if match:
+            if self.verbose > 3:
+                msg = _("Substituting '[]' in compressoptions with '%s'.") % ('"' + target + '"')
+                self.logger.debug(msg)
+            options = re.sub(r'\[\]', '"' + target + '"', options)
+
+        # substituting or trailing command with quoted source file name
+        match = re.search(r'\{\}', options)
+        if match:
+            if self.verbose > 3:
+                msg = _("Substituting '{}' in compressoptions with '%s'.") % ('"' + source + '"')
+                self.logger.debug(msg)
+            options = re.sub(r'\{\}', '"' + source + '"', options)
+        else:
+            options += ' "' + source + '"'
+
+        if self.verbose > 2:
+            msg = _("Compress options: '%s'.") % (options)
+            self.logger.debug(msg)
+
+        cmd = command + ' ' + options
+
+        src_statinfo = os.stat(source)
+
+        if not self._execute_command(cmd):
+            return False
+
+        if not self.test:
+            if not os.path.exists(target):
+                msg = _("Target '%s' of compression doesn't exists after executing compression command.") \
+                        % (target)
+                self.logger.error(msg)
+                return False
+
+        if os.path.exists(source):
+
+            self._copy_file_metadata(source=source, target=target)
+
+            # And last, but not least, delete uncompressed file
+            if self.verbose > 1:
+                msg = _("Deleting uncompressed file '%s' ...") % (source)
+                self.logger.debug(msg)
+
+            if not self.test:
+                try:
+                    os.remove(source)
+                except OSError, e:
+                    msg = _("Error removing uncompressed file '%(file)s': %(msg)") \
+                            % {'file': source, 'msg': str(e) }
+                    self.logger.error(msg)
+                    return False
+
+        else:
+
+            self._copy_file_metadata(target=target, statinfo=src_statinfo)
+
+        return True
+    #------------------------------------------------------------
+    def _copy_file_metadata(self, target, source=None, statinfo=None):
+        '''
+        Copy all metadata (owner, permissions, timestamps a.s.o) from
+        a source file onto a target file.
+        The target file must be exists.
+        Either an existing source file (parameter 'source') or the
+        statinfo of a former existing file (parameter 'statinfo') must
+        be given.
+
+        It raises a LogrotateHandlerError on uncoverable errors.
+
+        @param target: filename of an existing target file or directory
+        @type target:  str
+        @param source: filename of an existing source file or directory
+                       or None, if statinfo was given,
+                       has precedence before a given statinfo
+        @type source:  str or None
+        @param statinfo: stat object from os.stat() or None, if source was given
+        @type statinfo:  stat-object or None
+
+        @return: success or not
+        @rtype:  bool
+        '''
+
+        _ = self.t.lgettext
+
+        if source is None and statinfo is None:
+            msg = _("Neither 'target' nor 'statinfo' was given on calling _copy_file_metadata().")
+            raise LogrotateHandlerError(msg)
+            return False
+
+        if not os.path.exists(target):
+            msg = _("File or directory '%s' doesn't exists.") % (target)
+            if self.test:
+                self.logger.info(msg)
+                return True
+            self.logger.error(msg)
+            return False
+
+        new_statinfo = statinfo
+        old_statinfo = os.stat(target)
+
+        msg = _("Copying all file metadata to target '%s' ...") % (target)
+        self.logger.info(msg)
+
+        if source is not None:
+
+            # a source object was given
+
+            if not os.path.exists(source):
+                msg = _("File or directory '%s' doesn't exists.") % (source)
+                self.logger.error(msg)
+                return False
+
+            new_statinfo = os.stat(source)
+
+            # Copying permissions and timestamps from source to target
+            if self.verbose > 1:
+                msg = _("Copying permissions and timestamps from source '%(src)s' to target '%(target)s'.") \
+                        % {'src': source, 'target': target}
+                self.logger.debug(msg)
+            if not self.test:
+                shutil.copystat(source, target)
+
+        else:
+
+            # a source statinfo was given
+
+            atime = new_statinfo.st_atime
+            mtime = new_statinfo.st_mtime
+            mode  = new_statinfo.st_mode
+
+            # Setting atime and mtime
+            if self.verbose > 1:
+                msg = _("Setting atime and mtime of target '%s'.") % (target)
+                self.logger.debug(msg)
+            if not self.test:
+                try:
+                    os.utime(target, (atime, mtime))
+                except OSError, e:
+                    msg = _("Error on setting times on target file '%(target)s': %(err)s") \
+                            % {'target': target, 'err': e.strerror}
+                    self.logger.warning(msg)
+                    return False
+
+            # Setting permissions
+            old_mode = old_statinfo.st_mode
+            if mode != old_mode:
+                if self.verbose > 1:
+                    msg = _("Setting permissions of '%(target)s' to %(mode)4o.") \
+                            % {'target': target, 'mode': new_mode}
+                    self.logger.info(msg)
+                if not self.test:
+                    try:
+                        os.chmod(target, mode)
+                    except OSError, e:
+                        msg = _("Error on chmod of '%(target)s': %(err)s") \
+                                % {'target': target, 'err': e.strerror}
+                        self.logger.warning(msg)
+                        return False
+
+        # Copying ownership from source to target
+        new_uid = new_statinfo.st_uid
+        new_gid = new_statinfo.st_gid
+        old_uid = old_statinfo.st_uid
+        old_gid = old_statinfo.st_gid
+
+        if (old_uid != new_uid) or (old_gid != new_gid):
+            if self.verbose > 1:
+                msg = _("Copying ownership from source to target.")
+                self.logger.debug(msg)
+            myuid = os.geteuid()
+            if myuid != 0:
+                msg = _("Only root may execute chown().")
+                if self.test:
+                    self.logger.info(msg)
+                    return True
+                else:
+                    self.logger.warning(msg)
+                    return False
+            if not self.test:
+                try:
+                    os.chown(target, old_uid, old_gid)
+                except OSError, e:
+                    msg = _("Error on chown of '%(file)s': %(err)s") \
+                            % {'file': target, 'err': e.strerror}
+                    self.logger.warning(msg)
+                    return False
+
+        return True
+
+    #------------------------------------------------------------
+    def _compress_internal_zip(self, source, target):
+        '''
+        Compression of the given source file to the target file
+        with the Python module zipfile.
+
+        It raises a LogrotateHandlerError on some errors.
+
+        @param source: the source file to compress
+        @type source:  str
+        @param target: the filename of the compressed file.
+        @type target:  str
+
+        @return: success or not
+        @rtype:  bool
+        '''
+
+        _ = self.t.lgettext
+
+        if self.verbose > 1:
+            msg = _("Compressing source '%(source)s' to target'%(target)s' with module zipfile.") \
+                    % {'source': source, 'target': target}
+            self.logger.debug(msg)
+
+        if not self.test:
+
+            # open target for writing
+            f_out = None
+            try:
+                f_out = zipfile.ZipFile(
+                            file=target,
+                            mode='w',
+                            compression=zipfile.ZIP_DEFLATED
+                )
+            except IOError, e:
+                msg = _("Error on open file '%(file)s' on writing: %(err)s") \
+                        % {'file': target, 'err': str(e)}
+                self.logger.error(msg)
+                return False
+
+            basename = os.path.basename(source)
+            f_out.write(source, basename)
+            f_out.close()
+
+        self._copy_file_metadata(source=source, target=target)
+
+        # And last, but not least, delete uncompressed file
+        if self.verbose > 1:
+            msg = _("Deleting uncompressed file '%s' ...") % (source)
+            self.logger.debug(msg)
+
+        if not self.test:
+            try:
+                os.remove(source)
+            except OSError, e:
+                msg = _("Error removing uncompressed file '%(file)s': %(msg)") \
+                        % {'file': source, 'msg': str(e) }
+                self.logger.error(msg)
+                return False
+
+        return True
+
+    #------------------------------------------------------------
+    def _compress_internal_gzip(self, source, target):
+        '''
+        Compression of the given source file to the target file
+        with the Python module gzip.
+        As compression level is allways used 9 (highest compression).
+
+        It raises a LogrotateHandlerError on some errors.
+
+        @param source: the source file to compress
+        @type source:  str
+        @param target: the filename of the compressed file.
+        @type target:  str
+
+        @return: success or not
+        @rtype:  bool
+        '''
+
+        _ = self.t.lgettext
+
+        if self.verbose > 1:
+            msg = _("Compressing source '%(source)s' to target'%(target)s' with module gzip.") \
+                    % {'source': source, 'target': target}
+            self.logger.debug(msg)
+
+        if not self.test:
+            # open source for reading
+            f_in = None
+            try:
+                f_in = open(source, 'rb')
+            except IOError, e:
+                msg = _("Error on open file '%(file)s' on reading: %(err)s") \
+                        % {'file': source, 'err': str(e)}
+                self.logger.error(msg)
+                return False
+
+            # open target for writing
+            f_out = None
+            try:
+                f_out = gzip.open(target, 'wb')
+            except IOError, e:
+                msg = _("Error on open file '%(file)s' on writing: %(err)s") \
+                        % {'file': target, 'err': str(e)}
+                self.logger.error(msg)
+                f_in.close()
+                return False
+
+            # compress and write target
+            f_out.writelines(f_in)
+            # close both files
+            f_out.close()
+            f_in.close()
+
+        self._copy_file_metadata(source=source, target=target)
+
+        # And last, but not least, delete uncompressed file
+        if self.verbose > 1:
+            msg = _("Deleting uncompressed file '%s' ...") % (source)
+            self.logger.debug(msg)
+
+        if not self.test:
+            try:
+                os.remove(source)
+            except OSError, e:
+                msg = _("Error removing uncompressed file '%(file)s': %(msg)") \
+                        % {'file': source, 'msg': str(e) }
+                self.logger.error(msg)
+                return False
+
+        return True
+
+    #------------------------------------------------------------
+    def _compress_internal_bzip2(self, source, target):
+        '''
+        Compression of the given source file to the target file
+        with the Python module bz2.
+        As compression level is allways used 9 (highest compression).
+
+        It raises a LogrotateHandlerError on some errors.
+
+        @param source: the source file to compress
+        @type source:  str
+        @param target: the filename of the compressed file.
+        @type target:  str
+
+        @return: success or not
+        @rtype:  bool
+        '''
+
+        _ = self.t.lgettext
+
+        if self.verbose > 1:
+            msg = _("Compressing source '%(source)s' to target'%(target)s' with module bz2.") \
+                    % {'source': source, 'target': target}
+            self.logger.debug(msg)
+
+        if not self.test:
+            # open source for reading
+            f_in = None
+            try:
+                f_in = open(source, 'rb')
+            except IOError, e:
+                msg = _("Error on open file '%(file)s' on reading: %(err)s") \
+                        % {'file': source, 'err': str(e)}
+                self.logger.error(msg)
+                return False
+
+            # open target for writing
+            f_out = None
+            try:
+                f_out = bz2.BZ2File(target, 'w')
+            except IOError, e:
+                msg = _("Error on open file '%(file)s' on writing: %(err)s") \
+                        % {'file': target, 'err': str(e)}
+                self.logger.error(msg)
+                f_in.close()
+                return False
+
+            # compress and write target
+            f_out.writelines(f_in)
+            # close both files
+            f_out.close()
+            f_in.close()
+
+        self._copy_file_metadata(source=source, target=target)
+
+        # And last, but not least, delete uncompressed file
+        if self.verbose > 1:
+            msg = _("Deleting uncompressed file '%s' ...") % (source)
+            self.logger.debug(msg)
+
+        if not self.test:
+            try:
+                os.remove(source)
+            except OSError, e:
+                msg = _("Error removing uncompressed file '%(file)s': %(msg)") \
+                        % {'file': source, 'msg': str(e) }
+                self.logger.error(msg)
+                return False
+
+        return True
+
+
+    #------------------------------------------------------------
+    def send_logfiles(self):
+        '''
+        Sending all mails, they should be sent, to their recipients.
+        '''
+
+        _ = self.t.lgettext
+
+        if self.verbose > 1:
+            pp = pprint.PrettyPrinter(indent=4)
+            msg = _("Struct files2send:") + "\n" + pp.pformat(self.files2send)
+            self.logger.debug(msg)
+
+        for filename in self.files2send.keys():
+            self.mailer.send_file(filename, self.files2send[filename][0], self.files2send[filename][1])
+
+        return
+
+#========================================================================
+
+if __name__ == "__main__":
+    pass
+
+
+#========================================================================
+
+# vim: fileencoding=utf-8 filetype=python ts=4 expandtab
diff --git a/LogRotate/LogRotateMailer.py b/LogRotate/LogRotateMailer.py
new file mode 100755 (executable)
index 0000000..9ff2628
--- /dev/null
@@ -0,0 +1,574 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# $Id$
+# $URL$
+
+'''
+@author: Frank Brehm
+@contact: frank@brehm-online.com
+@license: GPL3
+@copyright: (c) 2010-2011 by Frank Brehm, Berlin
+@version: 0.0.2
+@summary: module for a logrotate mailer object to send
+          rotated logfiles per mail to a reciepient
+'''
+
+import re
+import logging
+import pprint
+import gettext
+import os
+import os.path
+import sys
+import pwd
+import socket
+import csv
+
+from datetime import datetime
+
+import mimetypes
+import email.utils
+from email import encoders
+from email.message import Message
+from email.mime.base import MIMEBase
+from email.mime.multipart import MIMEMultipart
+from email.mime.nonmultipart import MIMENonMultipart
+from email.mime.text import MIMEText
+
+from quopri import encodestring as _encodestring
+
+from LogRotateCommon import email_valid
+
+revision = '$Revision$'
+revision = re.sub( r'\$', '', revision )
+revision = re.sub( r'Revision: ', r'r', revision )
+revision = re.sub( r'\s*$', '', revision )
+
+__author__    = 'Frank Brehm'
+__copyright__ = '(C) 2011 by Frank Brehm, Berlin'
+__contact__    = 'frank@brehm-online.com'
+__version__    = '0.1.0 ' + revision
+__license__    = 'GPL3'
+
+#========================================================================
+
+class LogRotateMailerError(Exception):
+    '''
+    Base class for exceptions in this module.
+    '''
+
+#========================================================================
+
+class LogRotateMailer(object):
+    '''
+    Class for a mailer object to send
+    rotated logfiles per mail to a reciepient
+
+    @author: Frank Brehm
+    @contact: frank@brehm-online.com
+    '''
+
+    #-------------------------------------------------------
+    def __init__( self, local_dir = None,
+                        verbose   = 0,
+                        test_mode = False,
+                        mailer_version = None,
+    ):
+        '''
+        Constructor.
+
+        @param local_dir:      The directory, where the i18n-files (*.mo)
+                               are located. If None, then system default
+                               (/usr/share/locale) is used.
+        @type local_dir:       str or None
+        @param verbose:        verbosity (debug) level
+        @type verbose:         int
+        @param test_mode:      test mode - no write actions are made
+        @type test_mode:       bool
+        @param mailer_version: version of the X-Mailer tag in the mail header
+        @type mailer_version:  str
+
+        @return: None
+        '''
+
+        self.t = gettext.translation(
+            'LogRotateMailer',
+            local_dir,
+            fallback = True
+        )
+        '''
+        @ivar: a gettext translation object
+        @type: gettext.translation
+        '''
+
+        _ = self.t.lgettext
+
+        self.verbose = verbose
+        '''
+        @ivar: verbosity level (0 - 9)
+        @type: int
+        '''
+
+        self.test_mode = test_mode
+        '''
+        @ivar: test mode - no write actions are made
+        @type: bool
+        '''
+
+        self.logger = logging.getLogger('pylogrotate.mailer')
+        '''
+        @ivar: logger object
+        @type: logging.getLogger
+        '''
+
+        self._sendmail = None
+        '''
+        @ivar: file name of the sendmail executable
+               ('/usr/sbin/sendmail' or '/usr/lib/sendmail')
+               used for sending the mails.
+               if None, the mails will sended via SMTP
+        @type: str or None
+        '''
+        self._init_sendmail()
+
+        self._from_address = ('me', 'info@uhu-banane.de')
+        '''
+        @ivar: Mailaddress of the sender, tuple with the real name of
+               the sender and his mail address as the second value
+        @type: tuple
+        '''
+        self._init_from_address()
+
+        self._smtp_host = 'localhost'
+        '''
+        @ivar: the hostname to use for SMTP (smarthost), if no
+               sendmail binary was found
+        @type: str
+        '''
+
+        self._smtp_port = 25
+        '''
+        @ivar: the port to use for SMTP to the smarthost
+        @type: int
+        '''
+
+        self._smtp_tls  = False
+        '''
+        @ivar: use TLS for sending via SMTP to smarthost
+        @type: bool
+        '''
+
+        self.smtp_user = None
+        '''
+        @ivar: Authentication username for SMTP
+        @type: str or None
+        '''
+
+        self.smtp_passwd = None
+        '''
+        @ivar: Authentication password for SMTP
+        @type: str or None
+        '''
+
+        self.mailer_version = __version__
+        '''
+        @ivar: version of the X-Mailer tag in the mail header
+        @type: str
+        '''
+        if mailer_version is not None:
+            self.mailer_version = mailer_version
+
+    #------------------------------------------------------------
+    # Defintion of some properties
+
+    #------------------------------------------------------------
+    # Property 'from'
+    def _get_from_address(self):
+        '''
+        Getter method for property 'from_address'
+        '''
+        return email.utils.formataddr(self._from_address)
+
+    def _set_from_address(self, value):
+        '''
+        Setter method for property 'from_address'
+        '''
+        _ = self.t.lgettext
+        if value is None:
+            msg = _("The 'From' address may not set to None.")
+            raise LogRotateMailerError(msg)
+        pair = ('', '')
+        if isinstance(value, tuple):
+            if len(value) < 2:
+                pair = email.utils.parseaddr(value[0])
+            else:
+                pair = (value[0], value[1])
+        else:
+            pair = email.utils.parseaddr(value)
+
+        if ( (pair[0] is None or pair[0] == '') and
+             (pair[1] is None or pair[1] == '') ):
+            msg = _("Invalid mail address given: '%s'.") % (str(value))
+            raise LogRotateMailerError(msg)
+
+        if not email_valid(pair[1]):
+            msg = _("Invalid mail address given: '%s'.") % (str(value))
+            raise LogRotateMailerError(msg)
+
+        self._from_address = pair
+        if self.verbose > 3:
+            addr = email.utils.formataddr(pair)
+            msg = _("Set sender mail address to: '%s'.") % (addr)
+            self.logger.debug(msg)
+
+    def _del_from_address(self):
+        '''
+        Deleter method for property 'from_address'
+        '''
+        self._init_from_address()
+
+    from_address = property(_get_from_address, _set_from_address, _del_from_address, "The mail address of the sender")
+
+    #------------------------------------------------------------
+    # Property 'sendmail'
+    def _get_sendmail(self):
+        '''
+        Getter method for property 'sendmail'
+        '''
+        return self._sendmail
+
+    def _set_sendmail(self, value):
+        '''
+        Setter method for property 'sendmail'
+        '''
+        _ = self.t.lgettext
+        if value is None or value == '':
+            self._sendmail = None
+            return
+
+        if os.path.isabs(value):
+            if os.path.exists(value):
+                cmd = os.path.normpath(value)
+                if os.access(cmd, os.X_OK):
+                    msg = _("Using '%s' as the sendmail command.") % (cmd)
+                    self.logger.debug(msg)
+                    self._sendmail = cmd
+                    return
+                else:
+                    msg = _("No execute permissions to '%s'.") % (cmd)
+                    self.logger.warning(msg)
+                    return
+            else:
+                msg = _("Sendmail command '%s' not found.") % (value)
+                self.logger.warning(msg)
+                return
+        else:
+            msg = _("Only absolute path allowed for a sendmail command: '%s'.") % (value)
+            self.logger.warning(msg)
+            return
+
+    def _del_sendmail(self):
+        '''
+        Deleter method for property 'from_address'
+        '''
+        self._sendmail = None
+
+    sendmail = property(_get_sendmail, _set_sendmail, _del_sendmail, "The sendmail executable for sending mails local")
+
+    #------------------------------------------------------------
+    # Property 'smtp_host'
+    def _get_smtp_host(self):
+        '''
+        Getter method for property 'smtp_host'
+        '''
+        return self._smtp_host
+
+    def _set_smtp_host(self, value):
+        '''
+        Setter method for property 'smtp_host'
+        '''
+        _ = self.t.lgettext
+        if value:
+            self._smtp_host = value
+
+    smtp_host = property(_get_smtp_host, _set_smtp_host, None, "The hostname to use for sending mails via SMTP (smarthost)")
+
+    #------------------------------------------------------------
+    # Property 'smtp_port'
+    def _get_smtp_port(self):
+        '''
+        Getter method for property 'smtp_port'
+        '''
+        return self._smtp_port
+
+    def _set_smtp_port(self, value):
+        '''
+        Setter method for property 'smtp_port'
+        '''
+        _ = self.t.lgettext
+        if value:
+            port = 25
+            try:
+                port = int(value)
+            except ValueError, e:
+                return
+            if port < 1 or port >= 2**15:
+                return
+            self._smtp_port = port
+
+    smtp_port = property(_get_smtp_port, _set_smtp_port, None, "The port to use for sending mails via SMTP")
+
+    #------------------------------------------------------------
+    # Property 'smtp_tls'
+    def _get_smtp_tls(self):
+        '''
+        Getter method for property 'smtp_tls'
+        '''
+        return self._smtp_tls
+
+    def _set_smtp_tls(self, value):
+        '''
+        Setter method for property 'smtp_tls'
+        '''
+        self._smtp_tls = bool(value)
+
+    smtp_tls = property(_get_smtp_tls, _set_smtp_tls, None, "Use TLS for sending mails via SMTP (smarthost)")
+
+    #------------------------------------------------------------
+    # Other Methods
+
+    #-------------------------------------------------------
+    def __del__(self):
+        '''
+        Destructor.
+        '''
+
+        _ = self.t.lgettext
+        if self.verbose > 2:
+            msg = _("Mailer object will destroyed.")
+            self.logger.debug(msg)
+
+    #------------------------------------------------------------
+    def __str__(self):
+        '''
+        Typecasting function for translating object structure
+        into a string
+
+        @return: structure as string
+        @rtype:  str
+        '''
+
+        pp = pprint.PrettyPrinter(indent=4)
+        structure = self.as_dict()
+        return pp.pformat(structure)
+
+    #-------------------------------------------------------
+    def as_dict(self):
+        '''
+        Transforms the elements of the object into a dict
+
+        @return: structure as dict
+        @rtype:  dict
+        '''
+
+        res = {}
+        res['t']              = self.t
+        res['verbose']        = self.verbose
+        res['test_mode']      = self.test_mode
+        res['logger']         = self.logger
+        res['sendmail']       = self.sendmail
+        res['from']           = self.from_address
+        res['smtp_host']      = self.smtp_host
+        res['smtp_port']      = self.smtp_port
+        res['smtp_tls']       = self.smtp_tls
+        res['smtp_user']      = self.smtp_user
+        res['smtp_passwd']    = self.smtp_passwd
+        res['mailer_version'] = self.mailer_version
+
+        return res
+
+    #-------------------------------------------------------
+    def _init_from_address(self):
+        '''
+        Initialises the sender mail address
+        '''
+
+        _ = self.t.lgettext
+
+        cur_user = pwd.getpwuid(os.getuid())[0]
+        cur_host = socket.getfqdn()
+        addr = cur_user + '@' + cur_host
+
+        if self.verbose > 3:
+            msg = _("Using <%s> as the sender mail address.") % (addr)
+            self.logger.debug(msg)
+
+        self._from_address = (None, addr)
+
+    #-------------------------------------------------------
+    def _init_sendmail(self):
+        '''
+        Initialises the sendmail with 
+        '''
+
+        _ = self.t.lgettext
+
+        progs = [
+            os.sep + os.path.join('usr', 'sbin', 'sendmail'),
+            os.sep + os.path.join('usr', 'lib', 'sendmail'),
+        ]
+
+        if self.verbose > 3:
+            msg = _("Initial search for the sendmail executable ...")
+            self.logger.debug(msg)
+
+        for prog in progs:
+
+            if self.verbose > 3:
+                msg = _("Testing for '%s' ...") % (prog)
+                self.logger.debug(msg)
+
+            if os.path.exists(prog):
+                if os.access(prog, os.X_OK):
+                    if self.verbose > 1:
+                            msg = _("Using '%s' as the sendmail command.") % (prog)
+                            self.logger.debug(msg)
+                    self._sendmail = prog
+                    break
+                else:
+                    msg = _("No execute permissions to '%s'.") % (prog)
+                    self.logger.warning(msg)
+
+        return
+
+    #-------------------------------------------------------
+    def send_file(self,
+            filename,
+            addresses,
+            original=None,
+            mime_type='text/plain',
+            rotate_date=None,
+            charset=None
+            ):
+        '''
+        Mails the file with the given file name as an attachement
+        to the given recipient(s).
+
+        Raises a LogRotateMailerError on harder errors.
+
+        @param filename:  The file name of the file to send (the existing,
+                          rotated and maybe compressed logfile).
+        @type filename:   str
+        @param addresses: A list of tuples of a pair in the form
+                          of the return value of email.utils.parseaddr()
+        @type addresses:  list
+        @param original:  The file name of the original (unrotated) logfile for
+                          informational purposes.
+                          If not given, filename is used instead.
+        @type original:   str or None
+        @param mime_type: MIME type (content type) of the original logfile,
+                          defaults to 'text/plain'
+        @type mime_type:  str
+        @param rotate_date: datetime object of rotation, defaults to now()
+        @type rotate_date:  datetime or None
+        @param charset: character set of (uncompreesed) logfile, if the
+                        mime_type is 'text/plain', defaults to 'utf-8'
+        @type charset:  str or None
+
+        @return: success of sending
+        @rtype:  bool
+        '''
+
+        _ = self.t.lgettext
+
+        if not os.path.exists(filename):
+            msg = _("File '%s' dosn't exists.") % (filename)
+            self.logger.error(msg)
+            return False
+
+        if not os.path.isfile(filename):
+            msg = _("File '%s' is not a regular file.") % (filename)
+            self.logger.warning(msg)
+            return False
+
+        basename = os.path.basename(filename)
+        if not original:
+            original = os.path.abspath(filename)
+
+        if not rotate_date:
+            rotate_date = datetime.now()
+
+        msg = _("Sending mail with attached file '%(file)s' to: %(rcpt)s") \
+                % {'file': basename,
+                   'rcpt': ', '.join(map(lambda x: '"' + email.utils.formataddr(x) + '"', addresses))}
+        self.logger.debug(msg)
+
+        mail_container = MIMEMultipart()
+        mail_container['Subject']  = ( "Rotated logfile '%s'" % (filename) )
+        mail_container['X-Mailer'] = ( "pylogrotate version %s" % (self.mailer_version) )
+        mail_container['From']     = self.from_address
+        mail_container['To']       = ', '.join(map(lambda x: email.utils.formataddr(x), addresses))
+        mail_container.preamble = 'You will not see this in a MIME-aware mail reader.\n'
+
+        # Generate Text of the first part of mail body
+        mailtext = "Rotated Logfile:\n\n"
+        mailtext += "\t - " + filename + "\n"
+        mailtext += "\t   (" + original + ")\n"
+        mailtext += "\n"
+        mailtext += "Date of rotation: " + rotate_date.isoformat(' ')
+        mailtext += "\n"
+        mailtext = _encodestring(mailtext, quotetabs=False)
+        mail_part = MIMENonMultipart('text', 'plain', charset=sys.getdefaultencoding())
+        mail_part.set_payload(mailtext)
+        mail_part['Content-Transfer-Encoding'] = 'quoted-printable'
+        mail_container.attach(mail_part)
+
+        ctype, encoding = mimetypes.guess_type(filename)
+        if self.verbose > 3:
+            msg = _("Guessed content-type: '%(ctype)s' and encoding '%(encoding)s'.") \
+                    % {'ctype': ctype, 'encoding': encoding }
+            self.logger.debug(msg)
+
+        if encoding:
+            if encoding == 'gzip':
+                ctype = 'application/x-gzip'
+            elif encoding == 'bzip2':
+                ctype = 'application/x-bzip2'
+            else:
+                ctype = 'application/octet-stream'
+
+        if not ctype:
+            ctype = mime_type
+
+        maintype, subtype = ctype.split('/', 1)
+        fp = open(filename, 'rb')
+        mail_part = MIMEBase(maintype, subtype)
+        mail_part.set_payload(fp.read())
+        fp.close()
+        if maintype == 'text':
+            msgtext = mail_part.get_payload()
+            msgtext =  _encodestring(msgtext, quotetabs=False)
+            mail_part.set_payload(msgtext)
+            mail_part['Content-Transfer-Encoding'] = 'quoted-printable'
+        else:
+            encoders.encode_base64(mail_part)
+        mail_part.add_header('Content-Disposition', 'attachment', filename=basename)
+        mail_container.attach(mail_part)
+
+        composed = mail_container.as_string()
+        if self.verbose > 4:
+            msg = _("Generated E-mail:") + "\n" + composed
+            self.logger.debug(msg)
+
+        return True
+
+#========================================================================
+
+if __name__ == "__main__":
+    pass
+
+
+#========================================================================
+
+# vim: fileencoding=utf-8 filetype=python ts=4 expandtab
diff --git a/LogRotate/LogRotateScript.py b/LogRotate/LogRotateScript.py
new file mode 100755 (executable)
index 0000000..34268ca
--- /dev/null
@@ -0,0 +1,550 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# $Id$
+# $URL$
+
+'''
+@author: Frank Brehm
+@contact: frank@brehm-online.com
+@license: GPL3
+@copyright: (c) 2010-2011 by Frank Brehm, Berlin
+@version: 0.0.2
+@summary: module for a logrotate script object
+         (for pre- and postrotate actions)
+'''
+import re
+import logging
+import subprocess
+import pprint
+import gettext
+
+revision = '$Revision$'
+revision = re.sub( r'\$', '', revision )
+revision = re.sub( r'Revision: ', r'r', revision )
+revision = re.sub( r'\s*$', '', revision )
+
+__author__    = 'Frank Brehm'
+__copyright__ = '(C) 2011 by Frank Brehm, Berlin'
+__contact__    = 'frank@brehm-online.com'
+__version__    = '0.1.0 ' + revision
+__license__    = 'GPL3'
+
+#========================================================================
+
+class LogRotateScriptError(Exception):
+    '''
+    Base class for exceptions in this module.
+    '''
+
+#========================================================================
+
+class LogRotateScript(object):
+    '''
+    Class for encapsulating a logrotate script
+    (for pre- and postrotate actions)
+
+    @author: Frank Brehm
+    @contact: frank@brehm-online.com
+    '''
+
+    #-------------------------------------------------------
+    def __init__( self, name,
+                        local_dir = None,
+                        verbose   = 0,
+                        test_mode = False,
+    ):
+        '''
+        Constructor.
+
+        @param name:      the name of the script as an identifier
+        @type name:       str
+        @param local_dir: The directory, where the i18n-files (*.mo)
+                          are located. If None, then system default
+                          (/usr/share/locale) is used.
+        @type local_dir:  str or None
+        @param verbose:   verbosity (debug) level
+        @type verbose:    int
+        @param test_mode: test mode - no write actions are made
+        @type test_mode:  bool
+
+        @return: None
+        '''
+
+        self.t = gettext.translation(
+            'LogRotateScript',
+            local_dir,
+            fallback = True
+        )
+        '''
+        @ivar: a gettext translation object
+        @type: gettext.translation
+        '''
+
+        _ = self.t.lgettext
+
+        self.verbose = verbose
+        '''
+        @ivar: verbosity level (0 - 9)
+        @type: int
+        '''
+
+        self._name = name
+        '''
+        @ivar: the name of the script as an identifier
+        @type: str
+        '''
+
+        self.test_mode = test_mode
+        '''
+        @ivar: test mode - no write actions are made
+        @type: bool
+        '''
+
+        self.logger = logging.getLogger('pylogrotate.script')
+        '''
+        @ivar: logger object
+        @type: logging.getLogger
+        '''
+
+        self._cmd = []
+        '''
+        @ivar: List of commands to execute
+        @type: list
+        '''
+
+        self._post_files = 0
+        '''
+        @ivar: Number of logfiles referencing to this script
+               as a postrotate script
+        @type: int
+        '''
+
+        self._last_files = 0
+        '''
+        @ivar: Number of logfiles referencing to this script
+               as a lastaction script
+        @type: int
+        '''
+
+        self._done_firstrun = False
+        '''
+        @ivar: Flag, whether the script was executed as
+               a firstaction script
+        @type: bool
+        '''
+
+        self._done_prerun = False
+        '''
+        @ivar: Flag, whether the script was executed as
+               a prerun script
+        @type: bool
+        '''
+
+        self._done_postrun = False
+        '''
+        @ivar: Flag, whether the script was executed as
+               a postrun script
+        @type: bool
+        '''
+
+        self._done_lastrun = False
+        '''
+        @ivar: Flag, whether the script was executed as
+               a lastaction script
+        @type: bool
+        '''
+
+        self._do_post = False
+        '''
+        Runtime flag, that the script should be executed
+        as an postrun script
+        '''
+
+        self._do_last = False
+        '''
+        Runtime flag, that the script should be executed
+        as an lastaction script
+        '''
+
+    #------------------------------------------------------------
+    # Defintion of some properties
+
+    #------------------------------------------------------------
+    # Property 'name'
+    def _get_name(self):
+        '''
+        Getter method for property 'name'
+        '''
+        return self._name
+
+    name = property(_get_name, None, None, "Name of the script as an identifier")
+
+    #------------------------------------------------------------
+    # Property 'cmd'
+    def _get_cmd(self):
+        '''
+        Getter method for property 'cmd'
+        '''
+        if len(self._cmd):
+            return "\n".join(self._cmd)
+        else:
+            return None
+
+    def _set_cmd(self, value):
+        '''
+        Setter method for property 'cmd'
+        '''
+        if value:
+            if isinstance(value, list):
+                self._cmd = value[:]
+            else:
+                self._cmd = [value]
+        else:
+            self._cmd = []
+
+    def _del_cmd(self):
+        '''
+        Deleter method for property 'cmd'
+        '''
+        self._cmd = []
+
+    cmd = property(_get_cmd, _set_cmd, _del_cmd, "the commands to execute")
+
+    #------------------------------------------------------------
+    # Property 'post_files'
+    def _get_post_files(self):
+        '''
+        Getter method for property 'post_files'
+        '''
+        return self._post_files
+
+    def _set_post_files(self, value):
+        '''
+        Setter method for property 'post_files'
+        '''
+        _ = self.t.lgettext
+        if isinstance(value, int):
+            self._post_files = value
+        else:
+            msg = _("Invalid value for property '%s' given.") % ('post_files')
+            raise LogRotateScriptError(msg)
+
+    post_files = property(
+                    _get_post_files,
+                    _set_post_files,
+                    None,
+                    "Number of logfiles referencing to this script as a postrotate script."
+    )
+
+    #------------------------------------------------------------
+    # Property 'last_files'
+    def _get_last_files(self):
+        '''
+        Getter method for property 'last_files'
+        '''
+        return self._last_files
+
+    def _set_last_files(self, value):
+        '''
+        Setter method for property 'last_files'
+        '''
+        _ = self.t.lgettext
+        if isinstance(value, int):
+            self._last_files = value
+        else:
+            msg = _("Invalid value for property '%s' given.") % ('last_files')
+            raise LogRotateScriptError(msg)
+
+    last_files = property(
+                    _get_last_files,
+                    _set_last_files,
+                    None,
+                    "Number of logfiles referencing to this script as a lastaction script."
+    )
+
+    #------------------------------------------------------------
+    # Property 'done_firstrun'
+    def _get_done_firstrun(self):
+        '''
+        Getter method for property 'done_firstrun'
+        '''
+        return self._done_firstrun
+
+    def _set_done_firstrun(self, value):
+        '''
+        Setter method for property 'done_firstrun'
+        '''
+        self._done_firstrun = bool(value)
+
+    done_firstrun = property(
+                    _get_done_firstrun,
+                    _set_done_firstrun,
+                    None,
+                    "Flag, whether the script was executed as a firstaction script."
+    )
+
+    #------------------------------------------------------------
+    # Property 'done_prerun'
+    def _get_done_prerun(self):
+        '''
+        Getter method for property 'done_prerun'
+        '''
+        return self._done_prerun
+
+    def _set_done_prerun(self, value):
+        '''
+        Setter method for property 'done_prerun'
+        '''
+        self._done_prerun = bool(value)
+
+    done_prerun = property(
+                    _get_done_prerun,
+                    _set_done_prerun,
+                    None,
+                    "Flag, whether the script was executed as a prerun script."
+    )
+
+    #------------------------------------------------------------
+    # Property 'done_postrun'
+    def _get_done_postrun(self):
+        '''
+        Getter method for property 'done_postrun'
+        '''
+        return self._done_postrun
+
+    def _set_done_postrun(self, value):
+        '''
+        Setter method for property 'done_postrun'
+        '''
+        self._done_postrun = bool(value)
+
+    done_postrun = property(
+                    _get_done_postrun,
+                    _set_done_postrun,
+                    None,
+                    "Flag, whether the script was executed as a postrun script."
+    )
+
+    #------------------------------------------------------------
+    # Property 'done_lastrun'
+    def _get_done_lastrun(self):
+        '''
+        Getter method for property 'done_lastrun'
+        '''
+        return self._done_lastrun
+
+    def _set_done_lastrun(self, value):
+        '''
+        Setter method for property 'done_lastrun'
+        '''
+        self._done_lastrun = bool(value)
+
+    done_lastrun = property(
+                    _get_done_lastrun,
+                    _set_done_lastrun,
+                    None,
+                    "Flag, whether the script was executed as a lastaction script."
+    )
+
+    #------------------------------------------------------------
+    # Property 'do_post'
+    def _get_do_post(self):
+        '''
+        Getter method for property 'do_post'
+        '''
+        return self._do_post
+
+    def _set_do_post(self, value):
+        '''
+        Setter method for property 'do_post'
+        '''
+        self._do_post = bool(value)
+
+    do_post = property(
+                    _get_do_post,
+                    _set_do_post,
+                    None,
+                    "Flag, whether the script should be executed as a postrun script."
+    )
+
+    #------------------------------------------------------------
+    # Property 'do_last'
+    def _get_do_last(self):
+        '''
+        Getter method for property 'do_last'
+        '''
+        return self._do_last
+
+    def _set_do_last(self, value):
+        '''
+        Setter method for property 'do_last'
+        '''
+        self._do_last = bool(value)
+
+    do_last = property(
+                    _get_do_last,
+                    _set_do_last,
+                    None,
+                    "Flag, whether the script should be executed as a lastaction script."
+    )
+
+    #------------------------------------------------------------
+    # Other Methods
+
+    #-------------------------------------------------------
+    def __del__(self):
+        '''
+        Destructor.
+        Checks, whether the script should even be run as
+        a postrun or a lastaction script
+        '''
+
+        _ = self.t.lgettext
+        if self.verbose > 2:
+            msg = _("Logrotate script object '%s' will destroyed.") % (self.name)
+            self.logger.debug(msg)
+
+        self.check_for_execute()
+
+    #------------------------------------------------------------
+    def __str__(self):
+        '''
+        Typecasting function for translating object structure
+        into a string
+
+        @return: structure as string
+        @rtype:  str
+        '''
+
+        pp = pprint.PrettyPrinter(indent=4)
+        structure = self.as_dict()
+        return pp.pformat(structure)
+
+    #-------------------------------------------------------
+    def as_dict(self):
+        '''
+        Transforms the elements of the object into a dict
+
+        @return: structure as dict
+        @rtype:  dict
+        '''
+
+        res = {}
+        res['t']             = self.t
+        res['verbose']       = self.verbose
+        res['name']          = self.name
+        res['test_mode']     = self.test_mode
+        res['logger']        = self.logger
+        res['cmd']           = self._cmd[:]
+        res['post_files']    = self.post_files
+        res['last_files']    = self.last_files
+        res['done_firstrun'] = self.done_firstrun
+        res['done_prerun']   = self.done_prerun
+        res['done_postrun']  = self.done_postrun
+        res['done_lastrun']  = self.done_lastrun
+        res['do_post']       = self.do_post
+        res['do_last']       = self.do_last
+
+        return res
+
+    #------------------------------------------------------------
+    def add_cmd(self, cmd):
+        '''
+        Adding a command to the list self._cmd
+
+        @param cmd: the command to add to self._cmd
+        @type cmd:  str
+
+        @return: None
+        '''
+        self._cmd.append(cmd)
+
+    #------------------------------------------------------------
+    def execute(self, force=False, expected_retcode=0):
+        '''
+        Executes the command as an OS command in a shell.
+
+        @param force: force executing command even
+                      if self.test_mode == True
+        @type force:    bool
+        @param expected_retcode: expected returncode of the command
+                                 (should be 0)
+        @type expected_retcode:  int
+
+        @return: Success of the comand (shell returncode == 0)
+        @rtype:  bool
+        '''
+
+        _ = self.t.lgettext
+        cmd = self.cmd
+        if cmd is None:
+            msg = _("No command to execute defined in script '%s'.") % (self.name)
+            raise LogRotateScriptError(msg)
+            return False
+        if self.verbose > 3:
+            msg = _("Executing script '%(name)s' with command: '%(cmd)s'") \
+                    % {'name': self.name, 'cmd': cmd}
+            self.logger.debug(msg)
+        if not force:
+            if self.test_mode:
+                return True
+        try:
+            retcode = subprocess.call(command, shell=True)
+            if self.verbose > 3:
+                msg = _("Got returncode for script '%(name)s': '%(retcode)s'") \
+                        % {'name': self.name, 'retcode': retcode}
+                self.logger.debug(msg)
+            if retcode < 0:
+                msg = _("Child in script '%(name)s' was terminated by signal %(retcode)d") \
+                        % {'name': self.name, 'retcode': -retcode}
+                self.logger.error(msg)
+                return False
+            if retcode != expected_retcode:
+                return False
+            return True
+        except OSError, e:
+            msg = _("Execution of script '%(name)s' failed: %(error)s") \
+                    % {'name': self.name, 'error': str(e)}
+            self.logger.error(msg)
+            return False
+
+        return False
+
+    #------------------------------------------------------------
+    def check_for_execute(self, force=False, expected_retcode=0):
+        '''
+        Checks, whether the script should executed.
+
+        @param force: force executing command even
+                      if self.test_mode == True
+        @type force:    bool
+        @param expected_retcode: expected returncode of the command
+                                 (should be 0)
+        @type expected_retcode:  int
+
+        @return: Success of execution
+        @rtype:  bool
+        '''
+
+        _ = self.t.lgettext
+        msg = _("Checking, whether the script '%s' should be executed.") % (self.name)
+        self.logger.debug(msg)
+
+        if self.do_post or self.do_last:
+            result = self.execute(force=force, expected_retcode=expected_retcode)
+            self.do_post = False
+            self.do_last = False
+            return result
+
+        return True
+
+#========================================================================
+
+if __name__ == "__main__":
+    pass
+
+
+#========================================================================
+
+# vim: fileencoding=utf-8 filetype=python ts=4 expandtab
diff --git a/LogRotate/LogRotateStatusFile.py b/LogRotate/LogRotateStatusFile.py
new file mode 100755 (executable)
index 0000000..5dc4b3c
--- /dev/null
@@ -0,0 +1,575 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# $Id$
+# $URL$
+
+'''
+@author: Frank Brehm
+@contact: frank@brehm-online.com
+@license: GPL3
+@copyright: (c) 2010-2011 by Frank Brehm, Berlin
+@version: 0.0.2
+@summary: module for operations with the logrotate state file
+'''
+
+import re
+import sys
+import os
+import os.path
+import gettext
+import logging
+import pprint
+
+from datetime import tzinfo, timedelta, datetime, date, time
+
+from LogRotateCommon import split_parts 
+
+revision = '$Revision$'
+revision = re.sub( r'\$', '', revision )
+revision = re.sub( r'Revision: ', r'r', revision )
+revision = re.sub( r'\s*$', '', revision )
+
+__author__    = 'Frank Brehm'
+__copyright__ = '(C) 2011 by Frank Brehm, Berlin'
+__contact__    = 'frank@brehm-online.com'
+__version__    = '0.1.0 ' + revision
+__license__    = 'GPL3'
+
+#========================================================================
+
+class LogrotateStatusFileError(Exception):
+    '''
+    Base class for exceptions in this module.
+    '''
+
+#========================================================================
+
+ZERO = timedelta(0)
+
+class UTC(tzinfo):
+    """UTC"""
+
+    def utcoffset(self, dt):
+        return ZERO
+
+    def tzname(self, dt):
+        return "UTC"
+
+    def dst(self, dt):
+        return ZERO
+
+utc = UTC()
+
+
+#========================================================================
+
+class LogrotateStatusFile(object):
+    '''
+    Class for operations with the logrotate state file
+
+    @author: Frank Brehm
+    @contact: frank@brehm-online.com
+    '''
+
+    #-------------------------------------------------------
+    def __init__( self, file_name,
+                        local_dir  = None,
+                        verbose    = 0,
+                        test_mode  = False,
+    ):
+        '''
+        Constructor.
+
+        @param file_name: the file name of the status file
+        @type file_name:  str
+        @param verbose:   verbosity (debug) level
+        @type verbose:    int
+        @param test_mode: test mode - no write actions are made
+        @type test_mode:  bool
+        @param local_dir: The directory, where the i18n-files (*.mo)
+                          are located. If None, then system default
+                          (/usr/share/locale) is used.
+        @type local_dir:  str or None
+
+        @return: None
+        '''
+
+        self.local_dir = local_dir
+        '''
+        @ivar: The directory, where the i18n-files (*.mo) are located.
+        @type: str or None
+        '''
+
+        self.t = gettext.translation(
+            'LogRotateStatusFile',
+            local_dir,
+            fallback = True
+        )
+        '''
+        @ivar: a gettext translation object
+        @type: gettext.translation
+        '''
+
+        _ = self.t.lgettext
+
+        self.verbose = verbose
+        '''
+        @ivar: verbosity level (0 - 9)
+        @type: int
+        '''
+
+        self.file_name = file_name
+        '''
+        @ivar: the initial file name of the status file to use
+        @type: str
+        '''
+
+        self.file_name_is_absolute = False
+        '''
+        @ivar: flag, that shows, that the file name is now an absolute path
+        @type: bool
+        '''
+
+        self.fd = None
+        '''
+        @ivar: the file object of the opened status file, or None, if not opened
+        @type: file or None
+        '''
+
+        self.was_read = False
+        '''
+        @ivar: flag, whether the status file was read
+        @type: bool
+        '''
+
+        self.status_version = None
+        '''
+        @ivar: the version of the status file (2 or 3)
+        @type: int or None
+        '''
+
+        self.test_mode = test_mode
+        '''
+        @ivar: test mode - no write actions are made
+        @type: bool
+        '''
+
+        self.has_changed = False
+        '''
+        @ivar: flag, whether something has changed and needs to be written
+        @type: bool
+        '''
+
+        self.logger = logging.getLogger('pylogrotate.status_file')
+        '''
+        @ivar: logger object
+        @type: logging.getLogger
+        '''
+
+        self.file_state = {}
+        '''
+        @ivar: the last rotation date of every particular log file
+               keys are the asolute filenames (without globbing)
+               and the values are datetime objects of the last rotation
+               referencing to UTC
+               If no rotation was made, value is datetime.min().
+        @type: dict
+        '''
+
+        # Initial read and check for permissions
+        self.read(must_exists = False)
+        self._check_permissions()
+
+    #-------------------------------------------------------
+    def __del__(self):
+        '''
+        Destructor.
+        Enforce saving of status file, if something has changed.
+        '''
+
+        _ = self.t.lgettext
+        msg = _("Status file object will destroyed.")
+        self.logger.debug(msg)
+
+        if self.has_changed:
+            self.write()
+
+    #-------------------------------------------------------
+    def as_dict(self):
+        '''
+        Transforms the elements of the object into a dict
+
+        @return: structure as dict
+        @rtype:  dict
+        '''
+
+        res = {}
+        res['local_dir']             = self.local_dir
+        res['t']                     = self.t
+        res['verbose']               = self.verbose
+        res['file_name']             = self.file_name
+        res['file_name_is_absolute'] = self.file_name_is_absolute
+        res['fd']                    = self.fd
+        res['status_version']        = self.status_version
+        res['test_mode']             = self.test_mode
+        res['logger']                = self.logger
+        res['file_state']            = self.file_state
+        res['was_read']              = self.was_read
+        res['has_changed']           = self.has_changed
+
+        return res
+
+    #------------------------------------------------------------
+    def get_rotation_date(self, logfile):
+        '''
+        Gives back the date of the last rotation of a particular logfile.
+        If this logfile is not found in the state file, datetime.min() is given back.
+
+        @param logfile: the logfile to query
+        @type logfile:  str
+
+        @return: date of last rotation of this logfile
+        @rtype:  datetime
+        '''
+
+        if not self.was_read:
+            self.read(must_exists = False)
+
+        rotate_date = datetime.min.replace(tzinfo=utc)
+        if logfile in self.file_state:
+            rotate_date = self.file_state[logfile]
+
+        return rotate_date
+
+    #------------------------------------------------------------
+    def set_rotation_date(self, logfile, rotate_date = None):
+        '''
+        Sets the rotation date of the given logfile.
+        If the rotation date is not given, datetime.utcnow() is used.
+
+        @param logfile:     the logfile to set
+        @type logfile:      str
+        @param rotate_date: the rotation date of this logfile
+        @type rotate_date:  datetime or None
+
+        @return: date of rotation of this logfile (relative to UTC)
+        @rtype:  datetime
+        '''
+
+        date_utc = datetime.utcnow()
+        if rotate_date:
+            date_utc = rotate_date.astimezone(utc)
+
+        _ = self.t.lgettext
+        msg = _("Setting rotation date of '%(file)s' to '%(date)s' ...") \
+                % {'file': logfile, 'date': date_utc.isoformat(' ') }
+        self.logger.debug(msg)
+
+        #self.read(must_exists = False)
+        self.file_state[logfile] = date_utc
+        self.has_changed = True
+
+        #self.write()
+
+        return date_utc
+
+    #------------------------------------------------------------
+    def write(self):
+        '''
+        Writes the content of self.file_state in the state file.
+
+        @return:    success of writing
+        @rtype:     bool
+        '''
+
+        _ = self.t.lgettext
+
+        # setting a failing version of the status file
+        if not self.status_version:
+            self.status_version = 3
+
+        max_length = 1
+
+        # Retrieving the maximum length of the logfiles for version 3
+        if self.status_version == 3:
+            for logfile in self.file_state:
+                if len(logfile) > max_length:
+                    max_length = len(logfile)
+            max_length += 2
+
+        fd = None
+        # Big try block for ensure closing open status file
+        try:
+
+            msg = _("Open status file '%s' for writing ...") % (self.file_name)
+            self.logger.debug(msg)
+
+            # open status file for writing
+            if not self.test_mode:
+                try:
+                    fd = open(self.file_name, 'w')
+                except IOError, e:
+                    msg = _("Could not open status file '%s' for write: ") % (self.file_name) + str(e)
+                    raise LogrotateStatusFileError(msg)
+
+            # write logrotate version line
+            line = 'Logrotate State -- Version 3'
+            if self.status_version == 2:
+                line = 'logrotate state -- version 2'
+            if self.verbose > 2:
+                msg = _("Writing version line '%s'.") % (line)
+                self.logger.debug(msg)
+            line += '\n'
+            if fd:
+                fd.write(line)
+
+            # iterate over logfiles in self.file_state
+            for logfile in sorted(self.file_state.keys(), lambda x,y: cmp(x.lower(), y.lower())):
+                rotate_date = self.file_state[logfile]
+                date_str = "%d-%d-%d" % (rotate_date.year, rotate_date.month, rotate_date.day)
+                if self.status_version == 3:
+                    date_str = ( "%d-%02d-%02d_%02d:%02d:%02d" %
+                                (rotate_date.year, rotate_date.month, rotate_date.day,
+                                 rotate_date.hour, rotate_date.minute, rotate_date.second))
+                line = '%-*s %s' % (max_length, ('"' + logfile + '"'), date_str)
+                if self.verbose > 2:
+                    msg = _("Writing line '%s'.") % (line)
+                    self.logger.debug(msg)
+                if fd:
+                    fd.write(line + "\n")
+
+        finally:
+            if fd:
+                fd.close()
+                fd = None
+
+        self.has_changed = False
+        return True
+
+    #------------------------------------------------------------
+    def __str__(self):
+        '''
+        Typecasting function for translating object structure
+        into a string
+
+        @return: structure as string
+        @rtype:  str
+        '''
+
+        pp = pprint.PrettyPrinter(indent=4)
+        return pp.pformat(self.as_dict())
+
+    #------------------------------------------------------------
+    def _check_permissions(self):
+        '''
+        Checks the permissions of the state file and/or his parent directory.
+        Throws a LogrotateStatusFileError on a error.
+
+        @return:    success of check
+        @rtype:     bool
+        '''
+
+        _ = self.t.lgettext
+        msg = _("Checking permissions of status file '%s' ...") % (self.file_name)
+        self.logger.debug(msg)
+
+        if os.path.exists(self.file_name):
+            # Check for write access to the status file
+            if os.access(self.file_name, os.W_OK):
+                msg = _("Access to status file '%s' is OK.") % (self.file_name)
+                self.logger.debug(msg)
+                return True
+            else:
+                msg = _("No write access to status file '%s'.") % (self.file_name)
+                if self.test_mode:
+                    self.logger.error(msg)
+                else:
+                    raise LogrotateStatusFileError(msg)
+                return False
+
+        parent_dir = os.path.dirname(self.file_name)
+        msg = _("Checking permissions of parent directory '%s' ...") % (parent_dir)
+        self.logger.debug(msg)
+
+        # Check for existence of parent dir
+        if not os.path.exists(parent_dir):
+            msg = _("Directory '%s' doesn't exists.") % (parent_dir)
+            if self.test_mode:
+                self.logger.error(msg)
+            else:
+                raise LogrotateStatusFileError(msg)
+            return False
+
+        # Check whether parent dir is a directory
+        if not os.path.isdir(parent_dir):
+            msg = _("Parent directory '%(dir)s' of status file '%(file)s' is not a directory.") \
+                    % {'dir': parent_dir, 'file': self.file_name }
+            if self.test_mode:
+                self.logger.error(msg)
+            else:
+                raise LogrotateStatusFileError(msg)
+            return False
+
+        # Check for write access to parent dir
+        if not os.access(parent_dir, os.W_OK):
+            msg = _("No write access to parent directory '%(dir)s' of status file '%(file)s'.") \
+                    % {'dir': parent_dir, 'file': self.file_name }
+            if self.test_mode:
+                self.logger.error(msg)
+            else:
+                raise LogrotateStatusFileError(msg)
+            return False
+
+        msg = _("Permissions to parent directory '%s' are OK.") % (parent_dir)
+        self.logger.debug(msg)
+        return True
+
+    #-------------------------------------------------------
+    def read(self, must_exists = True):
+        '''
+        Reads the status file and put the results in the dict self.file_state.
+        Puts back the absolute path of the status file in self.file_name on success.
+
+        Throws a LogrotateStatusFileError on a error.
+
+        @param must_exists: throws an exception, if true and the status file
+                            doesn't exists
+        @type must_exists:  bool
+
+        @return:    success of reading
+        @rtype:     bool
+        '''
+
+        self.file_state = {}
+        _ = self.t.lgettext
+
+        # Check for existence of status file
+        if not os.path.exists(self.file_name):
+            msg = _("Status file '%s' doesn't exists.") % (self.file_name)
+            if must_exists:
+                raise LogrotateStatusFileError(msg)
+            else:
+                self.logger.info(msg)
+            return False
+
+        # makes the name of the status file an absolute path
+        if not self.file_name_is_absolute:
+            self.file_name = os.path.abspath(self.file_name)
+            self.file_name_is_absolute = True
+            if self.verbose > 2:
+                msg = _("Absolute path of status file is now '%s'.") % (self.file_name)
+                self.logger.debug(msg)
+
+        # Checks, that the status file is a regular file
+        if not os.path.isfile(self.file_name):
+            msg = _("Status file '%s' is not a regular file.") % (self.file_name)
+            raise LogrotateStatusFileError(msg)
+            return False
+
+        msg = _("Reading status file '%s' ...") % (self.file_name)
+        self.logger.debug(msg)
+
+        fd = None
+        try:
+            fd = open(self.file_name, 'Ur')
+        except IOError, e:
+            msg = _("Could not read status file '%s': ") % (self.file_name) + str(e)
+            raise LogrotateStatusFileError(msg)
+        self.fd = fd
+
+        try:
+            # Reading the lines of the status file
+            i = 0
+            for line in fd:
+                i += 1
+                line = line.strip()
+                if self.verbose > 4:
+                    msg = _("Performing status file line '%(line)s' (file: '%(file)s', row: %(row)d)") \
+                            % {'line': line, 'file': self.file_name, 'row': i, }
+                    self.logger.debug(msg)
+
+                # check for file heading
+                if i == 1:
+                    match = re.search(r'^logrotate\s+state\s+-+\s+version\s+([23])$', line, re.IGNORECASE)
+                    if match:
+                        # Correct file header
+                        self.status_version = int(match.group(1))
+                        if self.verbose > 1:
+                            msg = _("Idendified version of status file: %d") % (self.status_version)
+                            self.logger.debug(msg)
+                        continue
+                    else:
+                        # Wrong header
+                        msg = _("Incompatible version of status file '%(file)s': %(header)s") \
+                                % { 'file': self.file_name, 'header': line }
+                        fd.close()
+                        raise LogrotateStatusFileError(msg)
+
+                if line == '':
+                    continue
+
+                parts = split_parts(line)
+                logfile = parts[0]
+                rdate   = parts[1]
+                if self.verbose > 2:
+                    msg = _("Found logfile '%(file)s' with rotation date '%(date)s'.") \
+                            % { 'file': logfile, 'date': rdate }
+                    self.logger.debug(msg)
+
+                if logfile and rdate:
+                    match = re.search(r'\s*(\d+)[_\-](\d+)[_\-](\d+)(?:[\s\-_]+(\d+)[_\-:](\d+)[_\-:](\d+))?', rdate)
+                    if not match:
+                        msg = _("Could not determine date format: '%(date)s' (file: '%(file)s', row: %(row)d)") \
+                                % {'date': rdate, 'file': logfile, 'row': i, }
+                        self.logger.warning(msg)
+                        continue
+                    d = {
+                        'Y': int(match.group(1)),
+                        'm': int(match.group(2)),
+                        'd': int(match.group(3)),
+                        'H': 0,
+                        'M': 0,
+                        'S': 0,
+                    }
+                    if match.group(4) is not None:
+                        d['H'] = int(match.group(4))
+                    if match.group(5) is not None:
+                        d['M'] = int(match.group(5))
+                    if match.group(6) is not None:
+                        d['S'] = int(match.group(6))
+
+                    dt = None
+                    try:
+                        dt = datetime(d['Y'], d['m'], d['d'], d['H'], d['M'], d['S'], tzinfo = utc)
+                    except ValueError, e:
+                        msg = _("Invalid date: '%(date)s' (file: '%(file)s', row: %(row)d)") \
+                                % {'date': rdate, 'file': logfile, 'row': i, }
+                        self.logger.warning(msg)
+                        continue
+
+                    self.file_state[logfile] = dt
+
+                else:
+
+                    msg = _("Neither a logfile nor a date found in line '%(line)s' (file: '%(file)s', row: %(row)d)") \
+                            % {'line': line, 'file': logfile, 'row': i, }
+                    self.logger.warning(msg)
+
+        finally:
+            fd.close
+
+        self.fd = None
+        self.was_read = True
+
+        return True
+
+#========================================================================
+
+if __name__ == "__main__":
+    pass
+
+
+#========================================================================
+
+# vim: fileencoding=utf-8 filetype=python ts=4 expandtab
diff --git a/LogRotate/__init__.py b/LogRotate/__init__.py
new file mode 100755 (executable)
index 0000000..2c6a1ef
--- /dev/null
@@ -0,0 +1,9 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+'''
+@author: Frank Brehm
+@contact: frank@brehm-online.com
+@copyright: (c) 2010 - 2011 by Frank Brehm, Berlin
+@summary: All modules for logrotate.py
+'''
+# vim: fileencoding=utf-8 filetype=python ts=4
diff --git a/LogRotateCommon.py b/LogRotateCommon.py
deleted file mode 100755 (executable)
index af03d1b..0000000
+++ /dev/null
@@ -1,512 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-# $Id$
-# $URL$
-
-'''
-@author: Frank Brehm
-@contact: frank@brehm-online.com
-@license: GPL3
-@copyright: (c) 2010-2011 by Frank Brehm, Berlin
-@version: 0.1.0
-@summary: Module for common used functions
-'''
-
-import re
-import sys
-import locale
-import logging
-import gettext
-import csv
-import pprint
-import email.utils
-
-revision = '$Revision$'
-revision = re.sub( r'\$', '', revision )
-revision = re.sub( r'Revision: ', r'r', revision )
-revision = re.sub( r'\s*$', '', revision )
-
-__author__    = 'Frank Brehm'
-__copyright__ = '(C) 2011 by Frank Brehm, Berlin'
-__contact__    = 'frank@brehm-online.com'
-__version__    = '0.1.0 ' + revision
-__license__    = 'GPL3'
-
-
-logger = logging.getLogger('pylogrotate.common')
-locale_dir = None
-
-#========================================================================
-
-def split_parts( text, keep_quotes = False, raise_on_unbalanced = True):
-    '''
-    Split the given text in chunks by whitespaces or
-    single or double quoted strings.
-        
-    @param text:        the text to split in chunks
-    @type text:         str
-    @param keep_quotes: keep quotes of quoted chunks
-    @type keep_quotes:  bool
-    @param raise_on_unbalanced: raise an exception on
-                                unbalanced quotes
-    @type raise_on_unbalanced:  bool
-
-    @return: list of chunks
-    @rtype:  list
-    '''
-
-    chunks = []
-    if text is None:
-        return chunks
-
-    txt = str(text)
-    last_chunk = ''
-
-    # Big loop to split the text - until it is empty
-    while txt != '':
-
-        # add chunk, if there is a chunk left and a whitspace
-        # at the begin of the line
-        match = re.search(r"\s+", txt)
-        if ( last_chunk != '' ) and match:
-            chunks.append(last_chunk)
-            last_chunk = ''
-
-        # clean the line
-        txt = txt.strip()
-        if txt == '':
-            break
-
-        # search for a single quoted string at the begin of the line
-        match = re.search(r"^'((?:\\'|[^'])*)'", txt)
-        if match:
-            chunk = match.group(1)
-            chunk = re.sub(r"\\'", "'", chunk)
-            if keep_quotes:
-                chunk = "'" + chunk + "'"
-            last_chunk += chunk
-            txt = re.sub(r"^'(?:\\'|[^'])*'", "", txt)
-            continue
-
-        # search for a double quoted string at the begin of the line
-        match = re.search(r'^"((?:\\"|[^"])*)"', txt)
-        if match:
-            chunk = match.group(1)
-            chunk = re.sub(r'\\"', '"', chunk)
-            if keep_quotes:
-                chunk = '"' + chunk + '"'
-            last_chunk += chunk
-            txt = re.sub(r'^"(?:\\"|[^"])*"', "", txt)
-            continue
-
-        # search for unquoted, whitespace delimited text
-        # at the begin of the line
-        match = re.search(r'^((?:[^\s\'"]+|\\\'|\\")+)', txt)
-        if match:
-            last_chunk += match.group(1)
-            txt = re.sub(r'^(?:[^\s\'"]+|\\\'|\\")+', "", txt)
-            continue
-
-        # Only whitespaces left
-        match = re.search(r'^\s*$', txt)
-        if match:
-            break
-
-        # Check for unbalanced quotes
-        match = re.search(r'^([\'"].*)\s*', txt)
-        if match:
-            chunk = match.group(1)
-            if raise_on_unbalanced:
-                raise Exception("Unbalanced quotes in »%s«." % ( str(text) ) )
-            else:
-                last_chunk += chunk
-                continue
-
-        # Here we should not come to ...
-        raise Exception("Broken split of »%s«: »%s« left" %( str(text), txt))
-
-    if last_chunk != '':
-        chunks.append(last_chunk)
-
-    return chunks
-
-#------------------------------------------------------------------------
-
-def email_valid(address):
-    '''
-    Simple Check for E-Mail addresses
-
-    @param address: the mail address to check
-    @type address:  str
-
-    @return: Validity of the given mil address
-    @rtype:  bool
-    '''
-
-    if address is None:
-        return False
-
-    adr = str(address)
-    if adr is None or adr == '':
-        return False
-
-    pattern = r'^[a-z0-9._%-+]+@[a-z0-9._%-]+.[a-z]{2,6}$'
-    if re.search(pattern, adr, re.IGNORECASE) is None:
-        return False
-
-    return True
-
-#------------------------------------------------------------------------
-
-def human2bytes(value, si_conform = True, use_locale_radix = False, verbose = 0):
-    '''
-    Converts the given human readable byte value (e.g. 5MB, 8.4GiB etc.)
-    with a prefix into an integer/long value (without a prefix).
-    It raises a ValueError on invalid values.
-
-    Available prefixes are:
-        - kB (1000), KB (1024), KiB (1024)
-        - MB (1000*1000), MiB (1024*1024)
-        - GB (1000³), GiB (1024³)
-        - TB (1000^4), TiB (1024^4)
-        - PB (1000^5), PiB (1024^5)
-
-    @param value:            the value to convert
-    @type value:             str
-    @param si_conform:       use factor 1000 instead of 1024 for kB a.s.o.
-    @type si_conform:        bool
-    @param use_locale_radix: use the locale version of radix instead of the
-                             english decimal dot.
-    @type use_locale_radix:  bool
-    @param verbose:          level of verbosity
-    @type verbose:           int
-
-    @return: amount of bytes
-    @rtype:  long
-    '''
-
-    t = gettext.translation('LogRotateCommon', locale_dir, fallback=True)
-    _ = t.lgettext
-
-    if value is None:
-        msg = _("Given value is 'None'.")
-        raise ValueError(msg)
-
-    radix = '.'
-    if use_locale_radix:
-        radix = locale.RADIXCHAR
-    radix = re.escape(radix)
-    if verbose > 5:
-        msg = _("using radix '%s'.") % (radix)
-        logger.debug(msg)
-
-    value_raw = ''
-    prefix = None
-    pattern = r'^\s*\+?(\d+(?:' + radix + r'\d*)?)\s*(\S+)?'
-    match = re.search(pattern, value)
-    if match is not None:
-        value_raw = match.group(1)
-        prefix = match.group(2)
-    else:
-        msg = _("Could not determine bytes in '%s'.") % (value)
-        raise ValueError(msg)
-
-    if use_locale_radix:
-        value_raw = re.sub(radix, '.', value_raw, 1)
-    value_float = float(value_raw)
-    if prefix is None:
-        prefix = ''
-
-    factor_bin = long(1024)
-    factor_si  = long(1000)
-    if not si_conform:
-        factor_si = factor_bin
-
-    factor = long(1)
-
-    if re.search(r'^\s*(?:b(?:yte)?)?\s*$', prefix, re.IGNORECASE):
-        factor = long(1)
-    elif re.search(r'^\s*k(?:[bB](?:[Yy][Tt][Ee])?)?\s*$', prefix):
-        factor = factor_si
-    elif re.search(r'^\s*Ki?(?:[bB](?:[Yy][Tt][Ee])?)?\s*$', prefix):
-        factor = factor_bin
-    elif re.search(r'^\s*M(?:B(?:yte)?)?\s*$', prefix, re.IGNORECASE):
-        factor = (factor_si * factor_si)
-    elif re.search(r'^\s*MiB(?:yte)?\s*$', prefix, re.IGNORECASE):
-        factor = (factor_bin * factor_bin)
-    elif re.search(r'^\s*G(?:B(?:yte)?)?\s*$', prefix, re.IGNORECASE):
-        factor = (factor_si * factor_si * factor_si)
-    elif re.search(r'^\s*GiB(?:yte)?\s*$', prefix, re.IGNORECASE):
-        factor = (factor_bin * factor_bin * factor_bin)
-    elif re.search(r'^\s*T(?:B(?:yte)?)?\s*$', prefix, re.IGNORECASE):
-        factor = (factor_si * factor_si * factor_si * factor_si)
-    elif re.search(r'^\s*TiB(?:yte)?\s*$', prefix, re.IGNORECASE):
-        factor = (factor_bin * factor_bin * factor_bin * factor_bin)
-    elif re.search(r'^\s*P(?:B(?:yte)?)?\s*$', prefix, re.IGNORECASE):
-        factor = (factor_si * factor_si * factor_si * factor_si * factor_si)
-    elif re.search(r'^\s*PiB(?:yte)?\s*$', prefix, re.IGNORECASE):
-        factor = (factor_bin * factor_bin * factor_bin * factor_bin * factor_bin)
-    else:
-        msg = _("Couldn't detect prefix '%s'.") % (prefix)
-        raise ValueError(msg)
-
-    if verbose > 5:
-        msg = _("Found factor %d.") % (factor)
-        logger.debug(msg)
-
-    return long(factor * value_float)
-
-#------------------------------------------------------------------------
-
-def period2days(period, use_locale_radix = False, verbose = 0):
-    '''
-    Converts the given string of the form »5d 8h« in an amount of days.
-    It raises a ValueError on invalid values.
-
-    Special values of period:
-        - now (returns 0)
-        - never (returns float('inf'))
-
-    Valid units for periods are:
-        - »h[ours]«
-        - »d[ays]«   - default, if bare numbers are given
-        - »w[eeks]«  - == 7 days
-        - »m[onths]« - == 30 days
-        - »y[ears]«  - == 365 days
-
-    @param period:           the period to convert
-    @type period:            str
-    @param use_locale_radix: use the locale version of radix instead of the
-                             english decimal dot.
-    @type use_locale_radix:  bool
-    @param verbose:          level of verbosity
-    @type verbose:           int
-
-    @return: amount of days
-    @rtype:  float
-    '''
-
-    t = gettext.translation('LogRotateCommon', locale_dir, fallback=True)
-    _ = t.lgettext
-
-    if period is None:
-        msg = _("Given period is 'None'.")
-        raise ValueError(msg)
-
-    value = str(period).strip().lower()
-    if period == '':
-        msg = _("Given period was empty")
-        raise ValueError(msg)
-
-    if verbose > 4:
-        msg = _("Called with '%s'.") % (period)
-        logger.debug(msg)
-
-    if period == 'now':
-        return float(0)
-
-    # never - returns a positive infinite value
-    if period == 'never':
-        return float('inf')
-
-    days = float(0)
-    radix = '.'
-    if use_locale_radix:
-        radix = locale.RADIXCHAR
-    radix = re.escape(radix)
-    if verbose > 5:
-        msg = _("Using radix '%s'.") % (radix)
-        logger.debug(msg)
-
-    # Search for hours in value
-    pattern = r'(\d+(?:' + radix + r'\d*)?)\s*h(?:ours?)?'
-    if verbose > 5:
-        msg = _("Pattern '%s'.") % (pattern)
-        logger.debug(msg)
-    match = re.search(pattern, value, re.IGNORECASE)
-    if match:
-        hours_str = match.group(1)
-        if use_locale_radix:
-            hours_str = re.sub(radix, '.', hours_str, 1)
-        hours = float(hours_str)
-        days += (hours/24)
-        if verbose > 4:
-            msg = _("Found %f hours.") % (hours)
-            logger.debug(msg)
-        value = re.sub(pattern, '', value, re.IGNORECASE)
-    if verbose > 5:
-        msg = _("Rest after hours: '%s'." % (value))
-        logger.debug(msg)
-
-    # Search for weeks in value
-    pattern = r'(\d+(?:' + radix + r'\d*)?)\s*w(?:eeks?)?'
-    if verbose > 5:
-        msg = _("Pattern '%s'.") % (pattern)
-        logger.debug(msg)
-    match = re.search(pattern, value, re.IGNORECASE)
-    if match:
-        weeks_str = match.group(1)
-        if use_locale_radix:
-            weeks_str = re.sub(radix, '.', weeks_str, 1)
-        weeks = float(weeks_str)
-        days += (weeks*7)
-        if verbose > 4:
-            msg = _("Found %f weeks.") % (weeks)
-            logger.debug(msg)
-        value = re.sub(pattern, '', value, re.IGNORECASE)
-    if verbose > 5:
-        msg = _("Rest after weeks: '%s'." % (value))
-        logger.debug(msg)
-
-    # Search for months in value
-    pattern = r'(\d+(?:' + radix + r'\d*)?)\s*m(?:onths?)?'
-    if verbose > 5:
-        msg = _("Pattern '%s'.") % (pattern)
-        logger.debug(msg)
-    match = re.search(pattern, value, re.IGNORECASE)
-    if match:
-        months_str = match.group(1)
-        if use_locale_radix:
-            months_str = re.sub(radix, '.', months_str, 1)
-        months = float(months_str)
-        days += (months*30)
-        if verbose > 4:
-            msg = _("Found %f months.") % (months)
-            logger.debug(msg)
-        value = re.sub(pattern, '', value, re.IGNORECASE)
-    if verbose > 5:
-        msg = _("Rest after months: '%s'." % (value))
-        logger.debug(msg)
-
-    # Search for years in value
-    pattern = r'(\d+(?:' + radix + r'\d*)?)\s*y(?:ears?)?'
-    if verbose > 5:
-        msg = _("Pattern '%s'.") % (pattern)
-        logger.debug(msg)
-    match = re.search(pattern, value, re.IGNORECASE)
-    if match:
-        years_str = match.group(1)
-        if use_locale_radix:
-            years_str = re.sub(radix, '.', years_str, 1)
-        years = float(years_str)
-        days += (years*365)
-        if verbose > 4:
-            msg = _("Found %f years.") % (years)
-            logger.debug(msg)
-        value = re.sub(pattern, '', value, re.IGNORECASE)
-    if verbose > 5:
-        msg = _("Rest after years: '%s'." % (value))
-        logger.debug(msg)
-
-    # At last search for days in value
-    pattern = r'(\d+(?:' + radix + r'\d*)?)\s*(?:d(?:ays?)?)?'
-    if verbose > 5:
-        msg = _("Pattern '%s'.") % (pattern)
-        logger.debug(msg)
-    match = re.search(pattern, value, re.IGNORECASE)
-    if match:
-        days_str = match.group(1)
-        if use_locale_radix:
-            days_str = re.sub(radix, '.', days_str, 1)
-        days_float = float(days_str)
-        days += days_float
-        if verbose > 4:
-            msg = _("Found %f days.") % (days_float)
-            logger.debug(msg)
-        value = re.sub(pattern, '', value, re.IGNORECASE)
-    if verbose > 5:
-        msg = _("Rest after days: '%s'." % (value))
-        logger.debug(msg)
-
-    # warn, if there is a rest
-    if re.search(r'^\s*$', value) is None:
-        msg = _("Invalid content for a period: '%s'.") % (value)
-        logger.warning(msg)
-
-    if verbose > 4:
-        msg = _("Total %f days found.") % (days)
-        logger.debug(msg)
-
-    return days
-
-#------------------------------------------------------------------------
-
-def get_address_list(address_str, verbose = 0):
-    '''
-    Retrieves all mail addresses from address_str and give them back
-    as a list of tuples.
-
-    @param address_str: the string with all mail addresses as a comma
-                        separated list
-    @type address_str:  str
-    @param verbose:     level of verbosity
-    @type verbose:      int
-
-    @return: list of tuples in the form of the return value
-             of email.utils.parseaddr()
-    @rtype:  list
-
-    '''
-
-    t = gettext.translation('LogRotateCommon', locale_dir, fallback=True)
-    _ = t.lgettext
-    pp = pprint.PrettyPrinter(indent=4)
-
-    addr_list = []
-    addresses = []
-
-    for row in csv.reader([address_str], doublequote=False, skipinitialspace=True):
-        for address in row:
-            addr_list.append(address)
-
-    if verbose > 2:
-        msg = _("Found address entries:") + "\n" + pp.pformat(addr_list)
-        logger.debug(msg)
-
-    for address in addr_list:
-        address = re.sub(r',', ' ', address)
-        address = re.sub(r'\s+', ' ', address)
-        pair = email.utils.parseaddr(address)
-        if verbose > 2:
-            msg = _("Got mail address pair:") + "\n" + pp.pformat(pair)
-            logger.debug(msg)
-        if not email_valid(pair[1]):
-            msg = _("Found invalid mail address '%s'.") % (address)
-            logger.warning(msg)
-            continue
-        addresses.append(pair)
-
-    return addresses
-
-#------------------------------------------------------------------------
-
-def to_unicode_or_bust(obj, encoding='utf-8'):
-    '''
-    Transforms a string, what is not a unicode string, into a unicode string.
-    All other objects are left untouched.
-
-    @param obj: the object to transform
-    @type obj:  object
-    @param encoding: the encoding to use to decode the object
-                     defaults to 'utf-8'
-    @type encoding:  str
-
-    @return: the maybe decoded object
-    @rtype:  object
-    '''
-
-    if isinstance(obj, basestring):
-        if not isinstance(obj, unicode):
-            obj = unicode(obj, encoding)
-
-    return obj
-
-#========================================================================
-
-if __name__ == "__main__":
-    pass
-
-#========================================================================
-
-# vim: fileencoding=utf-8 filetype=python ts=4 expandtab
diff --git a/LogRotateConfig.py b/LogRotateConfig.py
deleted file mode 100755 (executable)
index ba613de..0000000
+++ /dev/null
@@ -1,2038 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-# $Id$
-# $URL$
-
-'''
-@author: Frank Brehm
-@contact: frank@brehm-online.com
-@license: GPL3
-@copyright: (c) 2010-2011 by Frank Brehm, Berlin
-@version: 0.0.2
-@summary: module the configuration parsing object for Python logrotating
-'''
-
-import re
-import sys
-import gettext
-import pprint
-import os
-import os.path
-import pwd
-import grp
-import glob
-import logging
-import email.utils
-
-from LogRotateCommon import split_parts, email_valid, period2days, human2bytes
-from LogRotateCommon import get_address_list
-from LogRotateScript import LogRotateScript
-
-revision = '$Revision$'
-revision = re.sub( r'\$', '', revision )
-revision = re.sub( r'Revision: ', r'r', revision )
-revision = re.sub( r'\s*$', '', revision )
-
-__author__    = 'Frank Brehm'
-__copyright__ = '(C) 2011 by Frank Brehm, Berlin'
-__contact__    = 'frank@brehm-online.com'
-__version__    = '0.1.2 ' + revision
-__license__    = 'GPL3'
-
-
-#========================================================================
-# Module variables
-
-# @var: dict with all valid taboo pattern types as keys
-#       and the resulting regex template for the filename as value
-pattern_types = {
-    'ext':    r'%s$',
-    'file':   r'^%s$',
-    'prefix': r'^%s',
-}
-
-script_directives = [
-    'postrotate',
-    'prerotate',
-    'firstaction',
-    'lastaction',
-]
-
-unsupported_options = (
-    'uncompresscmd',
-    'error',
-)
-
-options_with_values = (
-    'mail',
-    'compresscmd',
-    'statusfile',
-    'pidfile',
-    'compressext',
-    'rotate',
-    'maxage',
-    'mailfrom',
-    'smtphost',
-    'smtpport',
-    'smtptls',
-    'smtpuser',
-    'smtppasswd',
-)
-
-boolean_options = (
-    'compress',
-    'copy',
-    'copytruncate',
-    'ifempty',
-    'missingok',
-    'sharedscripts',
-)
-
-integer_options = (
-    'delaycompress',
-    'rotate',
-    'start',
-)
-
-string_options = (
-    'extension',
-    'compresscmd',
-    'compressext',
-    'compressoptions',
-)
-
-global_options = (
-    'statusfile',
-    'pidfile',
-    'mailfrom',
-    'smtphost',
-    'smtpport',
-    'smtptls',
-    'smtpuser',
-    'smtppasswd',
-)
-
-path_options = (
-    'statusfile',
-    'pidfile',
-)
-
-valid_periods = {
-    'hourly':   (1/24),
-    '2hourly':  (1/12),
-    '4hourly':  (1/6),
-    '6hourly':  (1/4),
-    '12hourly': (1/2),
-    'daily':    1,
-    '2daily':   2,
-    'weekly':   7,
-    'monthly':  30,
-    '2monthly': 60,
-    '4monthly': 120,
-    '6monthly': 182,
-    'yearly':   365,
-}
-
-yes_values = (
-    '1',
-    'on',
-    'y',
-    'yes',
-    'true',
-)
-
-no_values = (
-    '0',
-    'off',
-    'n',
-    'no',
-    'false',
-)
-
-
-#========================================================================
-
-class LogrotateConfigurationError(Exception):
-    '''
-    Base class for exceptions in this module.
-    '''
-
-#========================================================================
-
-class LogrotateConfigurationReader(object):
-    '''
-    Class for reading the configuration for Python logrotating
-
-    @author: Frank Brehm
-    @contact: frank@brehm-online.com
-    '''
-
-    #-------------------------------------------------------
-    def __init__( self, config_file,
-                        verbose   = 0,
-                        local_dir = None,
-                        test_mode = False,
-    ):
-        '''
-        Constructor.
-
-        @param config_file: the configuration file to use
-        @type config_file:  str
-        @param verbose:     verbosity (debug) level
-        @type verbose:      int
-        @param local_dir:   The directory, where the i18n-files (*.mo)
-                            are located. If None, then system default
-                            (/usr/share/locale) is used.
-        @type local_dir:    str or None
-        @param test_mode:   test mode - no write actions are made
-        @type test_mode:    bool
-
-        @return: None
-        '''
-
-        self.local_dir = local_dir
-        '''
-        @ivar: The directory, where the i18n-files (*.mo) are located.
-        @type: str or None
-        '''
-
-        self.t = gettext.translation(
-            'LogRotateConfig',
-            local_dir,
-            fallback = True
-        )
-        '''
-        @ivar: a gettext translation object
-        @type: gettext.translation
-        '''
-
-        _ = self.t.lgettext
-
-        self.verbose = verbose
-        '''
-        @ivar: verbosity level (0 - 9)
-        @type: int
-        '''
-
-        self.config_file = config_file
-        '''
-        @ivar: the initial configuration file to use
-        @type: str
-        '''
-
-        self.test_mode = test_mode
-        '''
-        @ivar: test mode - no write actions are made
-        @type: bool
-        '''
-
-        self.logger = logging.getLogger('pylogrotate.config')
-        '''
-        @ivar: logger object
-        @type: logging.getLogger
-        '''
-
-        self.global_option = {}
-        '''
-        @ivar: all global options
-        @type: dict
-        '''
-        self.global_option['smtphost'] = 'localhost'
-
-        #############################################
-        # the rest of instance variables:
-
-        self.search_path = ['/bin', '/usr/bin']
-        '''
-        @ivar: ordered list with directories, where executables are searched
-        @type: list
-        '''
-        self._init_search_path()
-
-        self.shred_command = '/usr/bin/shred'
-        '''
-        @ivar: the system command to shred aged rotated logfiles, if wanted
-        @type: str
-        '''
-        self.check_shred_command()
-
-        self.default = {}
-        '''
-        @ivar: the default values for  directives
-        @type: dict
-        '''
-        self._reset_defaults()
-
-        self.new_log = None
-        '''
-        @ivar: struct with the current log definition
-        @type: dict or None
-        '''
-
-        self.taboo = []
-        '''
-        @ivar: taboo patterns for including files of whole directories
-        @type: list
-        '''
-        self.add_taboo(r'\.rpmnew',        'ext');
-        self.add_taboo(r'\.rpmorig',       'ext');
-        self.add_taboo(r'\.rpmsave',       'ext');
-        self.add_taboo(r',v',              'ext');
-        self.add_taboo(r'\.swp',           'ext');
-        self.add_taboo(r'~',               'ext');
-        self.add_taboo(r'\.',              'prefix');
-        self.add_taboo(r'\.bak',           'ext');
-        self.add_taboo(r'\.old',           'ext');
-        self.add_taboo(r'\.rej',           'ext');
-        self.add_taboo(r'CVS',             'file');
-        self.add_taboo(r'RCS',             'file');
-        self.add_taboo(r'\.disabled',      'ext');
-        self.add_taboo(r'\.dpkg-old',      'ext');
-        self.add_taboo(r'\.dpkg-dist',     'ext');
-        self.add_taboo(r'\.dpkg-new',      'ext');
-        self.add_taboo(r'\.cfsaved',       'ext');
-        self.add_taboo(r'\.ucf-old',       'ext');
-        self.add_taboo(r'\.ucf-dist',      'ext');
-        self.add_taboo(r'\.ucf-new',       'ext');
-        self.add_taboo(r'\.cfsaved',       'ext');
-        self.add_taboo(r'\.rhn-cfg-tmp-*', 'ext');
-
-        self.config_files = {}
-        '''
-        @ivar: dict with all called and included configuration files
-               to avoid double including
-        @type: dict
-        '''
-
-        self.config_was_read = False
-        '''
-        @ivar: flag whether the configuration file was read.
-        @type: bool
-        '''
-
-        self.config = []
-        '''
-        @ivar: the configuration, how it was read from cofiguration file(s)
-        @type: list
-        '''
-
-        self.scripts = {}
-        '''
-        @ivar: dict of LogRotateScript objects
-               with all named scripts found in configuration
-        @type: dict
-        '''
-
-        self.defined_logfiles = {}
-        '''
-        @ivar: all even defined logfiles after globing of file patterns
-        @type: dict
-        '''
-
-        self.logger.debug( _("Logrotate config reader initialised") )
-
-    #------------------------------------------------------------
-    def __str__(self):
-        '''
-        Typecasting function for translating object structure
-        into a string
-
-        @return: structure as string
-        @rtype:  str
-        '''
-
-        pp = pprint.PrettyPrinter(indent=4)
-        structure = self.as_dict()
-        return pp.pformat(structure)
-
-    #-------------------------------------------------------
-    def as_dict(self):
-        '''
-        Transforms the elements of the object into a dict
-
-        @return: structure as dict
-        @rtype:  dict
-        '''
-
-        res = {
-            'config':           self.config,
-            'config_file':      self.config_file,
-            'config_files':     self.config_files,
-            'config_was_read':  self.config_was_read,
-            'default':          self.default,
-            'defined_logfiles': self.defined_logfiles,
-            'global_option':    self.global_option,
-            'logger':           self.logger,
-            'local_dir':        self.local_dir,
-            'new_log':          self.new_log,
-            'search_path':      self.search_path,
-            'scripts':          {},
-            'shred_command':    self.shred_command,
-            't':                self.t,
-            'taboo':            self.taboo,
-            'test_mode':        self.test_mode,
-            'verbose':          self.verbose,
-        }
-
-        for script_name in self.scripts.keys():
-            res['scripts'][script_name] = self.scripts[script_name].as_dict()
-
-        return res
-
-    #------------------------------------------------------------
-    def _reset_defaults(self):
-        '''
-        Resetting self.default to the hard coded values
-        '''
-
-        _ = self.t.lgettext
-
-        if self.verbose > 3:
-            self.logger.debug( _("Resetting default values for directives to hard coded values"))
-
-        self.default = {}
-
-        self.default['compress']      = False
-        self.default['compresscmd']   = 'internal_gzip'
-        self.default['compressext']   = None
-        self.default['compressoptions']  = None
-        self.default['copy']          = False
-        self.default['copytruncate']  = False
-        self.default['create']        = {
-            'enabled': False,
-            'mode':    None,
-            'owner':   None,
-            'group':   None,
-        }
-        self.default['period']        = 7
-        self.default['dateext']       = False
-        self.default['datepattern']   = '%Y-%m-%d'
-        self.default['delaycompress'] = None
-        self.default['extension']     = ""
-        self.default['ifempty']       = True
-        self.default['mailaddress']   = None
-        self.default['mailfirst']     = None
-        self.default['maxage']        = None
-        self.default['missingok']     = False
-        self.default['olddir']        = {
-            'dirname':    '',
-            'dateformat': False,
-            'enabled':    False,
-            'mode':       None,
-            'owner':      None,
-            'group':      None,
-        }
-        self.default['rotate']        = 4
-        self.default['sharedscripts'] = False
-        self.default['shred']         = False
-        self.default['size']          = None
-        self.default['start']         = 0
-
-    #------------------------------------------------------------
-    def add_taboo(self, pattern, pattern_type = 'file'):
-        '''
-        Add a pattern to the list of taboo patterns self.taboo
-        Raises a general exception, if pattern_type is invalid
-
-        @param pattern:      The patten to append to the taboo list
-        @type pattern:       str
-        @param pattern_type: The type of the taboo pattern
-                            ('ext', 'file' or 'prefix')
-        @type pattern_type:  str
-
-        @return: None
-        '''
-
-        _ = self.t.lgettext
-
-        if not pattern_type in pattern_types:
-            raise Exception( _("Invalid taboo pattern type '%s' given") % (pattern_type) )
-
-        pattern = ( pattern_types[pattern_type] % pattern )
-        if self.verbose > 3:
-            self.logger.debug( _("New taboo pattern: '%s'.") % (pattern) )
-
-        self.taboo.append(pattern)
-
-    #------------------------------------------------------------
-    def _init_search_path(self):
-        '''
-        Initialises the internal list of search pathes
-
-        @return: None
-        '''
-
-        _ = self.t.lgettext
-        dir_included = {}
-
-        # Including default path list from environment $PATH
-        def_path = os.environ['PATH']
-        if not def_path:
-            def_path = ''
-        sep = os.pathsep
-        path_list = []
-        for item in def_path.split(sep):
-            if item:
-                if os.path.isdir(item):
-                    real_dir = os.path.abspath(item)
-                    if not real_dir in dir_included:
-                        path_list.append(real_dir)
-                        dir_included[real_dir] = True
-                else:
-                    self.logger.debug( _("'%s' is not a directory") % (item))
-                        
-        # Including default path list from python
-        def_path = os.defpath
-        for item in def_path.split(sep):
-            if item:
-                if os.path.isdir(item):
-                    real_dir = os.path.abspath(item)
-                    if not real_dir in dir_included:
-                        path_list.append(real_dir)
-                        dir_included[real_dir] = True
-                else:
-                    self.logger.debug( _("'%s' is not a directory") % (item))
-
-        # Including own defined directories
-        for item in ('/usr/local/bin', '/sbin', '/usr/sbin', '/usr/local/sbin'):
-            if os.path.isdir(item):
-                real_dir = os.path.abspath(item)
-                if not real_dir in dir_included:
-                    path_list.append(real_dir)
-                    dir_included[real_dir] = True
-            else:
-                self.logger.debug( _("'%s' is not a directory") % (item))
-
-        self.search_path = path_list
-
-    #------------------------------------------------------------
-    def _get_std_search_path(self, include_current = False):
-        '''
-        Returns a list with all search directories from $PATH and some additionally
-        directiories.
-
-        @param include_current: include the current working directory
-                                at the end of the list
-        @type include_current:  bool
-
-        @return: list of search directories
-        @rtype:  list
-        '''
-
-        #_ = self.t.lgettext
-
-        path_list = self.search_path
-        if include_current:
-            item = os.getcwd()
-            real_dir = os.path.abspath(item)
-            path_list.append(real_dir)
-
-        return path_list
-
-    #------------------------------------------------------------
-    def check_shred_command(self):
-        '''
-        Checks the availability of a check command. Sets self.shred_command to
-        this system command or to None, if not found (including a warning).
-        '''
-
-        _ = self.t.lgettext
-        path_list = self._get_std_search_path(True)
-
-        cmd = None
-        found = False
-        for search_dir in path_list:
-            if os.path.isdir(search_dir):
-                cmd = os.path.join(search_dir, 'shred')
-                if not os.path.isfile(cmd):
-                    continue
-                if os.access(cmd, os.X_OK):
-                    found = True
-                    break
-            else:
-                self.logger.debug( _("Search path '%s' doesn't exists or is not a directory") % (search_dir))
-
-        if found:
-            self.logger.debug( _("Shred command found: '%s'") %(cmd) )
-            self.shred_command = cmd
-            return True
-        else:
-            self.logger.warning( _("Shred command not found, shred disabled") )
-            self.shred_command = None
-            return False
-
-    #------------------------------------------------------------
-    def check_compress_command(self, command):
-        '''
-        Checks the availability of the given compress command.
-
-        'internal_zip, 'internal_gzip' and 'internal_bzip2' are accepted as
-        valid compress commands for compressing with the appropriate python modules.
-
-        @param command: command to validate (absolute or relative for
-                        searching in standard search path)
-        @type command:  str
-
-        @return: absolute path of the compress command, 'internal_gzip',
-                 'internal_bzip2' or None if not found or invalid
-        @rtype:  str or None
-        '''
-
-        _ = self.t.lgettext
-        path_list = self._get_std_search_path(True)
-
-        match = re.search(r'^\s*internal[\-_\s]?zip\s*', command, re.IGNORECASE)
-        if match:
-            return 'internal_zip'
-
-        match = re.search(r'^\s*internal[\-_\s]?gzip\s*', command, re.IGNORECASE)
-        if match:
-            return 'internal_gzip'
-
-        match = re.search(r'^\s*internal[\-_\s]?bzip2\s*', command, re.IGNORECASE)
-        if match:
-            return 'internal_bzip2'
-
-        if os.path.isabs(command):
-            if os.access(command, os.X_OK):
-                return os.path.abspath(command)
-            else:
-                return None
-
-        cmd = None
-        found = False
-        for search_dir in path_list:
-            if os.path.isdir(search_dir):
-                cmd = os.path.join(search_dir, command)
-                if not os.path.isfile(cmd):
-                    continue
-                if os.access(cmd, os.X_OK):
-                    found = True
-                    break
-            else:
-                self.logger.debug( _("Search path '%s' doesn't exists or is not a directory") % (search_dir))
-
-        if found:
-            return os.path.abspath(cmd)
-        else:
-            return None
-
-    #------------------------------------------------------------
-    def get_config(self):
-        '''
-        Returns the configuration, how it was read from configuration file(s)
-
-        @return: configuration
-        @rtype:  dict or None
-        '''
-
-        if not self._read_main_configfile():
-            return None
-
-        return self.config
-
-    #------------------------------------------------------------
-    def get_scripts(self):
-        '''
-        Returns the scriptlist, how it was read from configuration file(s)
-
-        @return: list of scripts
-        @rtype:  list
-        '''
-
-        if not self._read_main_configfile():
-            return None
-
-        return self.scripts
-
-    #------------------------------------------------------------
-    def _read_main_configfile(self):
-        '''
-        Reads the main configuration file (self.config_file).
-
-        @return: success of reading
-        @rtype:  bool
-        '''
-
-        _ = self.t.lgettext
-
-        if self.config_was_read:
-            return True
-
-        if not os.path.exists(self.config_file):
-            raise LogrotateConfigurationError( _("File '%s' doesn't exists.") % (self.config_file))
-
-        self.config_file = os.path.abspath(self.config_file)
-
-        if not self._read(self.config_file):
-            return None
-
-        self.config_was_read = True
-        return True
-
-    #------------------------------------------------------------
-    def _read(self, configfile):
-        '''
-        Reads the configuration from given configuration file and all
-        included files.
-
-        @param configfile: the configfile to read
-        @type configfile:  str
-        '''
-
-        _ = self.t.lgettext
-        pp = pprint.PrettyPrinter(indent=4)
-        self.logger.debug( _("Try reading configuration from '%s' ...") % (configfile) )
-
-        if not os.path.exists(configfile):
-            raise LogrotateConfigurationError( _("File '%s' doesn't exists.") % (configfile))
-
-        if not os.path.isfile(configfile):
-            raise LogrotateConfigurationError( _("'%s' is not a regular file.") % (configfile))
-
-        self.config_files[configfile] = True
-
-        self.logger.info( _("Reading configuration from '%s' ...") % (configfile) )
-
-        cfile = None
-        try:
-            cfile = open(configfile, 'Ur')
-        except IOError, e:
-            raise LogrotateConfigurationError( ( _("Could not read configuration file '%s'") % (configfile) ) + ': ' + str(e))
-        lines = cfile.readlines()
-        cfile.close()
-
-        # defaults for the big loop
-        linenr          = 0
-        in_fd           = False
-        in_script       = False
-        in_logfile_list = False
-        lastrow         = ''
-        newscript       = ''
-
-        # inspect every line of configuration file
-        for line in lines:
-
-            linenr += 1
-            line = line.strip()
-
-            # Perform a backslash at the end of the line
-            line = lastrow + line
-            match = re.search(r'\\$', line)
-            if match:
-                line = re.sub(r'\\$', '', line)
-                lastrow = line
-                continue
-            lastrow = ''
-
-            # delete comments
-            line = re.sub(r'^#.*', '', line)
-            if line == '':
-                continue
-
-            # perform script content
-            if in_script:
-                match = re.search(r'^endscript$', line)
-                if match:
-                    in_script = False
-                    continue
-                #self.scripts[newscript]['cmd'].append(line)
-                self.scripts[newscript].add_cmd(line)
-                continue
-
-            # start of a logfile definition
-            if line == '{':
-
-                if self.verbose > 3:
-                    self.logger.debug( ( _("Starting a logfile definition (file '%(file)s', line %(line)s)") 
-                                        % {'file': configfile, 'line': linenr}))
-
-                self._start_logfile_definition( 
-                    line            = line,
-                    filename        = configfile,
-                    in_fd           = in_fd,
-                    in_logfile_list = in_logfile_list,
-                    linenr          = linenr
-                )
-                in_fd = True
-                in_logfile_list = False
-                continue
-
-            # start of a logfile pattern
-            match = re.search(r'^[\'"]', line)
-            if match or os.path.isabs(line):
-
-                if in_fd:
-                    raise LogrotateConfigurationError(
-                        ( _("Logfile pattern definition not allowed inside a logfile definition (file '%(file)s', line %(line)s)")
-                            % {'file': configfile, 'line': linenr})
-                    )
-                do_start_logfile_definition = False
-
-                # look, whether a start of a logfile definition is necessary
-                match_bracket = re.search(r'\s*{\s*$', line)
-                if match_bracket:
-                    line = re.sub(r'\s*{\s*$', '', line)
-                    do_start_logfile_definition = True
-                if not in_logfile_list:
-                    self._start_new_log(configfile, linenr)
-                in_logfile_list = True
-
-                parts = split_parts(line)
-                if self.verbose > 3:
-                    self.logger.debug(
-                        ( _("Split into parts of: '%s'") % (line))
-                        + ":\n" + pp.pformat(parts)
-                    )
-
-                for pattern in parts:
-                    if pattern == '{':
-                        raise LogrotateConfigurationError(
-                            ( _("Syntax error: open curly bracket inside a logfile pattern definition (file '%(file)s', line %(line)s)")
-                                % {'file': configfile, 'line': linenr})
-                        )
-                    self.new_log['file_patterns'].append(pattern)
-
-                # start of a logfile definition, if necessary
-                if do_start_logfile_definition:
-                    self._start_logfile_definition( 
-                        line            = line,
-                        filename        = configfile,
-                        in_fd           = in_fd,
-                        in_logfile_list = in_logfile_list,
-                        linenr          = linenr
-                    )
-                    in_fd = True
-                    in_logfile_list = False
-
-                continue
-
-            # end of a logfile definition
-            match = re.search(r'^}(.*)', line)
-            if match:
-                if not in_fd:
-                    raise LogrotateConfigurationError(
-                        ( _("Syntax error: unbalanced closing curly bracket found (file '%(file)s', line %(line)s)")
-                            % {'file': configfile, 'line': linenr})
-                    )
-                rest = match.group(1)
-                if self.verbose > 2:
-                    self.logger.debug( ( _("End of a logfile definition (file '%(file)s', line %(line)s)") % {'file': configfile, 'line': linenr}))
-                if rest:
-                    self.logger.warning(
-                        ( _("Needless content found at the end of a logfile definition found: '%(rest)s' (file '%(file)s', line %(line)s)")
-                            % { 'rest': str(rest), 'file': configfile, 'line': linenr})
-                    )
-                # set a compress ext, if Compress is True
-                if self.new_log['compress']:
-                    if not self.new_log['compressext']:
-                        if self.new_log['compresscmd'] == 'internal_gzip':
-                            self.new_log['compressext'] = '.gz'
-                        elif self.new_log['compresscmd'] == 'internal_zip':
-                            self.new_log['compressext'] = '.zip'
-                        elif self.new_log['compresscmd'] == 'internal_bzip2':
-                            self.new_log['compressext'] = '.bz2'
-                        else:
-                            msg = _("No extension for compressed logfiles given " +
-                                    "(File of definition: '%(file)s', start definition: %(rownum)d).") \
-                                  % { 'file': self.new_log['configfile'], 'rownum': self.new_log['configrow']}
-                            raise LogrotateConfigurationError(msg)
-                # set ifempty => True, if a minsize was given
-                if self.new_log['size']:
-                    self.new_log['ifempty'] = False
-                found_files = self._assign_logfiles()
-                if self.verbose > 3:
-                    self.logger.debug( ( _("New logfile definition:") + "\n" + pp.pformat(self.new_log)))
-                if found_files > 0:
-                    if self.new_log['postrotate']:
-                        script = self.new_log['postrotate']
-                        if self.scripts[script]:
-                            self.scripts[script].post_files += found_files
-                        else:
-                            msg = _("Postrotate script '%s' not found.") % (script)
-                            self.logger.error(msg)
-                    if self.new_log['lastaction']:
-                        script = self.new_log['lastaction']
-                        if self.scripts[script]:
-                            self.scripts[script].last_files += found_files
-                        else:
-                            msg = _("Lastaction script '%s' not found.") % (script)
-                            self.logger.error(msg)
-                    self.config.append(self.new_log)
-                in_fd = False
-                in_logfile_list = False
-
-                continue
-
-            # performing includes
-            match = re.search(r'^include(?:\s+(.*))?$', line, re.IGNORECASE)
-            if match:
-                rest = match.group(1)
-                if in_fd or in_logfile_list:
-                    self.logger.warning(
-                        ( _("Syntax error: include may not appear inside of log file definition (file '%(file)s', line %(line)s)")
-                            % {'file': configfile, 'line': linenr})
-                    )
-                    continue
-                self._do_include(line, rest, configfile, linenr)
-                continue
-
-            # start of a (regular) script definition
-            pattern = r'^(' + '|'.join(script_directives) + r')(\s+.*)?$'
-            match = re.search(pattern, line, re.IGNORECASE)
-            if match:
-                script_type = match.group(1).lower()
-                script_name = None
-                if match.group(2) is not None:
-                    values      = split_parts(match.group(2))
-                    if values[0]:
-                        script_name = values[0]
-                if self.verbose > 3:
-                    self.logger.debug(
-                        ( _("Found start of a regular script definition: type: '%(type)s', name: '%(name)s' (file '%(file)s', line %(line)s)")
-                            % {'type': script_type, 'name': script_name, 'file': configfile, 'line': linenr})
-                    )
-                newscript = self._start_log_script_definition(
-                    script_type = script_type,
-                    script_name = script_name,
-                    line        = line,
-                    filename    = configfile,
-                    in_fd       = in_fd,
-                    linenr      = linenr,
-                )
-                if newscript:
-                    in_script = True
-                if self.verbose > 3:
-                    self.logger.debug( ( _("New log script name: '%s'.") % (newscript) ))
-                continue
-
-            # start of an explicite external script definition
-            match = re.search(r'^script(\s+.*)?$', line, re.IGNORECASE)
-            if match:
-                if self.verbose > 3:
-                    self.logger.debug( ( _("Found start of a external script definition. (file '%(file)s', line %(line)s)")
-                                        % {'file': configfile, 'line': linenr})
-                    )
-                rest = match.group(1)
-                if in_fd or in_logfile_list:
-                    self.logger.warning(
-                        ( _("Syntax error: external script definition may not appear inside of a log file definition (file '%(file)s', line %(line)s)")
-                            % {'file': configfile, 'line': linenr})
-                    )
-                    continue
-                newscript = self._ext_script_definition(
-                    line, rest, configfile, linenr
-                )
-                if newscript:
-                    in_script = True
-                if self.verbose > 3:
-                    self.logger.debug( ( _("New external script name: '%s'.") % (newscript) ))
-                continue
-
-            # all other options
-            if not self._option(line, in_fd, configfile, linenr):
-                self.logger.warning( ( _("Syntax error in file '%(file)s', line %(line)s")
-                    % {'file': configfile, 'line': linenr})
-                )
-
-        return True
-
-    #------------------------------------------------------------
-    def _option(self, line, in_fd, filename, linenr):
-        '''
-        Checks the given line as a logrotate option and assign this
-        option on success to the default options or in the current
-        logfile directive
-
-        @param line:     line of current config file
-        @type line:      str
-        @param in_fd:    parsing inside a logfile definition
-        @type in_fd:     bool
-        @param filename: current configuration file
-        @type filename:  str
-        @param linenr:   current line number of configuration file
-        @type linenr:    int
-
-        @return: success of parsing this option
-        @rtype:  bool
-        '''
-
-        _ = self.t.lgettext
-        if self.verbose > 4:
-            self.logger.debug(
-                ( _("Checking line '%(line)s' for a logrotate option. (file '%(file)s', line %(lnr)s)")
-                    % {'line': line, 'file': filename, 'lnr': linenr})
-            )
-
-        # where to insert the option?
-        directive = self.default
-        directive_str = 'default'
-        if in_fd:
-            directive = self.new_log
-            directive_str = 'new_log'
-
-        # extract option from line
-        option = None
-        val    = None
-        match = re.search(r'^(\S+)\s*(.*)', line)
-        if match:
-            option = match.group(1).lower()
-            val    = match.group(2)
-        else:
-            self.logger.warning( ( _("Could not detect option in line '%s'.") % (line)))
-            return False
-        val = re.sub(r'^\s+$', '', val)
-        if self.verbose > 4:
-            msg = _("Found option '%(opt)s' with value '%(val)s'.") \
-                    % {'opt': option, 'val': val}
-            self.logger.debug(msg)
-
-        # Check for unsupported options
-        pattern = r'^(' + '|'.join(unsupported_options) + r')$'
-        match = re.search(pattern, option, re.IGNORECASE)
-        if match:
-            self.logger.info(
-                ( _("Unsupported option '%(option)s'. (file '%(file)s', line %(lnr)s)")
-                    % {'option': match.group(1).lower(), 'file': filename, 'lnr': linenr})
-            )
-            return True
-
-        # Check for boolean option
-        pattern = r'^(not?)?(' + '|'.join(boolean_options) + r')$'
-        match = re.search(pattern, option, re.IGNORECASE)
-        if match:
-            negated = match.group(1)
-            key     = match.group(2).lower()
-            if val:
-                self.logger.warning(
-                    ( _("Found value '%(value)s' behind the boolean option '%(option)s', ignoring. (file '%(file)s', line %(lnr)s)")
-                        % {'value': val, 'option': option, 'file': filename, 'lnr': linenr})
-                )
-            if negated is None:
-                option_value = True
-            else:
-                option_value = False
-            if self.verbose > 4:
-                self.logger.debug(
-                    ( _("Setting boolean option '%(option)s' in '%(directive)s' to '%(value)s'. (file '%(file)s', line %(lnr)s)")
-                        % {'option': key, 'directive': directive_str, 'value': str(option_value), 'file': filename, 'lnr': linenr})
-                )
-            directive[key] = option_value
-            if key == 'copy' and option_value:
-                if directive['copytruncate']:
-                    msg = _("Option 'copy' disables option 'copytruncate'. (file '%(file)s', line %(lnr)s)") \
-                            % {'file': filename, 'lnr': linenr}
-                    self.logger.warning(msg)
-                    directive['copytruncate'] = False
-                if directive['create']['enabled']:
-                    msg = _("Option 'copy' disables option 'create'. (file '%(file)s', line %(lnr)s)") \
-                            % {'file': filename, 'lnr': linenr}
-                    self.logger.warning(msg)
-                    directive['create']['enabled'] = False
-            elif key == 'copytruncate' and option_value:
-                if directive['copy']:
-                    msg = _("Option 'copytruncate' disables option 'copy'. (file '%(file)s', line %(lnr)s)") \
-                            % {'file': filename, 'lnr': linenr}
-                    self.logger.warning(msg)
-                    directive['copy'] = False
-                if directive['create']['enabled']:
-                    msg = _("Option 'copytruncate' disables option 'create'. (file '%(file)s', line %(lnr)s)") \
-                            % {'file': filename, 'lnr': linenr}
-                    self.logger.warning(msg)
-                    directive['create']['enabled'] = False
-            return True
-
-        # Check for integer options
-        pattern = r'^(not?)?(' + '|'.join(integer_options) + r')$'
-        match = re.search(pattern, option, re.IGNORECASE)
-        if match:
-            negated = match.group(1)
-            key     = match.group(2).lower()
-            option_value = 0
-            if negated is None:
-                if key in options_with_values:
-                    if val is None or val == '':
-                        self.logger.warning( ( _("Option '%s' without a necessary value.") % (key)))
-                        return False
-                else:
-                    if val is None or val == '':
-                        val = '1'
-                try:
-                    option_value = long(val)
-                except ValueError, e:
-                    self.logger.warning(
-                        ( _("Option '%(option)s' has no integer value: %(msg)s.")
-                            % {'option': key, 'msg': str(e)})
-                    )
-                    return False
-            if option_value < 0:
-                self.logger.warning(
-                    ( _("Negative value %(value)s for option '%(option)s' is not allowed.")
-                        % {'value': str(option_value), 'option': key})
-                )
-                return False
-            if self.verbose > 4:
-                self.logger.debug(
-                    ( _("Setting integer option '%(option)s' in '%(directive)s' to '%(value)s'. (file '%(file)s', line %(lnr)s)")
-                        % {'option': key, 'directive': directive_str, 'value': str(option_value), 'file': filename, 'lnr': linenr})
-                )
-            directive[key] = option_value
-            return True
-
-        # Check for mail address
-        match = re.search(r'^(not?)?mail$', option, re.IGNORECASE)
-        if match:
-            negated = match.group(1)
-            if negated:
-                directive['mailaddress'] = None
-                if val is not None and val != '':
-                    self.logger.warning(
-                        ( _("Senseless option value '%(value)s' after '%(option)s'.")
-                            % {'value': val, 'option': option.lower()})
-                    )
-                    return False
-                return True
-            address_list = get_address_list(val, self.verbose)
-            if len(address_list):
-                directive['mailaddress'] = address_list
-            else:
-                directive['mailaddress'] = None
-            if self.verbose > 4:
-                pp = pprint.PrettyPrinter(indent=4)
-                msg = _("Setting mail address in '%(directive)s' to '%(addr)s'. (file '%(file)s', line %(lnr)s)") \
-                    % {
-                        'directive': directive_str,
-                        'addr': pp.pformat(directive['mailaddress']),
-                        'file': filename,
-                        'lnr': linenr,
-                    }
-                self.logger.debug(msg)
-            return True
-
-        # Check for mailfirst/maillast
-        match = re.search(r'^mail(first|last)$', option, re.IGNORECASE)
-        if match:
-            when = match.group(1).lower()
-            option_value = False
-            if when == 'first':
-                option_value = True
-            directive['mailfirst'] = option_value
-            if self.verbose > 4:
-                self.logger.debug(
-                    ( _("Setting mailfirst in '%(directive)s' to '%(value)s'. (file '%(file)s', line %(lnr)s)")
-                        % {'directive': directive_str, 'value': str(option_value), 'file': filename, 'lnr': linenr})
-                )
-            if val is not None and val != '':
-                self.logger.warning(
-                    ( _("Senseless option value '%(value)s' after '%(option)s'.")
-                        % {'value': val, 'option': option.lower()})
-                )
-                return False
-            return True
-
-        # Check for string options
-        pattern = r'^(' + '|'.join(string_options) + r')$'
-        match = re.search(pattern, option, re.IGNORECASE)
-        if match:
-            key = match.group(1).lower()
-            if key in options_with_values:
-                if self.verbose > 5:
-                    self.logger.debug( ( _("Option '%s' must have a value.") %(key)))
-                if (val is None) or (val == ''):
-                    self.logger.warning( ( _("Option '%s' without a value") %(key)))
-                    return False
-            if key == 'compresscmd':
-                prog = self.check_compress_command(val)
-                if prog is None:
-                    self.logger.warning( ( _("Compress command '%s' not found.") %(val)))
-                    return False
-                val = prog
-            if key == 'compressoptions' and val is None:
-                val = ''
-            directive[key] = val
-            return True
-
-        # Check for global options
-        pattern = r'^(' + '|'.join(global_options) + r')$'
-        match = re.search(pattern, option, re.IGNORECASE)
-        if match:
-            key = match.group(1).lower()
-            if in_fd:
-                self.logger.warning( ( _("Option '%s' not allowed inside a logfile directive.") %(key)))
-                return False
-            if key in options_with_values:
-                if self.verbose > 5:
-                    self.logger.debug( ( _("Option '%s' must have a value.") %(key)))
-                if (val is None) or (re.search(r'^\s*$', val) is not None):
-                    self.logger.warning( ( _("Option '%s' without a value") %(key)))
-                    return False
-            if key in path_options:
-                if not os.path.abspath(val):
-                    self.logger.warning(
-                        ( _("Value '%(value)s' for option '%(option)s' is not an absolute path.")
-                            % {'value': val, 'option': key} )
-                    )
-                    return False
-            if key == 'mailfrom':
-               pair = email.utils.parseaddr(val)
-               if not email_valid(pair[1]):
-                    msg = _("Invalid mail address for 'mailfrom' given: '%s'.") % (val)
-                    self.logger.warning(msg)
-                    return False
-               val = pair
-            elif key == 'smtpport':
-                port = 25
-                try:
-                    port = int(val)
-                except ValueError, e:
-                    msg = _("Invalid SMTP port '%s' given.") % (val)
-                    self.logger.warning(msg)
-                    return False
-                if port < 1 or port >= 2**15:
-                    msg = _("Invalid SMTP port '%s' given.") % (val)
-                    self.logger.warning(msg)
-                    return False
-                val = port
-            elif key == 'smtptls':
-                use_tls = False
-                match = re.search(r'^\s*(?:0+|false|no?)\s*$', val, re.IGNORECASE)
-                if not match:
-                    match = re.search(r'^\s*(?:1|true|y(?:es)?)\s*$', val, re.IGNORECASE)
-                    if match:
-                        use_tls = True
-                    else:
-                        use_tls = bool(val)
-                val = use_tls
-            if self.verbose > 4:
-                self.logger.debug(
-                    ( _("Setting global option '%(option)s' to '%(value)s'. (file '%(file)s', line %(lnr)s)")
-                        % {'option': key, 'directive': directive_str, 'value': str(val), 'file': filename, 'lnr': linenr})
-                )
-            self.global_option[key] = val
-            return True
-
-        # Check for rotation period
-        pattern = r'^(' + '|'.join(valid_periods.keys()) + r'|period)$'
-        match = re.search(pattern, option, re.IGNORECASE)
-        if match:
-            key = match.group(1).lower()
-            if self.verbose > 4:
-                self.logger.debug(
-                    ( _("Checking 'period': key '%(key)s', value '%(value)s'. (file '%(file)s', line %(lnr)s)")
-                        % {'key': key, 'value': str(val), 'file': filename, 'lnr': linenr})
-                )
-            option_value = 1
-            if key in valid_periods:
-                if (val is not None) and (re.search(r'^\s*$', val) is None):
-                    self.logger.warning(
-                        ( _("Option '%(option)s' may not have a value ('%(value)s'). (file '%(file)s', line %(lnr)s)")
-                            % {'option': key, 'value': val, 'file': filename, 'lnr': linenr})
-                    )
-                option_value = valid_periods[key]
-            else:
-                try:
-                    option_value = period2days(val, verbose = self.verbose)
-                except ValueError, e:
-                    self.logger.warning( ( _("Invalid period definition: '%s'") %(val) ))
-                    return False
-            if self.verbose > 4:
-                self.logger.debug(
-                    ( _("Setting 'period' in '%(directive)s' to %(days)f days. (file '%(file)s', line %(lnr)s)")
-                        % {'directive': directive_str, 'days': option_value, 'file': filename, 'lnr': linenr})
-                )
-            directive['period'] = option_value
-            return True
-
-        # get maximum age of old rotated log files
-        match = re.search(r'^(not?)?maxage$', option, re.IGNORECASE)
-        if match:
-            negated = False
-            if match.group(1) is not None:
-                negated = True
-            if (val is None) or re.search(r'^\s*$', val) is not None:
-                negated = True
-            option_value = 0
-            if not negated:
-                try:
-                    option_value = period2days(val, verbose = self.verbose)
-                except ValueError, e:
-                    self.logger.warning( ( _("Invalid maxage definition: '%s'") %(val) ))
-                    return False
-            if self.verbose > 4:
-                self.logger.debug(
-                    ( _("Setting 'maxage' in '%(directive)s' to %(days)f days. (file '%(file)s', line %(lnr)s)")
-                        % {'directive': directive_str, 'days': option_value, 'file': filename, 'lnr': linenr})
-                )
-            directive['maxage'] = option_value
-            return True
-
-        # Setting date extension of rotated log files
-        match = re.search(r'^(no)?dateext$', option, re.IGNORECASE)
-        if match:
-
-            negated = False
-            if match.group(1) is not None:
-                negated = True
-            use_dateext = False
-            dateext = None
-
-            if self.verbose > 4:
-                self.logger.debug(
-                    ( _("Checking 'dateext', negated: '%(negated)s'. (file '%(file)s', line %(lnr)s)")
-                        % {'negated': str(negated), 'file': filename, 'lnr': linenr})
-                )
-            values = []
-            if val is not None:
-                values = split_parts(val) 
-
-            if not negated:
-                first_val = ''
-                if len(values) > 0:
-                    first_val = values[0].lower()
-                option_value = first_val
-                if first_val is None or \
-                        re.search(r'^\s*$', first_val) is not None:
-                    option_value = 'true'
-                if self.verbose > 5:
-                    self.logger.debug(
-                        ( _("'dateext': first_val: '%(first_val)s', option_value: '%(value)s'. (file '%(file)s', line %(lnr)s)")
-                            % {'first_val': first_val, 'value': option_value, 'file': filename, 'lnr': linenr})
-                    )
-                if option_value in yes_values:
-                    use_dateext = True
-                elif option_value in no_values:
-                    use_dateext = False
-                else:
-                    use_dateext = True
-                    dateext = val
-
-            if self.verbose > 4:
-                self.logger.debug(
-                    ( _("Setting 'dateext' in '%(directive)s' to %(ext)s. (file '%(file)s', line %(lnr)s)")
-                        % {'directive': directive_str, 'ext': str(use_dateext), 'file': filename, 'lnr': linenr})
-                )
-            directive['dateext'] = use_dateext
-
-            if dateext is not None:
-                if self.verbose > 4:
-                    self.logger.debug(
-                        ( _("Setting 'datepattern' in '%(directive)s' to '%(pattern)s'. (file '%(file)s', line %(lnr)s)")
-                            % {'directive': directive_str, 'pattern': dateext, 'file': filename, 'lnr': linenr})
-                    )
-                directive['datepattern'] = dateext
-
-            return True
-
-        # Checking for create options ...
-        match = re.search(r'(not?)?create$', option, re.IGNORECASE)
-        if match:
-
-            negated = False
-            if match.group(1) is not None:
-                negated = True
-
-            if self.verbose > 5:
-                self.logger.debug(
-                    ( _("Checking for 'create' ... (file '%(file)s', line %(lnr)s)")
-                        % {'file': filename, 'lnr': linenr})
-                )
-
-            if negated:
-                if self.verbose > 4:
-                    self.logger.debug(
-                        ( _("Removing 'create'. (file '%(file)s', line %(lnr)s)")
-                            % {'file': filename, 'lnr': linenr})
-                    )
-                directive['create']['enabled'] = False
-                return True
-
-            if directive['copy']:
-                msg = _("Option 'copy' was set, so option 'create' has no effect. (file '%(file)s', line %(lnr)s)") \
-                        % {'file': filename, 'lnr': linenr}
-                self.logger.warning(msg)
-                directive['create']['enabled'] = False
-                return True
-
-            if directive['copytruncate']:
-                msg = _("Option 'copytruncate' was set, so option 'create' has no effect. (file '%(file)s', line %(lnr)s)") \
-                        % {'file': filename, 'lnr': linenr}
-                self.logger.warning(msg)
-                directive['create']['enabled'] = False
-                return True
-
-            values = []
-            if val is not None:
-                values = split_parts(val)
-
-            directive['create']['enabled'] = True
-
-            mode  = None
-            owner = None
-            group = None
-
-            # Check for create mode
-            if len(values) > 0:
-                if self.verbose > 5:
-                    self.logger.debug(
-                        ( _("Trying to determine create mode '%(mode)s'... (file '%(file)s', line %(lnr)s)")
-                            % {'mode': values[0], 'file': filename, 'lnr': linenr})
-                    )
-                mode_octal = values[0]
-                if re.search(r'^0', mode_octal) is None:
-                    mode_octal = '0' + mode_octal
-                try:
-                    mode = int(mode_octal, 8)
-                except ValueError:
-                    self.logger.warning( ( _("Invalid create mode '%s'.") %(values[1])))
-                    return False
-
-            # Check for Owner (user, uid)
-            if len(values) > 1:
-                owner_raw = values[1]
-                if self.verbose > 5:
-                    self.logger.debug(
-                        ( _("Trying to determine create owner '%(owner)s'... (file '%(file)s', line %(lnr)s)")
-                            % {'owner': owner_raw, 'file': filename, 'lnr': linenr})
-                    )
-                if re.search(r'^[1-9]\d*$', owner_raw) is not None:
-                    owner = int(owner_raw)
-                else:
-                    try:
-                        owner = pwd.getpwnam(owner_raw)[2]
-                    except KeyError:
-                        self.logger.warning( ( _("Invalid owner '%s' in 'create'.") %(owner_raw)))
-                        return False
-
-            # Check for Group (gid)
-            if len(values) > 2:
-                group_raw = values[2]
-                if self.verbose > 5:
-                    self.logger.debug(
-                        ( _("Trying to determine create group '%(group)s'... (file '%(file)s', line %(lnr)s)")
-                            % {'group': group_raw, 'file': filename, 'lnr': linenr})
-                    )
-                if re.search(r'^[1-9]\d*$', group_raw) is not None:
-                    group = int(group_raw)
-                else:
-                    try:
-                        group = grp.getgrnam(group_raw)[2]
-                    except KeyError:
-                        self.logger.warning( ( _("Invalid group '%s' in 'create'.") %(group_raw)))
-                        return False
-
-            # Give values back ...
-            directive['create']['mode']  = mode
-            directive['create']['owner'] = owner
-            directive['create']['group'] = group
-            return True
-
-        # checking for olddir ...
-        match = re.search(r'^(not?)?olddir$', option, re.IGNORECASE)
-        if match:
-
-            negated = False
-            if match.group(1) is not None:
-                negated = True
-
-            if self.verbose > 5:
-                self.logger.debug(
-                    ( _("Checking for 'olddir' ... (file '%(file)s', line %(lnr)s)")
-                        % {'file': filename, 'lnr': linenr})
-                )
-
-            if negated:
-                if self.verbose > 4:
-                    self.logger.debug(
-                        ( _("Removing 'olddir'. (file '%(file)s', line %(lnr)s)")
-                            % {'file': filename, 'lnr': linenr})
-                    )
-                directive['olddir']['enabled'] = False
-                return True
-
-            values = []
-            if val is not None:
-                values = split_parts(val)
-
-            # Check for dirname of olddir
-            if len(values) < 1 or values[0] is None or re.search(r'^\s*$', values[0]) is not None:
-                self.logger.warning( ( _("Option 'olddir' without a value given.")))
-                return False
-            directive['olddir']['dirname'] = values[0]
-            directive['olddir']['enabled'] = True
-
-            mode  = None
-            owner = None
-            group = None
-
-            # Check for create mode of olddir
-            if len(values) > 1:
-                if self.verbose > 5:
-                    self.logger.debug(
-                        ( _("Trying to determine olddir create mode '%(mode)s' ... (file '%(file)s', line %(lnr)s)")
-                            % {'mode': values[1], 'file': filename, 'lnr': linenr})
-                    )
-                mode_octal = values[1]
-                if re.search(r'^0', mode_octal) is None:
-                    mode_octal = '0' + mode_octal
-                try:
-                    mode = int(mode_octal, 8)
-                except ValueError:
-                    self.logger.warning( ( _("Invalid create mode '%s' in 'olddir'.") %(values[1])))
-                    return False
-
-            # Check for Owner (user, uid)
-            if len(values) > 2:
-                owner_raw = values[2]
-                if self.verbose > 5:
-                    self.logger.debug(
-                        ( _("Trying to determine olddir owner '%(owner)s' ... (file '%(file)s', line %(lnr)s)")
-                            % {'owner': owner_raw, 'file': filename, 'lnr': linenr})
-                    )
-                if re.search(r'^[1-9]\d*$', owner_raw) is not None:
-                    owner = int(owner_raw)
-                else:
-                    try:
-                        owner = pwd.getpwnam(owner_raw)[2]
-                    except KeyError:
-                        self.logger.warning( ( _("Invalid owner '%s' in 'olddir'.") %(owner_raw)))
-                        return False
-
-            # Check for Group (gid)
-            if len(values) > 3:
-                group_raw = values[3]
-                if self.verbose > 5:
-                    self.logger.debug(
-                        ( _("Trying to determine olddir group '%(group)s' ... (file '%(file)s', line %(lnr)s)")
-                            % {'group': group_raw, 'file': filename, 'lnr': linenr})
-                    )
-                if re.search(r'^[1-9]\d*$', group_raw) is not None:
-                    group = int(group_raw)
-                else:
-                    try:
-                        group = grp.getgrnam(group_raw)[2]
-                    except KeyError:
-                        self.logger.warning( ( _("Invalid group '%s' in 'olddir'.") %(group_raw)))
-                        return False
-
-            # Give values back ...
-            directive['olddir']['mode']  = mode
-            directive['olddir']['owner'] = owner
-            directive['olddir']['group'] = group
-            return True
-
-        # Check for minimum size for ratation
-        match = re.search(r'^size(?:(?:\s*=|\s)|$)', line, re.IGNORECASE)
-        if match:
-            size_str = re.sub(r'^size(?:\s*=\s*|\s+)', '', line)
-            if self.verbose > 5:
-                self.logger.debug(
-                    ( _("Checking for option 'size', value: '%(value)s' ... (file '%(file)s', line %(lnr)s)")
-                        % {'value': size_str, 'file': filename, 'lnr': linenr})
-                )
-            if size_str is None:
-                self.logger.warning( _("Failing size definition."))
-                return False
-            size_bytes = None
-            try:
-                size_bytes = human2bytes(size_str, verbose = self.verbose)
-            except ValueError, e:
-                self.logger.warning( ( _("Invalid definition for 'size': '%s'.") %(size_str)))
-                return False
-            if self.verbose > 4:
-                self.logger.debug(
-                    ( _("Got a rotation size in '%(directive)s' of %(bytes)d bytes. (file '%(file)s', line %(lnr)s)")
-                        % {'directive': directive_str, 'bytes': size_bytes, 'file': filename, 'lnr': linenr})
-                )
-            directive['size'] = size_bytes
-            return True
-
-        # Check for taboo options
-        pattern = r'^taboo(ext|file|prefix)$'
-        match = re.search(pattern, option, re.IGNORECASE)
-        if match:
-            key = match.group(1).lower()
-            if self.verbose > 5:
-                self.logger.debug(
-                    ( _("Checking for option 'taboo%(type)s', value: '%(value)s' ... (file '%(file)s', line %(lnr)s)")
-                        % {'type': key, 'value': val, 'file': filename, 'lnr': linenr})
-                )
-
-            if in_fd:
-                self.logger.warning( ( _("Option 'taboo%s' not allowed inside a logfile directive.") %(key)))
-                return False
-
-            values = []
-            if val is not None:
-                values = split_parts(val)
-
-            extend = False
-            if len(values) > 0 and values[0] is not None and values[0] == '+':
-                extend = True
-                values.pop(0)
-
-            if len(values) < 1:
-                self.logger.warning( ( _("Option 'taboo%s' needs a value.") %(key)))
-                return False
-
-            if not extend:
-                self.taboo = []
-            for extension in values:
-                self.add_taboo(extension, key)
-
-            return True
-
-        # Option not found, I'm angry
-        self.logger.warning( ( _("Unknown option '%s'.") %(option)))
-        return False
-
-    #------------------------------------------------------------
-    def _ext_script_definition(self, line, rest, filename, linenr):
-        '''
-        Starts a new explicite external script definition.
-        It raises a LogrotateConfigurationError on error.
-
-        @param line:     line of current config file
-        @type line:      str
-        @param rest:     rest of the current line after »script«
-        @type rest:      str
-        @param filename: current configuration file
-        @type filename:  str
-        @param linenr:   current line number of configuration file
-        @type linenr:    int
-
-        @return: name of the script (if a new script definition) or None
-        @rtype:  str or None
-        '''
-
-        _ = self.t.lgettext
-
-        # split the rest in chunks
-        values = split_parts(rest)
-
-        # insufficient arguments to include ...
-        if len(values) < 1:
-            self.logger.warning(
-                ( _("No script name given in a script directive. (file '%(file)s', line %(lnr)s)")
-                    % {'file': filename, 'lnr': linenr})
-            )
-            return None
-
-        # to much arguments to include ...
-        if len(values) > 1:
-            self.logger.warning(
-                ( _("Only one script name is allowed in a script directive, the first one is used. (file '%(file)s', line %(lnr)s)")
-                    % {'file': filename, 'lnr': linenr})
-            )
-
-        script_name = values[0]
-
-        if script_name in self.scripts:
-            self.logger.warning(
-                ( _("Script name '%(name)s' is allready declared, it will be overwritten. (file '%(file)s', line %(lnr)s)")
-                    % {'name': script_name, 'file': filename, 'lnr': linenr})
-            )
-
-        self.scripts[script_name] = LogRotateScript(
-            name      = script_name,
-            local_dir = self.local_dir,
-            verbose   = self.verbose,
-            test_mode = self.test_mode,
-        )
-        #self.scripts[script_name]['cmd'] = []
-        #self.scripts[script_name]['post_files'] = 0
-        #self.scripts[script_name]['last_files'] = 0
-        #self.scripts[script_name]['first'] = False
-        #self.scripts[script_name]['prerun'] = False
-        #self.scripts[script_name]['donepost'] = False
-        #self.scripts[script_name]['donelast'] = False
-
-        return script_name
-
-    #------------------------------------------------------------
-    def _do_include( self, line, rest, filename, linenr):
-        '''
-        Starts a new logfile definition.
-        It raises a LogrotateConfigurationError on error.
-
-        @param line:     line of current config file
-        @type line:      str
-        @param rest:     rest of the current line after »include«
-        @type rest:      str
-        @param filename: current configuration file
-        @type filename:  str
-        @param linenr:   current line number of configuration file
-        @type linenr:    int
-
-        @return: Success of include
-        @rtype:  bool
-        '''
-
-        _ = self.t.lgettext
-
-        # split the rest in chunks
-        values = split_parts(rest)
-
-        # insufficient arguments to include ...
-        if len(values) < 1:
-            self.logger.warning(
-                ( _("No file or directory given in a include directive (file '%(file)s', line %(lnr)s)")
-                    % {'file': filename, 'lnr': linenr})
-            )
-            return False
-
-        # to much arguments to include ...
-        if len(values) > 1:
-            self.logger.warning(
-                ( _("Only one declaration of a file or directory is allowed in a include directive, the first one is used. (file '%(file)s', line %(lnr)s)")
-                    % {'file': filename, 'lnr': linenr})
-            )
-
-        include = values[0]
-
-        # including object doesn't exists
-        if not os.path.exists(include):
-            self.logger.warning(
-                ( _("Including object '%(include)s' doesn't exists. (file '%(file)s', line %(lnr)s)")
-                    % {'include': include, 'file': filename, 'lnr': linenr})
-            )
-            return False
-
-        include = os.path.abspath(include)
-
-        # including object is neither a regular file nor a directory
-        if not (os.path.isfile(include) or os.path.isdir(include)):
-            self.logger.warning(
-                ( _("Including object '%(include)s' is neither a regular file  nor a directory. (file '%(file)s', line %(lnr)s)")
-                    % {'include': include, 'file': filename, 'lnr': linenr})
-            )
-            return False
-
-        if self.verbose > 1:
-            self.logger.debug( ( _("Trying to include object '%s' ...") % (include) ))
-
-        # including object is a regular file
-        if os.path.isfile(include):
-            if include in self.config_files:
-                self.logger.warning(
-                    ( _("Recursive including of '%(include)s'. (file '%(file)s', line %(lnr)s)")
-                        % {'include': include, 'file': filename, 'lnr': linenr})
-                )
-                return False
-            return self._read(include)
-
-        # This should never happen ...
-        if not os.path.isdir(include):
-            raise Exception(
-                ( _("What the hell is this: '%(include)s'. (file '%(file)s', line %(lnr)s)")
-                    % {'include': include, 'file': filename, 'lnr': linenr})
-            )
-
-        # including object is a directory - include all files
-        if self.verbose > 1:
-            self.logger.debug( ( _("Including directory '%s' ...") % (include) ))
-
-        dir_list = os.listdir(include)
-        for item in sorted(dir_list, key=str.lower):
-
-            item_path = os.path.abspath(os.path.join(include, item))
-            if self.verbose > 2:
-                self.logger.debug( ( _( "Including item '%(item)s' ('%(path)s') ..." )
-                    % {'item': item, 'path': item_path} )
-                )
-
-            # Skip directories
-            if os.path.isdir(item_path):
-                if self.verbose > 1:
-                    self.logger.debug( ( _("Skip subdirectory '%s' in including.") % (item_path)))
-                continue
-
-            # Skip non regular files
-            if not os.path.isfile(item_path):
-                self.logger.debug( ( _("Item '%s' is not a regular file.") % (item_path)))
-                continue
-
-            # Check for taboo pattern
-            taboo_found = False
-            for pattern in self.taboo:
-                match = re.search(pattern, item)
-                if match:
-                    if self.verbose > 1:
-                        self.logger.debug(
-                            ( _("Item '%(item)s' is matching pattern '%(pattern)s', skiping.")
-                                % {'item': item, 'pattern': pattern})
-                        )
-                    taboo_found = True
-                    break
-            if taboo_found:
-                continue
-
-            # Check, whther it was former included
-            if item_path in self.config_files:
-                self.logger.warning(
-                    ( _("Recursive including of '%(include)s' (file '%(file)s', line %(lnr)s)")
-                        % {'include': item_path, 'file': filename, 'lnr': linenr})
-                )
-                return False
-            self._read(item_path)
-
-    #------------------------------------------------------------
-    def _start_logfile_definition(
-        self, line, filename, in_fd, in_logfile_list, linenr
-    ):
-        '''
-        Starts a new logfile definition.
-        It raises a LogrotateConfigurationError on error.
-
-        @param line:            line of current config file
-        @type line:             str
-        @param filename:        current configuration file
-        @type filename:         str
-        @param in_fd:           parsing inside a logfile definition
-        @type in_fd:            bool
-        @param in_logfile_list: logfile pattern list was started
-        @type in_logfile_list:  bool
-        @param linenr:          current line number of configuration file
-        @type linenr:           int
-
-        @return: name of the script (if a new script definition) or None
-        @rtype:  str or None
-        '''
-
-        _ = self.t.lgettext
-
-        if in_fd:
-            raise LogrotateConfigurationError(
-                ( _("Nested logfile definitions are not allowed. (file '%(file)s', line %(lnr)s)")
-                    % {'file': filename, 'lnr': linenr})
-            )
-
-        if not in_logfile_list:
-            raise LogrotateConfigurationError(
-                ( _("No logfile pattern defined on starting a logfile definition. (file '%(file)s', line %(lnr)s)")
-                    % {'file': filename, 'lnr': linenr})
-            )
-
-    #------------------------------------------------------------
-    def _start_log_script_definition( self, script_type, script_name, line, filename, in_fd, linenr):
-        '''
-        Starts a new logfile definition or logfile refrence
-        inside a logfile definition.
-        It raises a LogrotateConfigurationError outside a logfile definition.
-
-        @param script_type: postrotate, prerotate, firstaction
-                            or lastaction
-        @type script_type:  str
-        @param script_name: name of refernced script
-        @type script_name:  str or None
-        @param line:        line of current config file
-        @type line:         str
-        @param filename:    current configuration file
-        @type filename:     str
-        @param in_fd:       parsing inside a logfile definition
-        @type in_fd:        bool
-        @param linenr:      current line number of configuration file
-        @type linenr:       int
-
-        @return: name of the script (if a new script definition) or None
-        @rtype:  str or None
-        '''
-
-        _ = self.t.lgettext
-
-        if not in_fd:
-            raise LogrotateConfigurationError(
-                ( _("Directive '%(directive)s' is not allowed outside of a logfile definition. (file '%(file)s', line %(lnr)s)")
-                    % {'directive': script_type, 'file': filename, 'lnr': linenr})
-            )
-
-        if script_name:
-            self.new_log[script_type] = script_name
-            return None
-
-        new_script_name = self._new_scriptname(script_type)
-
-        self.scripts[new_script_name] = LogRotateScript(
-            name      = new_script_name,
-            local_dir = self.local_dir,
-            verbose   = self.verbose,
-            test_mode = self.test_mode,
-        )
-        #self.scripts[new_script_name] = {}
-        #self.scripts[new_script_name]['cmd'] = []
-        #self.scripts[new_script_name]['post_files'] = 0
-        #self.scripts[new_script_name]['last_files'] = 0
-        #self.scripts[new_script_name]['first'] = False
-        #self.scripts[new_script_name]['prerun'] = False
-        #self.scripts[new_script_name]['donepost'] = False
-        #self.scripts[new_script_name]['donelast'] = False
-
-        self.new_log[script_type] = new_script_name
-
-        return new_script_name
-
-    #------------------------------------------------------------
-    def _new_scriptname(self, script_type = 'script'):
-        '''
-        Retrieves a new, unique script name.
-
-        @param script_type: prefix of the script name
-        @type script_type:  str
-
-        @return: a new, unique script name
-        @rtype:  str
-        '''
-
-        i = 0
-        template = script_type + "_%02d"
-        name = template % (i)
-
-        while True:
-
-            if name in self.scripts:
-                cmd = self.scripts[name].cmd
-                if cmd is not None:
-                    if len(cmd):
-                        i += 1
-                        name = template % (i)
-                    else:
-                        break
-                else:
-                    break
-            else:
-                break
-
-        return name
-
-    #------------------------------------------------------------
-    def _start_new_log(self, config_file, rownum):
-        '''
-        Starting a new log definition in self.new_log and filling it
-        with the current default values.
-
-        @param config_file: the configuration file with the start
-                            of the logfile definition
-        @type config_file:  str
-        @param rownum:      the row number of the configuration file
-                            with the start of the logfile definition
-        @type rownum:       int
-        '''
-
-        _ = self.t.lgettext
-
-        if self.verbose > 3:
-            self.logger.debug( _("Starting a new log directive with default values."))
-
-        self.new_log = {}
-
-        self.new_log['files'] = []
-        self.new_log['file_patterns'] = []
-
-        self.new_log['compress']      = self.default['compress']
-        self.new_log['compresscmd']   = self.default['compresscmd']
-        self.new_log['compressext']   = self.default['compressext']
-        self.new_log['compressoptions']  = self.default['compressoptions']
-        self.new_log['configfile']    = config_file
-        self.new_log['configrow']     = rownum
-        self.new_log['copy']          = self.default['copy']
-        self.new_log['copytruncate']  = self.default['copytruncate']
-        self.new_log['create']        = {
-            'enabled': self.default['create']['enabled'],
-            'mode':    self.default['create']['mode'],
-            'owner':   self.default['create']['owner'],
-            'group':   self.default['create']['group'],
-        }
-        self.new_log['period']        = self.default['period']
-        self.new_log['dateext']       = self.default['dateext']
-        self.new_log['datepattern']   = self.default['datepattern']
-        self.new_log['delaycompress'] = self.default['delaycompress']
-        self.new_log['extension']     = self.default['extension']
-        self.new_log['ifempty']       = self.default['ifempty']
-        self.new_log['mailaddress']   = self.default['mailaddress']
-        self.new_log['mailfirst']     = self.default['mailfirst']
-        self.new_log['maxage']        = self.default['maxage']
-        self.new_log['missingok']     = self.default['missingok']
-        self.new_log['olddir']        = {
-            'dirname':    self.default['olddir']['dirname'],
-            'dateformat': self.default['olddir']['dateformat'],
-            'enabled':    self.default['olddir']['enabled'],
-            'mode':       self.default['olddir']['mode'],
-            'owner':      self.default['olddir']['owner'],
-            'group':      self.default['olddir']['group'],
-        }
-        self.new_log['rotate']        = self.default['rotate']
-        self.new_log['sharedscripts'] = self.default['sharedscripts']
-        self.new_log['shred']         = self.default['shred']
-        self.new_log['size']          = self.default['size']
-        self.new_log['start']         = self.default['start']
-
-        for script_type in script_directives:
-            self.new_log[script_type] = None
-
-    #------------------------------------------------------------
-    def _assign_logfiles(self):
-        '''
-        Finds all existing logfiles of self.new_log according to the
-        shell matching patterns in self.new_log['file_patterns'].
-        If a logfile was even defined, a warning is omitted and the
-        new definition will thrown away.
-
-        @return: number of found logfiles according to self.new_log['file_patterns']
-        @rtype:  int
-        '''
-
-        _ = self.t.lgettext
-
-        if len(self.new_log['file_patterns']) <= 0:
-            msg = _("No logfile pattern defined.")
-            self.logger.warning(msg)
-            return 0
-
-        for pattern in self.new_log['file_patterns']:
-            if self.verbose > 1:
-                msg = _("Find all logfiles for shell matching pattern '%s' ...") \
-                       % (pattern)
-                self.logger.debug(msg)
-            logfiles = glob.glob(pattern)
-            if len(logfiles) <= 0:
-                msg = _("No logfile found for pattern '%s'.") % (pattern)
-                if self.new_log['missingok']:
-                    self.logger.debug(msg)
-                else:
-                    self.logger.warning(msg)
-                continue
-            for logfile in logfiles:
-                if self.verbose > 1:
-                    msg = _("Found logfile '%(file)s for pattern '%(pattern)s'.") \
-                           % {'file': logfile, 'pattern': pattern }
-                    self.logger.debug(msg)
-                if logfile in self.defined_logfiles:
-                    f = self.defined_logfiles[logfile]
-                    msg = ( _("Logfile '%(logfile)s' is even defined (file '%(cfgfile)s', " +
-                              "row %(rownum)d) and so not taken a second time.") 
-                             % {'logfile': logfile,
-                                'cfgfile': f['file'],
-                                'rownum': f['rownum']}
-                    )
-                    self.logger.warning(msg)
-                    continue
-                if self.verbose > 1:
-                    msg = _("Logfile '%s' will taken.") \
-                            % (logfile)
-                self.defined_logfiles[logfile] = {
-                        'file': self.new_log['configfile'],
-                        'rownum': self.new_log['configrow'],
-                }
-                self.new_log['files'].append(logfile)
-
-        return len(self.new_log['files'])
-
-#========================================================================
-
-if __name__ == "__main__":
-    pass
-
-
-#========================================================================
-
-# vim: fileencoding=utf-8 filetype=python ts=4 expandtab
diff --git a/LogRotateGetopts.py b/LogRotateGetopts.py
deleted file mode 100755 (executable)
index e74bde7..0000000
+++ /dev/null
@@ -1,317 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-# $Id$
-# $URL$
-
-'''
-@author: Frank Brehm
-@contact: frank@brehm-online.com
-@license: GPL3
-@copyright: (c) 2010-2011 by Frank Brehm, Berlin
-@version: 0.0.1
-@summary: Option parser for Python logrotating
-'''
-
-import re
-import sys
-import gettext
-
-from optparse import OptionError
-from optparse import OptionParser
-from optparse import OptionGroup
-from optparse import OptionConflictError
-
-
-revision = '$Revision$'
-revision = re.sub( r'\$', '', revision )
-revision = re.sub( r'Revision: ', r'r', revision )
-revision = re.sub( r'\s*$', '', revision )
-
-__author__    = 'Frank Brehm'
-__copyright__ = '(C) 2011 by Frank Brehm, Berlin'
-__contact__    = 'frank@brehm-online.com'
-__version__    = '0.0.1 ' + revision
-__license__    = 'GPL3'
-
-
-#========================================================================
-
-class LogrotateOptParserError(Exception):
-    '''
-    Class for exceptions in this module, escpacially
-    due to false commandline options.
-    '''
-
-#========================================================================
-
-class LogrotateOptParser(object):
-    '''
-    Class for parsing commandline options of Python logrotating.
-
-    @author: Frank Brehm
-    @contact: frank@brehm-online.com
-    '''
-
-    #-------------------------------------------------------
-    def __init__( self, prog = '%prog',
-                        version = None,
-                        local_dir = None,
-    ):
-        '''
-        Constructor.
-
-        @param prog:      The name of the calling process (e.g. sys.argv[0])
-        @type prog:       str
-        @param version:   The version string to use
-        @type version:    str
-        @param local_dir: The directory, where the i18n-files (*.mo)
-                          are located. If None, then system default
-                          (/usr/share/locale) is used.
-        @type local_dir:  str or None
-
-        @return: None
-        '''
-
-        self.prog = prog
-        '''
-        @ivar: The name of the calling process
-        @type: str
-        '''
-
-        self.version = version
-        '''
-        @ivar: The version string to use
-        @type: str
-        '''
-
-        self.local_dir = local_dir
-        '''
-        @ivar: The directory, where the i18n-files (*.mo) are located.
-        @type: str or None
-        '''
-
-        self.t = gettext.translation(
-            'LogRotateGetopts',
-            local_dir,
-            fallback = True
-        )
-        '''
-        @ivar: a gettext translation object
-        @type: gettext.translation
-        '''
-
-        _ = self.t.lgettext
-
-        self.description = _('Rotates, compresses and mails system logs.')
-        '''
-        @ivar: description of the program
-        @type: str
-        '''
-
-        self.usage = ( _("%s [options] <configfile>") + "\n" ) %(prog)
-        '''
-        @ivar: the usage string in getopt help output
-        @type: str
-        '''
-        self.usage += ( '       %s [-h|-?|--help]\n' %(prog) )
-        self.usage += ( '       %s --usage\n' %(prog) )
-        self.usage += ( '       %s --version' %(prog) )
-
-        self.options = None
-        '''
-        @ivar: a dict with all given commandline options
-               after calling getOpts()
-        @type: dict or None
-        '''
-
-        self.args = None
-        '''
-        @ivar: a list with all commandline parameters, what are not options
-        @type: list or None
-        '''
-
-        self.parsed = False
-        '''
-        @ivar: flag, whether the parsing was done
-        @type: bool
-        '''
-
-        if version:
-            self.version = version
-
-        self.parser = OptionParser(
-                prog             = self.prog,
-                version          = self.version,
-                description      = self.description,
-                usage            = self.usage,
-                conflict_handler = "resolve",
-        )
-        '''
-        @ivar: the working OptionParser Object
-        @type: optparse.OptionParser
-        '''
-
-        self._add_options()
-
-    #-------------------------------------------------------
-    def _add_options(self):
-        '''
-        Private function to add all necessary options
-        to the OptionParser object
-        '''
-
-        _ = self.t.ugettext
-        __ = self.t.ungettext
-
-        if self.parser.has_option('--help'):
-            self.parser.remove_option('--help')
-
-        if self.parser.has_option('--version'):
-            self.parser.remove_option('--version')
-
-        self.parser.add_option(
-            '--simulate',
-            '--test',
-            '-T',
-            default = False,
-            action  = 'store_true',
-            dest    = 'test',
-            help    = _('set this do simulate commands'),
-        )
-
-        self.parser.add_option(
-            '--verbose',
-            '-v',
-            default = False,
-            action  = 'count',
-            dest    = 'verbose',
-            help    = _('set the verbosity level'),
-        )
-
-        self.parser.add_option(
-            '--debug',
-            '-d',
-            default = False,
-            action  = 'store_true',
-            dest    = 'debug',
-            help    = _("Don't do anything, just test (implies -v and -T)"),
-        )
-
-        self.parser.add_option(
-            '--force',
-            '-f',
-            default = False,
-            action  = 'store_true',
-            dest    = 'force',
-            help    = _("Force file rotation"),
-        )
-
-        self.parser.add_option(
-            '--config-check',
-            '-c',
-            default = False,
-            action  = 'store_true',
-            dest    = 'configcheck',
-            help    = _("Checks only the given configuration file and does "
-                      + "nothing. Conflicts with -f."),
-        )
-
-        self.parser.add_option(
-            '--state',
-            '-s',
-            dest    = "statefile",
-            metavar = 'FILE',
-            help    = _('Path of state file (different to configuration)'),
-        )
-
-        self.parser.add_option(
-            '--pid-file',
-            '-P',
-            dest    = "pidfile",
-            metavar = 'FILE',
-            help    = _('Path of PID file (different to configuration)'),
-        )
-
-        self.parser.add_option(
-            '--mail',
-            '-m',
-            dest    = "mailcmd",
-            metavar = 'CMD',
-            help    = _('Command to send mail (instead of using '
-                        + 'the Phyton email package)'),
-        )
-
-        ######
-        # Option group for common options
-
-        group = OptionGroup(self.parser, _("Common options"))
-
-        group.add_option(
-            '-h',
-            '-?',
-            '--help',
-            default = False,
-            action  = 'help',
-            dest    = 'help',
-            help    = _('Shows a help message and exit.'),
-        )
-
-        group.add_option(
-            '--usage',
-            default = False,
-            action  = 'store_true',
-            dest    = 'usage',
-            help    = _('Display brief usage message and exit.'),
-        )
-
-        group.add_option(
-            '-V',
-            '--version',
-            default = False,
-            action  = 'version',
-            dest    = 'version',
-            help    = _('Shows the version number of the program and exit.'),
-        )
-
-        self.parser.add_option_group(group)
-
-    #----------------------------------------------------------------------
-    def getOpts(self):
-        '''
-        Wrapper function to OptionParser.parse_args().
-        Sets self.options and self.args with the appropriate values.
-        @return: None
-        '''
-
-        _ = self.t.ugettext
-
-        if not self.parsed:
-            self.options, self.args = self.parser.parse_args()
-            self.parsed = True
-
-        if self.options.usage:
-            self.parser.print_usage()
-            sys.exit(0)
-
-        if self.options.force and self.options.configcheck:
-            raise LogrotateOptParserError( _('Invalid usage of --force and '
-                + '--config-check.') )
-
-        if self.args is None or len(self.args) < 1:
-            raise LogrotateOptParserError( _('No configuration file given.') )
-
-        if len(self.args) != 1:
-            raise LogrotateOptParserError(
-                _('Only one configuration file is allowed.')
-            )
-
-#========================================================================
-
-if __name__ == "__main__":
-    pass
-
-
-#========================================================================
-
-# vim: fileencoding=utf-8 filetype=python ts=4 expandtab
diff --git a/LogRotateHandler.py b/LogRotateHandler.py
deleted file mode 100755 (executable)
index dda1852..0000000
+++ /dev/null
@@ -1,2390 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-# $Id$
-# $URL$
-
-'''
-@author: Frank Brehm
-@contact: frank@brehm-online.com
-@license: GPL3
-@copyright: (c) 2010-2011 by Frank Brehm, Berlin
-@version: 0.4.0
-@summary: Application handler module for Python logrotating
-'''
-
-# Für Terminal-Dinge: http://code.activestate.com/recipes/475116/
-
-import re
-import sys
-import gettext
-import logging
-import pprint
-import os
-import os.path
-import errno
-import socket
-import subprocess
-import shutil
-import glob
-from datetime import datetime, timedelta
-import time
-import gzip
-import bz2
-import zipfile
-
-from LogRotateConfig import LogrotateConfigurationError
-from LogRotateConfig import LogrotateConfigurationReader
-
-from LogRotateStatusFile import LogrotateStatusFileError
-from LogRotateStatusFile import LogrotateStatusFile
-from LogRotateStatusFile import utc
-
-from LogRotateMailer import LogRotateMailerError
-from LogRotateMailer import LogRotateMailer
-
-revision = '$Revision$'
-revision = re.sub( r'\$', '', revision )
-revision = re.sub( r'Revision: ', r'r', revision )
-revision = re.sub( r'\s*$', '', revision )
-
-__author__    = 'Frank Brehm'
-__copyright__ = '(C) 2011 by Frank Brehm, Berlin'
-__contact__    = 'frank@brehm-online.com'
-__version__    = '0.4.0 ' + revision
-__license__    = 'GPL3'
-
-
-#========================================================================
-
-class LogrotateHandlerError(Exception):
-    '''
-    Base class for exceptions in this module.
-    '''
-
-#========================================================================
-
-class StdoutFilter(logging.Filter):
-    '''
-    Class, that filters all logrecords
-    '''
-
-    def filter(self, record):
-        '''
-        Filtering log records and let through messages
-        except them with the level names 'WARNING', 'ERROR' or 'CRITICAL'.
-
-        @param record: the record to filter
-        @type record:  logging.LogRecord
-
-        @return: pass the record or not
-        '''
-        if record.levelname == 'WARNING':
-            return False
-        if record.levelname == 'ERROR':
-            return False
-        if record.levelname == 'CRITICAL':
-            return False
-        return True
-
-#========================================================================
-
-class LogrotateHandler(object):
-    '''
-    Class for application handler for Python logrotating
-
-    @author: Frank Brehm
-    @contact: frank@brehm-online.com
-    '''
-
-    #-------------------------------------------------------
-    def __init__( self, config_file,
-                        test         = False,
-                        verbose      = 0,
-                        force        = False,
-                        config_check = False,
-                        state_file   = None,
-                        pid_file     = None,
-                        mail_cmd     = None,
-                        local_dir    = None,
-                        version      = None,
-    ):
-        '''
-        Constructor.
-
-        @param config_file:  the configuration file to use
-        @type config_file:   str
-        @param test:         testmode, no real actions are made
-        @type test:          bool
-        @param verbose:      verbosity (debug) level
-        @type verbose:       int
-        @param force:        Force file rotation
-        @type force:         bool
-        @param config_check: Checks only the configuration and does nothing
-        @type config_check:  bool
-        @param state_file:   Path of state file (different to configuration)
-        @type state_file:    str or None
-        @param pid_file:     Path of PID file (different to configuration)
-        @type pid_file:      str or None
-        @param mail_cmd:     command to send mail (instead of using
-                             the Phyton email package)
-        @type mail_cmd:      str or None
-        @param local_dir:    The directory, where the i18n-files (*.mo)
-                             are located. If None, then system default
-                             (/usr/share/locale) is used.
-        @type local_dir:     str or None
-        @param version:      version number to show
-        @type version:       str
-
-        @return: None
-        '''
-
-        self.local_dir = local_dir
-        '''
-        @ivar: The directory, where the i18n-files (*.mo) are located.
-        @type: str or None
-        '''
-
-        self.t = gettext.translation(
-            'LogRotateHandler',
-            local_dir,
-            fallback = True
-        )
-        '''
-        @ivar: a gettext translation object
-        @type: gettext.translation
-        '''
-
-        _ = self.t.lgettext
-
-        self.verbose = verbose
-        '''
-        @ivar: verbosity level (0 - 9)
-        @type: int
-        '''
-
-        self.version = __version__
-        '''
-        @ivar: version number to show, e.g. as the X-Mailer version
-        @type: str
-        '''
-        if version is not None:
-            self.version = version
-
-        self.test = test
-        '''
-        @ivar: testmode, no real actions are made
-        @type: bool
-        '''
-
-        self.force = force
-        '''
-        @ivar: Force file rotation
-        @type: bool
-        '''
-
-        self.state_file = None
-        '''
-        @ivar: the state file object after his initialisation
-        @type: LogRotateStateFile or None
-        '''
-
-        self.state_file_name = state_file
-        '''
-        @ivar: Path of state file (from commandline or from configuration)
-        @type: str
-        '''
-
-        self.pid_file = pid_file
-        '''
-        @ivar: Path of PID file (from commandline or from configuration)
-        @type: str
-        '''
-
-        self.pidfile_created = False
-        '''
-        @ivar: Is a PID file created by this instance and should removed
-               on destroying this object.
-        @type: bool
-        '''
-
-        self.mail_cmd = mail_cmd
-        '''
-        @ivar: command to send mail (instead of using the Phyton email package)
-        @type: str or None
-        '''
-
-        self.config_file = config_file
-        '''
-        @ivar: the initial configuration file to use
-        @type: str
-        '''
-
-        self.config = []
-        '''
-        @ivar: the configuration, how it was read from cofiguration file(s)
-        @type: dict
-        '''
-
-        self.scripts = {}
-        '''
-        @ivar: list of LogRotateScript objects with all named scripts found in configuration
-        @type: list
-        '''
-
-        self.template = {}
-        '''
-        @ivar: things to do in olddir stuff
-        @type: dict
-        '''
-        self._prepare_templates()
-
-        self.logfiles = []
-        '''
-        @ivar: list of all rotated logfiles. Each entry is a dict with
-               three keys:
-                - 'original': str with the name of the unrotated file
-                - 'rotated':  str with the name of the rotated file
-                - 'oldfiles:  list with all old rotated files of this file
-                - 'desc_index': index of list self.config for appropriate
-                                logfile definition
-        @type: list
-        '''
-
-        self.files_delete = {}
-        '''
-        @ivar: dictionary with all files, they have to delete
-        @type: dict
-        '''
-
-        self.files_compress = {}
-        '''
-        @ivar: dictionary with all files, they have to compress
-               keys are the filenames, values are the index number
-               of the list self.config (for compress options)
-        @type: dict
-        '''
-
-        self.files2send = {}
-        '''
-        @ivar: dictionary with all all rotated logfiles to send via
-               mail to one or more recipients.
-               Keys are the file names of the (even existing) rotated
-               and maybe compressed logfiles.
-               Values are a tuple of (mailaddress, original_logfile), where
-               mailaddress is a comma separated list of mail addresses of
-               the recipients of the mails, and original_logfile is the name
-               of unrotated logfile.
-               This dict will filled by _do_rotate_file(), and will performed
-               by send_logfiles().
-        @type: dict
-        '''
-
-        #################################################
-        # Create a logger object
-        self.logger = logging.getLogger('pylogrotate')
-        '''
-        @ivar: logger object
-        @type: logging.getLogger
-        '''
-
-        self.logger.setLevel(logging.DEBUG)
-
-        # create formatter
-        format_str = '[%(asctime)s]: %(levelname)-8s - %(message)s'
-        if test:
-            format_str = '%(levelname)-8s - %(message)s'
-        if verbose:
-            if verbose > 1:
-                format_str = '[%(asctime)s]: %(name)s %(funcName)s() %(levelname)-8s - %(message)s'
-                if test:
-                    format_str = '%(name)s %(funcName)s() %(levelname)-8s - %(message)s'
-            else:
-                format_str = '[%(asctime)s]: %(name)s %(levelname)-8s - %(message)s'
-                if test:
-                    format_str = '%(name)s %(levelname)-8s - %(message)s'
-        formatter = logging.Formatter(format_str)
-
-        # create console handler for error messages
-        console_stderr = logging.StreamHandler(sys.stderr)
-        console_stderr.setLevel(logging.WARNING)
-        console_stderr.setFormatter(formatter)
-        self.logger.addHandler(console_stderr)
-
-        # create console handler for other messages
-        console_stdout = logging.StreamHandler(sys.stdout)
-        if verbose:
-            console_stdout.setLevel(logging.DEBUG)
-        else:
-            console_stdout.setLevel(logging.INFO)
-        fltr = StdoutFilter()
-        console_stdout.addFilter(fltr)
-        console_stdout.setFormatter(formatter)
-        self.logger.addHandler(console_stdout)
-
-        # define a mailer object
-        self.mailer = LogRotateMailer(
-            local_dir = self.local_dir,
-            verbose = self.verbose,
-            test_mode = self.test,
-            mailer_version = self.version,
-        )
-        if mail_cmd:
-            self.mailer.sendmail = mail_cmd
-
-        # end of init properties
-        self.logger.debug( _("Logrotating initialised") )
-
-        if not self.read_configuration():
-            self.logger.error( _('Could not read configuration') )
-            sys.exit(1)
-
-        if config_check:
-            return
-
-        if not self._check_pidfile():
-            sys.exit(3)
-
-        if not self._write_pidfile():
-            sys.exit(3)
-
-        self.logger.debug( _("Logrotating ready for work") )
-
-        # Create status file object
-        self.state_file = LogrotateStatusFile(
-            file_name = self.state_file_name,
-            local_dir = self.local_dir,
-            verbose   = self.verbose,
-            test_mode = self.test,
-        )
-
-    #------------------------------------------------------------
-    def __str__(self):
-        '''
-        Typecasting function for translating object structure
-        into a string
-
-        @return: structure as string
-        @rtype:  str
-        '''
-
-        pp = pprint.PrettyPrinter(indent=4)
-        structure = self.as_dict()
-        return pp.pformat(structure)
-
-    #-------------------------------------------------------
-    def as_dict(self):
-        '''
-        Transforms the elements of the object into a dict
-
-        @return: structure as dict
-        @rtype:  dict
-        '''
-
-        res = {
-            'config':          self.config,
-            'config_file':     self.config_file,
-            'files_delete':    self.files_delete,
-            'files_compress':  self.files_compress,
-            'files2send':      self.files2send,
-            'force':           self.force,
-            'local_dir':       self.local_dir,
-            'logfiles':        self.logfiles,
-            'logger':          self.logger,
-            'mail_cmd':        self.mail_cmd,
-            'mailer':          self.mailer.as_dict(),
-            'scripts':         {},
-            'state_file':      None,
-            'state_file_name': self.state_file_name,
-            'pid_file':        self.pid_file,
-            'pidfile_created': self.pidfile_created,
-            't':               self.t,
-            'test':            self.test,
-            'template':        self.template,
-            'verbose':         self.verbose,
-            'version':         self.version,
-        }
-        if self.state_file:
-            res['state_file'] = self.state_file.as_dict()
-
-        for script_name in self.scripts.keys():
-            res['scripts'][script_name] = self.scripts[script_name].as_dict()
-
-        return res
-
-    #------------------------------------------------------------
-    def __del__(self):
-        '''
-        Destructor.
-        No parameters, no return value.
-        '''
-
-        _ = self.t.lgettext
-
-        if self.pidfile_created:
-            if os.path.exists(self.pid_file):
-                self.logger.debug( _("Removing PID file '%s' ...") % (self.pid_file) )
-                try:
-                    os.remove(self.pid_file)
-                except OSError, e:
-                    self.logger.error( _("Error removing PID file '%(file)s': %(msg)")
-                        % { 'file': self.pid_file, 'msg': str(e) }
-                    )
-
-    #------------------------------------------------------------
-    def _prepare_templates(self):
-        '''
-        Preparing self.template with values for placeholders
-        in olddir stuff.
-        '''
-
-        self.template = {}
-
-        hostname = socket.getfqdn()
-        self.template['nodename'] = hostname
-        self.template['domain'] = ''
-
-        match = re.search(r'^([^\.]+)\.(.*)', hostname)
-        if match:
-            self.template['nodename'] = match.group(1)
-            self.template['domain'] = match.group(2)
-
-        uname = os.uname()
-        self.template['sysname'] = uname[0]
-        self.template['release'] = uname[2]
-        self.template['version'] = uname[3]
-        self.template['machine'] = uname[4]
-
-    #------------------------------------------------------------
-    def read_configuration(self):
-        '''
-        Reads the configuration from self.config_file
-
-        @return: Success of reading
-        @rtype:  bool
-        '''
-
-        _ = self.t.lgettext
-
-        config_reader = LogrotateConfigurationReader(
-            config_file = self.config_file,
-            verbose     = self.verbose,
-            local_dir   = self.local_dir,
-            test_mode   = self.test,
-        )
-
-        if self.verbose > 2:
-            msg = _("Configuration reader object structure") + ':\n' + str(config_reader)
-            self.logger.debug(msg)
-
-        try:
-            self.config  = config_reader.get_config()
-            self.scripts = config_reader.get_scripts()
-        except LogrotateConfigurationError, e:
-            self.logger.error( str(e) )
-            sys.exit(10)
-
-        if self.verbose > 2:
-            pp = pprint.PrettyPrinter(indent=4)
-            msg = _("Found global options:") + "\n" + pp.pformat(config_reader.global_option)
-            self.logger.debug(msg)
-
-        # Get and set mailer options
-        if 'mailfrom' in config_reader.global_option and \
-                config_reader.global_option['mailfrom']:
-            self.mailer.from_address = config_reader.global_option['mailfrom']
-        if config_reader.global_option['smtphost'] and \
-                config_reader.global_option['smtphost'] != 'localhost':
-            self.mailer.smtp_host = config_reader.global_option['smtphost']
-        if 'smtpport' in config_reader.global_option:
-            self.mailer.smtp_port = config_reader.global_option['smtpport']
-        if 'smtptls' in config_reader.global_option:
-            self.mailer.smtp_tls = config_reader.global_option['smtptls']
-        if 'smtpuser' in config_reader.global_option:
-            self.mailer.smtp_user = config_reader.global_option['smtpuser']
-        if 'smtppasswd' in config_reader.global_option:
-            self.mailer.smtp_passwd = config_reader.global_option['smtppasswd']
-
-        if self.state_file_name is None:
-            if 'statusfile' in config_reader.global_option and \
-                    config_reader.global_option['statusfile'] is not None:
-                self.state_file_name = config_reader.global_option['statusfile']
-            else:
-                self.state_file_name = os.sep + os.path.join('var', 'lib', 'py-logrotate.status')
-        self.logger.debug( _("Name of state file: '%s'") % (self.state_file_name) )
-
-        if self.pid_file is None:
-            if 'pidfile' in config_reader.global_option and \
-                    config_reader.global_option['pidfile'] is not None:
-                self.pid_file = config_reader.global_option['pidfile']
-            else:
-                self.pid_file = os.sep + os.path.join('var', 'run', 'py-logrotate.pid')
-        self.logger.debug( _("PID file: '%s'") % (self.pid_file) )
-
-        return True
-
-    #------------------------------------------------------------
-    def _check_pidfile(self):
-        '''
-        Checks the existence and consistence of self.pid_file.
-
-        Exit, if there is a running process with a PID from this file.
-        Doesn't exit in test mode.
-
-        Writes on success (no other process) this PID file.
-
-        @return: Success
-        @rtype:  bool
-        '''
-
-        _ = self.t.lgettext
-
-        if not os.path.exists(self.pid_file):
-            if self.verbose > 1:
-                self.logger.debug( _("PID file '%s' doesn't exists.") % (self.pid_file) )
-            return True
-
-        if self.test:
-            self.logger.info( _("Testmode, skip test of PID file '%s'.") % (self.pid_file) )
-            return True
-
-        self.logger.debug( _("Reading PID file '%s' ...") % (self.pid_file) )
-        f = None
-        try:
-            f = open(self.pid_file, 'r')
-        except IOError, e:
-            raise LogrotateHandlerError(
-                _("Couldn't open PID file '%(file)s' for reading: %(msg)s")
-                % { 'file': self.pid_file, 'msg': str(e) }
-            )
-
-        line = f.readline()
-        f.close()
-
-        pid = None
-        line = line.strip()
-        match = re.search(r'^\s*(\d+)\s*$', line)
-        if match:
-            pid = int(match.group(1))
-        else:
-            self.logger.warn( _("No useful information found in PID file '%(file)s': '%(line)s'")
-                % { 'file': self.pid_file, 'line': line }
-            )
-            return False
-
-        if self.verbose > 1:
-            self.logger.debug( _("Trying check for process with PID %d ...") % (pid) )
-        try:
-            os.kill(pid, 0)
-        except OSError, err:
-            if err.errno == errno.ESRCH:
-                self.logger.info( _("Process with PID %d anonymous died.") % (pid) )
-                return True
-            elif err.errno == errno.EPERM:
-                self.logger.warn( _("No permission to signal the process %d ...") % (pid) )
-                return True
-            else:
-                self.logger.warn( _("Unknown error: '%s'") % (str(err)) )
-                return False
-        else:
-            self.logger.error( _("Process with PID %d is allready running.") % (pid) )
-            return False
-
-        return False
-
-    #------------------------------------------------------------
-    def _write_pidfile(self):
-        '''
-        Writes the PID of the current process in self.pid_file.
-
-        Exit with an error, if it's not possible to write.
-        Doesn't exit in test mode.
-
-        Writes on success (no other process) this PID file.
-
-        @return: Success
-        @rtype:  bool
-        '''
-
-        _ = self.t.lgettext
-
-        if self.test:
-            self.logger.info( _("Testmode, skip writing of PID file '%s'.") % (self.pid_file) )
-            return True
-
-        self.logger.debug( _("Writing PID file '%s' ...") % (self.pid_file) )
-
-        f = None
-        try:
-            f = open(self.pid_file, 'w')
-            f.write(str(os.getppid()) + "\n")
-            f.close()
-        except IOError, e:
-            raise LogrotateHandlerError(
-                _("Couldn't open PID file '%(file)s' for writing: %(msg)s")
-                % { 'file': self.pid_file, 'msg': str(e) }
-            )
-
-        self.pidfile_created = True
-
-        return True
-
-    #------------------------------------------------------------
-    def rotate(self):
-        '''
-        Starting the underlying rotating.
-
-        @return: None
-        '''
-
-        _ = self.t.lgettext
-
-        if len(self.config) < 1:
-            msg = _("No logfile definitions found.")
-            self.logger.info(msg)
-            return
-
-        msg = _("Starting underlying rotation ...")
-        self.logger.info(msg)
-
-        cur_desc_index = 0
-        for d in self.config:
-            self._rotate_definition(cur_desc_index)
-            cur_desc_index += 1
-
-        if self.verbose > 1:
-            line = 60 * '-'
-            print line + "\n\n"
-
-        # Check for left over scripts to execute
-        for scriptname in self.scripts.keys():
-            if self.verbose >= 4:
-                msg = ( _("State of script '%s':") % (scriptname) ) \
-                        + "\n" + str(self.scripts[scriptname])
-                self.logger.debug(msg)
-            del self.scripts[scriptname]
-
-        return
-
-    #------------------------------------------------------------
-    def _rotate_definition(self, cur_desc_index):
-        '''
-        Rotation of a logfile definition from a configuration file.
-
-        @param cur_desc_index: index of self.config for definition
-                               of logfile from configuration file
-        @type cur_desc_index:  int
-
-        @return: None
-        '''
-
-        definition = self.config[cur_desc_index]
-
-        _ = self.t.lgettext
-
-        if self.verbose > 1:
-            line = 60 * '-'
-            print line + "\n\n"
-
-        if self.verbose >= 4:
-            pp = pprint.PrettyPrinter(indent=4)
-            msg = _("Rotating of logfile definition:") + \
-                    "\n" + pp.pformat(definition)
-            self.logger.debug(msg)
-
-        # re-reading of status file
-        self.state_file.read()
-
-        for logfile in definition['files']:
-            if self.verbose > 1:
-                line = 30 * '-'
-                print (line + "\n")
-                msg = ( _("Performing logfile '%s' ...") % (logfile))
-                self.logger.debug(msg)
-            should_rotate = self._should_rotate(logfile, cur_desc_index)
-            if self.verbose > 1:
-                if should_rotate:
-                    msg = _("logfile '%s' WILL rotated.")
-                else:
-                    msg = _("logfile '%s' will NOT rotated.")
-                self.logger.debug(msg % (logfile))
-            if not should_rotate:
-                continue
-            self._rotate_file(logfile, cur_desc_index)
-
-        if self.verbose > 1:
-            print "\n"
-
-        return
-
-    #------------------------------------------------------------
-    def _rotate_file(self, logfile, cur_desc_index):
-        '''
-        Rotates a logfile with all with all necessary actions before
-        and after rotation.
-
-        Throughs an LogrotateHandlerError on error.
-
-        @param logfile: the logfile to rotate
-        @type logfile:  str
-        @param cur_desc_index: index of self.config for definition
-                               of logfile from configuration file
-        @type cur_desc_index:  int
-
-        @return: None
-        '''
-
-        definition = self.config[cur_desc_index]
-
-        _ = self.t.lgettext
-
-        sharedscripts = definition['sharedscripts']
-        firstscript   = definition['firstaction']
-        prescript     = definition['prerotate']
-        postscript    = definition['postrotate']
-        lastscript    = definition['lastaction']
-
-        # Executing of the firstaction script, if it wasn't executed
-        if firstscript:
-            if self.verbose > 2:
-                msg = _("Looking, whether the firstaction script should be executed.")
-                self.logger.debug(msg)
-            if not self.scripts[firstscript].done_firstrun:
-                msg = _("Executing firstaction script '%s' ...") % (firstscript)
-                self.logger.info(msg)
-                if not self.scripts[firstscript].execute():
-                    return
-                self.scripts[firstscript].done_firstrun = True
-
-        # Executing prerotate scripts, if not sharedscripts or even not executed
-        if prescript:
-            if self.verbose > 2:
-                msg = _("Looking, whether the prerun script should be executed.")
-                self.logger.debug(msg)
-            do_it = False
-            if sharedscripts:
-                if not self.scripts[prescript].done_prerun:
-                    do_it = True
-            else:
-                do_it = True
-            if do_it:
-                msg = _("Executing prerun script '%s' ...") % (prescript)
-                self.logger.info(msg)
-                if not self.scripts[prescript].execute():
-                    return
-                self.scripts[prescript].done_prerun = True
-
-        olddir = self._create_olddir(logfile, cur_desc_index)
-        if olddir is None:
-            return
-
-        if not self._do_rotate_file(logfile, cur_desc_index, olddir):
-            return
-
-        # Looking for postrotate script in a similar way like for the prerotate
-        if postscript:
-            if self.verbose > 2:
-                msg = _("Looking, whether the postrun script should be executed.")
-                self.logger.debug(msg)
-            do_it = False
-            self.scripts[postscript].post_files -= 1
-            self.scripts[postscript].do_post = True
-            if sharedscripts:
-                if self.scripts[postscript].post_files <= 0:
-                    do_it = True
-                    self.scripts[postscript].do_post = False
-            else:
-                do_it = True
-            if do_it:
-                msg = _("Executing postrun script '%s' ...") % (postscript)
-                self.logger.info(msg)
-                if not self.scripts[postscript].execute():
-                    return
-                self.scripts[postscript].done_postrun = True
-
-        # Looking for lastaction script
-        if lastscript:
-            if self.verbose > 2:
-                msg = _("Looking, whether the lastaction script should be executed.")
-                self.logger.debug(msg)
-            do_it = False
-            self.scripts[lastscript].last_files -= 1
-            self.scripts[lastscript].do_last = True
-            if self.scripts[lastscript].done_lastrun:
-                self.scripts[lastscript].do_last = False
-            else:
-                if self.scripts[lastscript].last_files <= 0:
-                    do_it = True
-                    self.scripts[lastscript].do_last = False
-            if do_it:
-                msg = _("Executing lastaction script '%s' ...") % (lastscript)
-                self.logger.info(msg)
-                if not self.scripts[lastscript].execute():
-                    return
-                self.scripts[lastscript].done_lastrun = True
-
-    #------------------------------------------------------------
-    def _do_rotate_file(self, logfile, cur_desc_index, olddir = None):
-        '''
-        The underlaying unconditionally rotation of a logfile.
-
-        After the successful rotation 
-
-        @param logfile: the logfile to rotate
-        @type logfile:  str
-        @param cur_desc_index: index of self.config for definition
-                               of logfile from configuration file
-        @type cur_desc_index:  int
-        @param olddir: the directory of the rotated logfile
-                       if "." or None, store the rotated logfile
-                       in their original directory
-        @type olddir: str or None
-
-        @return: successful or not
-        @rtype:  bool
-        '''
-
-        definition = self.config[cur_desc_index]
-
-        if (olddir is not None) and (olddir == "."):
-            olddir = None
-
-        _ = self.t.lgettext
-
-        uid = os.geteuid()
-        gid = os.getegid()
-
-        msg = _("Do rotate logfile '%s' ...") % (logfile)
-        self.logger.debug(msg)
-
-        target = self._get_rotation_target(logfile, cur_desc_index, olddir)
-        rotations = self._get_rotations(logfile, target, cur_desc_index)
-
-        extension = rotations['extension']
-        compress_extension = rotations['compress_extension']
-
-        # First move all cyclic stuff
-        for pair in rotations['move']:
-            file_from = pair['from']
-            file_to = pair['to']
-            if pair['compressed']:
-                file_from += compress_extension
-                file_to += compress_extension
-            msg = _("Moving file '%(from)s' => '%(to)s'.") \
-                    % {'from': file_from, 'to': file_to }
-            self.logger.info(msg)
-            if not self.test:
-                try:
-                    shutil.move(file_from, file_to)
-                except OSError:
-                    msg = _("Error on moving '%(from)s' => '%(to)s': %(err)s") \
-                            % {'from': file_from, 'to': file_to, 'err': e.strerror}
-                    self.logger.error(msg)
-                    return False
-
-        # Now the underlaying rotation
-        file_from = rotations['rotate']['from']
-        file_to = rotations['rotate']['to']
-
-        # First check for an existing mail address
-        if definition['mailaddress'] and definition['mailfirst']:
-            self.mailer.send_file(file_from, definition['mailaddress'])
-
-        # separate between copy(truncate) and move (and create)
-        if definition['copytruncate'] or definition['copy']:
-            # Copying logfile to target
-            msg = _("Copying file '%(from)s' => '%(to)s'.") \
-                    % {'from': file_from, 'to': file_to }
-            self.logger.info(msg)
-            if not self.test:
-                try:
-                    shutil.copy2(file_from, file_to)
-                except OSError:
-                    msg = _("Error on copying '%(from)s' => '%(to)s': %(err)s") \
-                            % {'from': file_from, 'to': file_to, 'err': e.strerror}
-                    self.logger.error(msg)
-                    return False
-            if definition['copytruncate']: 
-                msg = _("Truncating file '%s'.") % (file_from)
-                self.logger.info(msg)
-                if not self.test:
-                    try:
-                        fd = open(file_from, 'w')
-                        fd.close()
-                    except IOError, e:
-                        msg = _("Error on truncing file '%(from)s': %(err)s") \
-                                % {'from': file_from, 'err': str(e)}
-                        self.logger.error(msg)
-                        return False
-
-        else:
-
-            # Moving logfile to target
-            msg = _("Moving file '%(from)s' => '%(to)s'.") \
-                    % {'from': file_from, 'to': file_to }
-            self.logger.info(msg)
-
-            # get old permissions of logfile
-            statinfo = os.stat(file_from)
-
-            if not self.test:
-                try:
-                    shutil.move(file_from, file_to)
-                except OSError:
-                    msg = _("Error on moving '%(from)s' => '%(to)s': %(err)s") \
-                            % {'from': file_from, 'to': file_to, 'err': e.strerror}
-                    self.logger.error(msg)
-                    return False
-    
-            if definition['create']['enabled']:
-
-                # Recreate logfile
-                msg = _("Recreating file '%s'.") % (file_from)
-                self.logger.info(msg)
-                if not self.test:
-                    try:
-                        fd = open(file_from, 'w')
-                        fd.close()
-                    except IOError, e:
-                        msg = _("Error on creating file '%(from)s': %(err)s") \
-                                % {'from': file_from, 'err': str(e)}
-                        self.logger.error(msg)
-                        return False
-
-                # Setting permissions and ownership
-                new_mode = statinfo.st_mode
-                new_uid  = statinfo.st_uid
-                new_gid  = statinfo.st_gid
-
-                if not definition['create']['mode'] is None:
-                    new_mode = definition['create']['mode']
-                if not definition['create']['owner'] is None:
-                    new_uid = definition['create']['owner']
-                if not definition['create']['group'] is None:
-                    new_gid = definition['create']['group']
-
-                statinfo = os.stat(file_from)
-                old_mode = statinfo.st_mode
-                old_uid  = statinfo.st_uid
-                old_gid  = statinfo.st_gid
-
-                # Check and set permissions of new logfile
-                if new_mode != old_mode:
-                    msg = _("Setting permissions of '%(file)s' to %(mode)4o.") \
-                            % {'file': file_from, 'mode': new_mode}
-                    self.logger.info(msg)
-                    if not self.test:
-                        try:
-                            os.chmod(file_from, new_mode)
-                        except OSError, e:
-                            msg = _("Error on chmod of '%(file)s': %(err)s") \
-                                    % {'file': file_from, 'err': e.strerror}
-                            self.logger.warning(msg)
-
-                # Check and set ownership of new logfile
-                if (new_uid != old_uid) or (new_gid != old_gid):
-                    myuid = os.geteuid()
-                    if myuid != 0:
-                        msg = _("Only root may execute chown().")
-                        if self.test:
-                            self.logger.info(msg)
-                        else:
-                            self.logger.warning(msg)
-                    else:
-                        msg = _("Setting ownership of '%(file)s' to uid %(uid)d and gid %(gid)d.") \
-                                % {'file': file_from, 'uid': new_uid, 'gid': new_gid}
-                        self.logger.info(msg)
-                        if not self.test:
-                            try:
-                                os.chown(file_from, new_uid, new_gid)
-                            except OSError, e:
-                                msg = _("Error on chown of '%(file)s': %(err)s") \
-                                        % {'file': file_from, 'err': e.strerror}
-                                self.logger.warning(msg)
-
-        oldfiles = self._collect_old_logfiles(logfile, extension, compress_extension, cur_desc_index)
-
-        # get files to delete and save them back in self.files_delete
-        files_delete = self._collect_files_delete(oldfiles, cur_desc_index)
-        if len(files_delete):
-            for oldfile in files_delete:
-                self.files_delete[oldfile] = True
-                if definition['mailaddress'] and not definition['mailfirst']:
-                    self.files2send[oldfile] = (definition['mailaddress'], logfile)
-
-        # get files to compress save them back in self.files_compress
-        files_compress = self._collect_files_compress(oldfiles, compress_extension, cur_desc_index)
-        if len(files_compress):
-            for oldfile in files_compress:
-                self.files_compress[oldfile] = cur_desc_index
-
-        # write back date of rotation into state file
-        self.state_file.set_rotation_date(logfile)
-        self.state_file.write()
-
-        return True
-
-    #------------------------------------------------------------
-    def _collect_files_compress(self, oldfiles, compress_extension, cur_desc_index):
-        '''
-        Collects a list with all old logfiles, they have to compress.
-
-        @param oldfiles: a dict whith all found old logfiles as keys and
-                         their modification time as values
-        @type oldfiles:  dict
-        @param compress_extension: file extension for rotated and
-                                   compressed logfiles
-        @type compress_extension:  str
-        @param cur_desc_index: index of self.config for definition
-                               of logfile from configuration file
-        @type cur_desc_index:  int
-
-        @return: all old (and compressed) logfiles to delete
-        @rtype:  list
-        '''
-
-        definition = self.config[cur_desc_index]
-        _ = self.t.lgettext
-
-        if self.verbose > 2:
-            msg = _("Retrieving logfiles to compress ...")
-            self.logger.debug(msg)
-
-        result = []
-
-        if not definition['compress']:
-            if self.verbose > 3:
-                msg = _("No compression defined.")
-                self.logger.debug(msg)
-            return result
-
-        if not oldfiles.keys():
-            if self.verbose > 3:
-                msg = _("No old logfiles available.")
-                self.logger.debug(msg)
-            return result
-
-        no_compress = definition['delaycompress']
-        if no_compress is None:
-            no_compress = 0
-
-        ce = re.escape(compress_extension)
-        for oldfile in sorted(oldfiles.keys(), key=lambda x: oldfiles[x], reverse=True):
-
-            match = re.search(ce + r'$', oldfile)
-            if match:
-                if self.verbose > 2:
-                    msg = _("File '%s' seems to be compressed, skip it.") % (oldfile)
-                    self.logger.debug(msg)
-                continue
-
-            if oldfile in self.files_delete:
-                if self.verbose > 2:
-                    msg = _("File '%s' will be deleted, compression unnecessary.") % (oldfile)
-                    self.logger.debug(msg)
-                continue
-
-            if no_compress:
-                if self.verbose > 2:
-                    msg = _("Compression of file '%s' will be delayed.") % (oldfile)
-                    self.logger.debug(msg)
-                no_compress -= 1
-                continue
-
-            result.append(oldfile)
-
-        if self.verbose > 3:
-            if len(result):
-                pp = pprint.PrettyPrinter(indent=4)
-                msg = _("Found logfiles to compress:") + "\n" + pp.pformat(result)
-                self.logger.debug(msg)
-            else:
-                msg = _("No old logfiles to compress found.")
-                self.logger.debug(msg)
-        return result
-
-    #------------------------------------------------------------
-    def _collect_files_delete(self, oldfiles, cur_desc_index):
-        '''
-        Collects a list with all old (and compressed) logfiles, they have to delete.
-
-        @param oldfiles: a dict whith all found old logfiles as keys and
-                        their modification time as values
-        @type oldfiles:  dict
-        @param cur_desc_index: index of self.config for definition
-                               of logfile from configuration file
-        @type cur_desc_index:  int
-
-        @return: all old (and compressed) logfiles to delete
-        @rtype:  list
-        '''
-
-        definition = self.config[cur_desc_index]
-        _ = self.t.lgettext
-
-        if self.verbose > 2:
-            msg = _("Retrieving logfiles to delete ...")
-            self.logger.debug(msg)
-
-        result = []
-
-        if not oldfiles.keys():
-            if self.verbose > 3:
-                msg = _("No old logfiles available.")
-                self.logger.debug(msg)
-            return result
-
-        # Maxage in seconds or None
-        maxage = definition['maxage']
-        if maxage is None:
-            if self.verbose >= 4:
-                msg = _("No maxage given.")
-                self.logger.debug(msg)
-        else:
-            maxage *= (24 * 60 * 60)
-            if self.verbose >= 4:
-                msg = _("Maxage: %d seconds") % (maxage)
-                self.logger.debug(msg)
-
-        # Number of rotations or Zero
-        rotate = definition['rotate']
-        if rotate is None:
-            rotate = 0
-        if self.verbose >= 4:
-            msg = _("Max. count rotations: %d") % (rotate)
-            self.logger.debug(msg)
-
-        count = len(oldfiles.keys())
-        for oldfile in sorted(oldfiles.keys(), key=lambda x: oldfiles[x]):
-            count -= 1
-            age = int(time.time() - oldfiles[oldfile])
-            if self.verbose > 3:
-                msg = _("Checking file '%s' for deleting ...") % (oldfile)
-                self.logger.debug(msg)
-            if self.verbose >= 4:
-                msg = _("Current count: %(count)d, current age: %(age)d seconds") \
-                        % {'count': count, 'age': age}
-                self.logger.debug(msg)
-
-            # Delete all files, their count is more than the rotate option
-            if rotate:
-                if count >= rotate:
-                    if self.verbose >= 3:
-                        msg = _("Deleting '%s' because of too much.") % (oldfile)
-                        self.logger.debug(msg)
-                    result.append(oldfile)
-                    continue
-
-            # Now checking for maximum age
-            if maxage:
-                if age >= maxage:
-                    if self.verbose >= 3:
-                        msg = _("Deleting '%s' because of too old.") % (oldfile)
-                        self.logger.debug(msg)
-                    result.append(oldfile)
-
-        if self.verbose > 3:
-            if len(result):
-                pp = pprint.PrettyPrinter(indent=4)
-                msg = _("Found logfiles to delete:") + "\n" + pp.pformat(result)
-                self.logger.debug(msg)
-            else:
-                msg = _("No old logfiles to delete found.")
-                self.logger.debug(msg)
-        return result
-
-    #------------------------------------------------------------
-    def _collect_old_logfiles(self, logfile, extension, compress_extension, cur_desc_index):
-        '''
-        Collect all rotated versions of this logfile and gives back the
-        information about.
-
-        @param logfile: the logfile to rotate
-        @type logfile:  str
-        @param extension: additional fix file extension for rotated logfiles
-        @type extension:  str
-        @param compress_extension: file extension for rotated and
-                                   compressed logfiles
-        @type compress_extension:  str
-        @param cur_desc_index: index of self.config for definition
-                               of logfile from configuration file
-        @type cur_desc_index:  int
-
-        @return: all found old rotated logfiles as keys
-                 and the last modification timestamp of these files as values
-        @rtype:  dict
-        '''
-
-        definition = self.config[cur_desc_index]
-        _ = self.t.lgettext
-
-        if self.verbose > 2:
-            msg = _("Retrieving all old logfiles for file '%s' ...") % (logfile)
-            self.logger.debug(msg)
-
-        result = {}
-
-        basename = os.path.basename(logfile)
-        dirname  = os.path.dirname(logfile)
-
-        if definition['dateext']:
-            basename += '.*'
-
-        if definition['olddir']['dirname']:
-            # Create a file pattern depending on olddir definition
-
-            olddir = definition['olddir']['dirname']
-
-            # Substitution of $dirname
-            olddir = re.sub(r'(?:\${dirname}|\$dirname(?![a-zA-Z0-9_]))', dirname, olddir)
-
-            # Substitution of $basename
-            olddir = re.sub(r'(?:\${basename}|\$basename(?![a-zA-Z0-9_]))', basename, olddir)
-
-            # Substitution of $nodename
-            olddir = re.sub(r'(?:\${nodename}|\$nodename(?![a-zA-Z0-9_]))', self.template['nodename'], olddir)
-
-            # Substitution of $domain
-            olddir = re.sub(r'(?:\${domain}|\$domain(?![a-zA-Z0-9_]))', self.template['domain'], olddir)
-
-            # Substitution of $machine
-            olddir = re.sub(r'(?:\${machine}|\$machine(?![a-zA-Z0-9_]))', self.template['machine'], olddir)
-
-            # Substitution of $release
-            olddir = re.sub(r'(?:\${release}|\$release(?![a-zA-Z0-9_]))', self.template['release'], olddir)
-
-            # Substitution of $sysname
-            olddir = re.sub(r'(?:\${sysname}|\$sysname(?![a-zA-Z0-9_]))', self.template['sysname'], olddir)
-
-            if not os.path.isabs(olddir):
-                olddir = os.path.join(dirname, olddir)
-            olddir = os.path.normpath(olddir)
-
-            ####
-            # Substituting all datetime.strftime() placeholders by shell pattern
-
-            # weekday
-            olddir = re.sub(r'%[aA]', '*', olddir)
-            # name of month
-            olddir = re.sub(r'%[bBh]', '*', olddir)
-            # complete date
-            olddir = re.sub(r'%c', '*', olddir)
-            # century
-            olddir = re.sub(r'%C', '[0-9][0-9]', olddir)
-            # day of month
-            olddir = re.sub(r'%d', '[0-9][0-9]', olddir)
-            # date as %m/%d/%y
-            olddir = re.sub(r'%[Dx]', '[0-9][0-9]/[0-9][0-9]/[0-9][0-9]', olddir)
-            # Hour in 24-hours format
-            olddir = re.sub(r'%H', '[012][0-9]', olddir)
-            # Hour in 12-hours format
-            olddir = re.sub(r'%J', '[01][0-9]', olddir)
-            # number of month
-            olddir = re.sub(r'%m', '[01][0-9]', olddir)
-            # minute
-            olddir = re.sub(r'%M', '[0-5][0-9]', olddir)
-            # AM/PM
-            olddir = re.sub(r'%p', '[AP]M', olddir)
-            # complete time in 12-hours format with AM/PM
-            olddir = re.sub(r'%r', '[01][0-9]:[0-5][0-9]:[0-5][0-9] [AP]M', olddir)
-            # time in format %H:%M
-            olddir = re.sub(r'%R', '[012][0-9]:[0-5][0-9]', olddir)
-            # seconds
-            olddir = re.sub(r'%S', '[0-5][0-9]', olddir)
-            # complete time in 24-hours format
-            olddir = re.sub(r'%[TX]', '[012][0-9]:[0-5][0-9]:[0-5][0-9]', olddir)
-            # weekday as a number (0-7)
-            olddir = re.sub(r'%[uw]', '[0-7]', olddir)
-            # number of week in year (00-53)
-            olddir = re.sub(r'%[UVW]', '[0-5][0-9]', olddir)
-            # last two digits of the year
-            olddir = re.sub(r'%y', '[0-9][0-9]', olddir)
-            # year complete
-            olddir = re.sub(r'%Y', '[12][0-9][0-9][0-9]', olddir)
-            # time zone numeric
-            olddir = re.sub(r'%z', '[-+][0-9][0-9][0-9][0-9]', olddir)
-            # time zone name
-            olddir = re.sub(r'%Z', '*', olddir)
-
-            dirname = olddir
-
-        # composing file pattern
-        file_pattern = os.path.join(dirname, basename)
-        pattern_list = []
-        pattern_list.append(file_pattern + extension)
-        pattern_list.append(file_pattern + '.[0-9]' + extension)
-        pattern_list.append(file_pattern + '.[0-9][0-9]' + extension)
-        pattern_list.append(file_pattern + '.[0-9][0-9][0-9]' + extension)
-        pattern_list.append(file_pattern + '.[0-9][0-9][0-9][0-9]' + extension)
-        pattern_list.append(file_pattern + '.[0-9][0-9][0-9][0-9][0-9]' + extension)
-
-        if definition['compress']:
-            ext = extension + compress_extension
-            pattern_list.append(file_pattern + ext)
-            pattern_list.append(file_pattern + '.[0-9]' + ext)
-            pattern_list.append(file_pattern + '.[0-9][0-9]' + ext)
-            pattern_list.append(file_pattern + '.[0-9][0-9][0-9]' + ext)
-            pattern_list.append(file_pattern + '.[0-9][0-9][0-9][0-9]' + ext)
-            pattern_list.append(file_pattern + '.[0-9][0-9][0-9][0-9][0-9]' + ext)
-
-        for pattern in pattern_list:
-            if self.verbose > 2:
-                msg = _("Search for pattern '%s' ...") % (pattern)
-                self.logger.debug(msg)
-            found_files = glob.glob(pattern) 
-            for oldfile in found_files:
-                oldfile = os.path.abspath(oldfile)
-                if oldfile == logfile:
-                    continue
-                statinfo = os.stat(oldfile)
-                result[oldfile] = statinfo.st_mtime
-
-        if self.verbose > 3:
-            pp = pprint.PrettyPrinter(indent=4)
-            msg = _("Found old logfiles:") + "\n" + pp.pformat(result)
-            self.logger.debug(msg)
-        return result
-
-    #------------------------------------------------------------
-    def _get_rotations(self, logfile, target, cur_desc_index):
-        '''
-        Retrieves all files to move and to rotate and gives them back
-        as a dict.
-
-        @param logfile: the logfile to rotate
-        @type logfile:  str
-        @param target:  name of the rotated logfile
-        @type target:   str
-        @param cur_desc_index: index of self.config for definition
-                               of logfile from configuration file
-        @type cur_desc_index:  int
-
-        @return: dict in the form::
-                    {
-                        'compress_extension': '.gz',
-                        'extension': '',
-                        'rotate': {
-                            'from': <file>,
-                            'to': <target>
-                        },
-                        'move': [
-                            ...
-                            { 'from': <file2>, 'to': <file3>, 'compressed': True},
-                            { 'from': <file1>, 'to': <file2>, 'compressed': True},
-                            { 'from': <file0>, 'to': <file1>, 'compressed': False},
-                        ],
-                    }
-
-                 the order in the list 'move' is the order, how the
-                 files have to rename.
-        @rtype: dict
-        '''
-
-        definition = self.config[cur_desc_index]
-        _ = self.t.lgettext
-
-        if self.verbose > 2:
-            msg = _("Retrieving all movings and rotations for logfile '%(file)s' to target '%(target)s' ...") \
-                    % {'file': logfile, 'target': target}
-            self.logger.debug(msg)
-
-        result = { 'rotate': {}, 'move': [] }
-
-        # retrieve additional file extension of logfile after rotation
-        # without compress extension
-        extension = definition['extension']
-        if extension is None:
-            extension = ''
-        match = re.search(r'^\s*$', extension)
-        if match:
-            extension = ''
-        if extension != '':
-            match = re.search(r'^\.', extension)
-            if not match:
-                extension = "." + extension
-        result['extension'] = extension
-        extension_wo_compress = extension
-
-        # retrieve additional file extension of logfile after rotation
-        # for compress extension
-        compress_extension = ''
-        if definition['compress']:
-            compress_extension = definition['compressext']
-            match = re.search(r'^\.', compress_extension)
-            if not match:
-                compress_extension = "." + compress_extension
-        result['compress_extension'] = compress_extension
-
-        # appending a trailing '.0', if there are no other differences
-        # between logfile and target
-        i = definition['start']
-        if i is None:
-            i = 0
-        resulting_target = target + extension_wo_compress
-        target_wo_number = resulting_target
-        if resulting_target == logfile:
-            resulting_target = resulting_target + "." + str(i)
-
-        result['rotate']['from'] = logfile
-        result['rotate']['to']   = resulting_target
-
-        # resulting target exists, retrieve cyclic rotation
-        if os.path.exists(resulting_target):
-            if self.verbose > 3:
-                msg = _("Resulting target '%s' exists, retrieve cyclic rotation ...") \
-                        % (resulting_target)
-                self.logger.debug(msg)
-            target_wo_cext_old = target_wo_number + "." + str(i)
-            target_with_cext_old = target_wo_cext_old + compress_extension
-            while os.path.exists(target_wo_cext_old) or os.path.exists(target_with_cext_old):
-                i += 1
-                target_wo_cext_new = target_wo_number + "." + str(i)
-                target_with_cext_new = target_wo_cext_new + compress_extension
-                if self.verbose > 4:
-                    msg = _("Cyclic rotation from '%(from)s' to '%(to)s'.") \
-                            % {'from': target_wo_cext_old, 'to': target_wo_cext_new}
-                    self.logger.debug(msg)
-                pair = {
-                    'from': target_wo_cext_old,
-                    'to': target_wo_cext_new,
-                    'compressed': False,
-                }
-                if definition['compress']:
-                    if os.path.exists(target_with_cext_old):
-                        pair['compressed'] = True
-                result['move'].insert(0, pair)
-                target_wo_cext_old = target_wo_cext_new
-                target_with_cext_old = target_with_cext_new
-
-        if self.verbose > 3:
-            pp = pprint.PrettyPrinter(indent=4)
-            msg = _("Found rotations:") + "\n" + pp.pformat(result)
-            self.logger.debug(msg)
-        return result
-
-    #------------------------------------------------------------
-    def _get_rotation_target(self, logfile, cur_desc_index, olddir = None):
-        '''
-        Retrieves the name of the rotated logfile and gives it back.
-
-        @param logfile: the logfile to rotate
-        @type logfile:  str
-        @param cur_desc_index: index of self.config for definition
-                               of logfile from configuration file
-        @type cur_desc_index:  int
-        @param olddir: the directory of the rotated logfile
-                       if None, store the rotated logfile
-                       in their original directory
-        @type olddir: str or None
-
-        @return: name of the rotated logfile
-        @rtype:  str
-        '''
-
-        definition = self.config[cur_desc_index]
-
-        _ = self.t.lgettext
-
-        if self.verbose > 2:
-            msg = _("Retrieving the name of the rotated file of '%s' ...") % (logfile)
-            self.logger.debug(msg)
-
-        target = logfile
-        if olddir is not None:
-            basename = os.path.basename(logfile)
-            target = os.path.join(olddir, basename)
-
-        if definition['dateext']:
-            pattern = definition['datepattern']
-            if pattern is None:
-                pattern = '%Y-%m-%d'
-            dateext = datetime.utcnow().strftime(pattern)
-            if self.verbose > 3:
-                msg = _("Using date extension '.%(ext)s' from pattern '%(pattern)s'.") \
-                        % {'ext': dateext, 'pattern': pattern}
-                self.logger.debug(msg)
-            target += "." + dateext
-
-        if self.verbose > 1:
-            msg = _("Using '%(target)s' as target for rotation of logfile '%(logfile)s'.") \
-                    % {'target': target, 'logfile': logfile}
-            self.logger.debug(msg)
-        return target
-
-    #------------------------------------------------------------
-    def _create_olddir(self, logfile, cur_desc_index):
-        '''
-        Creating the olddir, if necessary.
-
-        @param logfile: the logfile to rotate
-        @type logfile:  str
-        @param cur_desc_index: index of self.config for definition
-                               of logfile from configuration file
-        @type cur_desc_index:  int
-
-        @return: Name of the retrieved olddir, ".", if storing
-                 the rotated logfiles in their original directory or
-                 None in case of some minor errors (olddir couldn't
-                 created a.s.o.)
-        @rtype:  str or None
-        '''
-
-        definition = self.config[cur_desc_index]
-
-        _ = self.t.lgettext
-
-        uid = os.geteuid()
-        gid = os.getegid()
-
-        o = definition['olddir']
-        if not o['dirname']:
-            if self.verbose > 1:
-                msg = _("No dirname directive for olddir given.")
-                self.logger.debug(msg)
-            return "."
-        olddir = o['dirname']
-
-        mode = o['mode']
-        if mode is None:
-            mode = int('0755', 8)
-        owner = o['owner']
-        if not owner:
-            owner = uid
-        group = o['group']
-        if not group:
-            group = gid
-
-        basename = os.path.basename(logfile)
-        dirname  = os.path.dirname(logfile)
-
-        match = re.search(r'%', olddir)
-        if match:
-            o['dateformat'] = True
-            olddir = datetime.utcnow().strftime(olddir)
-
-        # Substitution of $dirname
-        olddir = re.sub(r'(?:\${dirname}|\$dirname(?![a-zA-Z0-9_]))', dirname, olddir)
-
-        # Substitution of $basename
-        olddir = re.sub(r'(?:\${basename}|\$basename(?![a-zA-Z0-9_]))', basename, olddir)
-
-        # Substitution of $nodename
-        olddir = re.sub(r'(?:\${nodename}|\$nodename(?![a-zA-Z0-9_]))', self.template['nodename'], olddir)
-
-        # Substitution of $domain
-        olddir = re.sub(r'(?:\${domain}|\$domain(?![a-zA-Z0-9_]))', self.template['domain'], olddir)
-
-        # Substitution of $machine
-        olddir = re.sub(r'(?:\${machine}|\$machine(?![a-zA-Z0-9_]))', self.template['machine'], olddir)
-
-        # Substitution of $release
-        olddir = re.sub(r'(?:\${release}|\$release(?![a-zA-Z0-9_]))', self.template['release'], olddir)
-
-        # Substitution of $sysname
-        olddir = re.sub(r'(?:\${sysname}|\$sysname(?![a-zA-Z0-9_]))', self.template['sysname'], olddir)
-
-        if not os.path.isabs(olddir):
-            olddir = os.path.join(dirname, olddir)
-        olddir = os.path.normpath(olddir)
-
-        if self.verbose > 1:
-            msg = _("Olddir name is now '%s'") % (olddir)
-            self.logger.debug(msg)
-
-        # Check for Existence and Consistence
-        if os.path.exists(olddir):
-            if os.path.isdir(olddir):
-                if os.access(olddir, (os.W_OK | os.X_OK)):
-                    if self.verbose > 2:
-                        msg = _("Olddir '%s' allready exists, not created.") % (olddir)
-                        self.logger.debug(msg)
-                    olddir = os.path.realpath(olddir)
-                    return olddir
-                else:
-                    msg = _("No write and execute access to olddir '%s'.") % (olddir)
-                    if self.test:
-                        self.logger.warning(msg)
-                        return olddir
-                    raise LogrotateHandlerError(msg)
-                    return None
-            else:
-                msg = _("Olddir '%s' exists, but is not a valid directory.") % (olddir)
-                raise LogrotateHandlerError(msg)
-                return None
-
-        dirs = []
-        dir_head = olddir
-        while dir_head != os.sep:
-            (dir_head, dir_tail) = os.path.split(dir_head)
-            dirs.insert(0, dir_tail)
-        if self.verbose > 2:
-            msg = _("Directory chain to create: '%s'") % (str(dirs))
-            self.logger.debug(msg)
-
-        # Create olddir recursive, if necessary
-        msg = _("Creating olddir '%s' recursive ...") % (olddir)
-        self.logger.info(msg)
-        create_dir = None
-        parent_statinfo = os.stat(os.sep)
-        parent_mode = parent_statinfo.st_mode
-        parent_uid  = parent_statinfo.st_uid
-        parent_gid  = parent_statinfo.st_gid
-        while len(dirs):
-            dir_head = dirs.pop(0)
-            if create_dir:
-                create_dir = os.path.join(create_dir, dir_head)
-            else:
-                create_dir = os.sep + dir_head
-            if self.verbose > 3:
-                msg = _("Try to create directory '%s' ...") % (create_dir)
-                self.logger.debug(msg)
-            if os.path.exists(create_dir):
-                if os.path.isdir(create_dir):
-                    if self.verbose > 3:
-                        msg = _("Directory '%s' allready exists, not created.") % (create_dir)
-                        self.logger.debug(msg)
-                    parent_statinfo = os.stat(create_dir)
-                    parent_mode = parent_statinfo.st_mode
-                    parent_uid  = parent_statinfo.st_uid
-                    parent_gid  = parent_statinfo.st_gid
-                    continue
-                else:
-                    msg = _("Directory '%s' exists, but is not a valid directory.") % (create_dir)
-                    self.logger.error(msg)
-                    return None
-            msg = _("Creating directory '%s' ...") % (create_dir)
-            self.logger.debug(msg)
-            create_mode = parent_mode
-            if o['mode'] is not None:
-                create_mode = o['mode']
-            create_uid = parent_uid
-            if o['owner'] is not None:
-                create_uid = o['owner']
-            create_gid = parent_gid
-            if o['group'] is not None:
-                create_gid = o['group']
-            if self.verbose > 1:
-                msg = _("Create permissions: %(mode)4o, Owner-UID: %(uid)d, Group-GID: %(gid)d") \
-                        % {'mode': create_mode, 'uid': create_uid, 'gid': create_gid}
-                self.logger.debug(msg)
-            if not self.test:
-                if self.verbose > 2:
-                    msg = "os.mkdir('%s', %4o)" % (create_dir, create_mode)
-                    self.logger.debug(msg)
-                try:
-                    os.mkdir(create_dir, create_mode)
-                except OSError, e:
-                    msg = _("Error on creating directory '%(dir)s': %(err)s") \
-                            % {'dir': create_dir, 'err': e.strerror}
-                    self.logger.error(msg)
-                    return None
-                if (create_uid != uid) or (create_gid != gid):
-                    myuid = os.geteuid()
-                    if myuid != 0:
-                        msg = _("Only root may execute chown().")
-                        if self.test:
-                            self.logger.info(msg)
-                        else:
-                            self.logger.warning(msg)
-                    else:
-                        if self.verbose > 2:
-                            msg = "os.chown('%s', %d, %d)" % (create_dir, create_uid, create_gid)
-                            self.logger.debug(msg)
-                        try:
-                            os.chown(create_dir, create_uid, create_gid)
-                        except OSError, e:
-                            msg = _("Error on chowning directory '%(dir)s': %(err)s") \
-                                    % {'dir': create_dir, 'err': e.strerror}
-                            self.logger.error(msg)
-                            return None
-
-        olddir = os.path.realpath(olddir)
-        return olddir
-
-    #------------------------------------------------------------
-    def _execute_command(self, command, force=False, expected_retcode=0):
-        '''
-        Executes the given command as an OS command in a shell.
-
-        @param command: the command to execute
-        @type command:  str
-        @param force:   force executing command even if self.test == True
-        @type force:    bool
-        @param expected_retcode: expected returncode of the command
-                                 (should be 0)
-        @type expected_retcode:  int
-
-        @return: Success of the comand (shell returncode == 0)
-        @rtype:  bool
-        '''
-
-        _ = self.t.lgettext
-        if self.verbose > 3:
-            msg = _("Executing command: '%s'") % (command)
-            self.logger.debug(msg)
-        if not force:
-            if self.test:
-                return True
-        try:
-            retcode = subprocess.call(command, shell=True)
-            if self.verbose > 3:
-                msg = _("Got returncode: '%s'") % (retcode)
-                self.logger.debug(msg)
-            if retcode < 0:
-                msg = _("Child was terminated by signal %d") % (-retcode)
-                self.logger.error(msg)
-                return False
-            if retcode != expected_retcode:
-                return False
-            return True
-        except OSError, e:
-            msg = _("Execution failed: %s") % (str(e))
-            self.logger.error(msg)
-            return False
-
-        return False
-
-    #------------------------------------------------------------
-    def _should_rotate(self, logfile, cur_desc_index):
-        '''
-        Determines, whether a logfile should rotated dependend on
-        the informations in the definition.
-
-        Throughs an LogrotateHandlerError on harder errors.
-
-        @param logfile: the logfile to inspect
-        @type logfile:  str
-        @param cur_desc_index: index of self.config for definition
-                               of logfile from configuration file
-        @type cur_desc_index:  int
-
-        @return: to rotate or not
-        @rtype:  bool
-        '''
-
-        definition = self.config[cur_desc_index]
-
-        _ = self.t.lgettext
-
-        if self.verbose > 2:
-            msg = _("Check, whether logfile '%s' should rotated.") % (logfile)
-            self.logger.debug(msg)
-
-        if not os.path.exists(logfile):
-            msg = _("logfile '%s' doesn't exists, not rotated") % (logfile)
-            if not definition['missingok']:
-                self.logger.error(msg)
-            else:
-                if self.verbose > 1:
-                    self.logger.debug(msg)
-            return False
-
-        if not os.path.isfile(logfile):
-            msg = _("logfile '%s' is not a regular file, not rotated") % (logfile)
-            self.logger.warning(msg)
-            return False
-
-        filesize = os.path.getsize(logfile)
-        if self.verbose > 2:
-            msg = _("Filesize of '%(file)s': %(size)d") % {'file': logfile, 'size': filesize}
-            self.logger.debug(msg)
-
-        if not filesize:
-            if not definition['ifempty']:
-                if self.verbose > 1:
-                    msg = _("Logfile '%s' has a filesize of Zero, not rotated") % (logfile)
-                    self.logger.debug(msg)
-                return False
-
-        if self.force:
-            if self.verbose > 1:
-                msg = _("Rotating of '%s' because of force mode.") % (logfile)
-                self.logger.debug(msg)
-            return True
-
-        maxsize = definition['size']
-        if maxsize is None:
-            maxsize = 0
-
-        last_rotated = self.state_file.get_rotation_date(logfile)
-        if self.verbose > 2:
-            msg = _("Date of last rotation: %s") %(last_rotated.isoformat(' '))
-            self.logger.debug(msg)
-        next_rotation = last_rotated + timedelta(days = definition['period'])
-        if self.verbose > 2:
-            msg = _("Date of next rotation: %s") %(next_rotation.isoformat(' '))
-            self.logger.debug(msg)
-
-        if filesize < maxsize:
-            if self.verbose > 1:
-                msg = _("Filesize %(filesize)d is less than %(maxsize)d, rotation not necessary.") \
-                        % {'filesize': filesize, 'maxsize': maxsize}
-                self.logger.debug(msg)
-            return False
-
-        curdate = datetime.utcnow().replace(tzinfo = utc)
-        if next_rotation > curdate:
-            if self.verbose > 1:
-                msg = _("Date of next rotation '%(next)s' is in future, rotation not necessary.") \
-                        % {'next': next_rotation.isoformat(' ')}
-                self.logger.debug(msg)
-            return False
-
-        return True
-
-    #------------------------------------------------------------
-    def delete_oldfiles(self):
-        '''
-        Deleting of all logfiles in self.files_delete
-
-        @return: None
-        '''
-
-        _ = self.t.lgettext
-
-        msg = _("Deletion of all superfluid logfiles ...")
-        self.logger.debug(msg)
-
-        if not len(self.files_delete.keys()):
-            msg = _("No logfiles to delete found.")
-            self.logger.info(msg)
-
-        for logfile in sorted(self.files_delete.keys(), key=str.lower):
-            msg = _("Deleting file '%s' ...") % (logfile)
-            self.logger.info(msg)
-            if not self.test:
-                try:
-                    os.remove(logfile)
-                except OSError, e:
-                    msg = _("Error on removing file '%(file)s': %(err)s") \
-                            % {'file': logfile, 'err': e.strerror}
-                    self.logger.error(msg)
-
-        return
-
-    #------------------------------------------------------------
-    def compress(self):
-        '''
-        Compressing all logfiles in self.files_compress
-
-        @return: None
-        '''
-
-        _ = self.t.lgettext
-
-        msg = _("Compression of all uncompressed logfiles ...")
-        self.logger.debug(msg)
-
-        if not len(self.files_compress.keys()):
-            msg = _("No logfiles to compress found.")
-            self.logger.info(msg)
-
-        for logfile in sorted(self.files_compress.keys(), key=str.lower):
-
-            cur_desc_index = self.files_compress[logfile]
-            definition = self.config[cur_desc_index]
-            command = definition['compresscmd']
-            compress_extension = definition['compressext']
-            compress_opts = definition['compressoptions']
-
-            match = re.search(r'^\.', compress_extension)
-            if not match:
-                compress_extension = "." + compress_extension
-            target = logfile + compress_extension
-
-            # Check existence source logfile
-            if not os.path.exists(logfile):
-                msg = _("Source file '%s' for compression doesn't exists.") % (logfile)
-                raise LogrotateHandlerError(msg)
-                return
-
-            # Check existence target (compressed file)
-            if os.path.exists(target):
-                if os.path.samefile(logfile, target):
-                    msg = _("Source file '%(source)s' and target file '%(target)s' are the same file.") \
-                            % {'source': logfile, 'target': target}
-                    raise LogrotateHandlerError(msg)
-                    return
-                msg = _("Target file '%s' for compression allready exists.") %(target)
-                self.logger.warning(msg)
-
-            # Check for filesize Zero => not compressed
-            filesize = os.path.getsize(logfile)
-            if filesize <= 0:
-                msg = _("File '%s' has a size of 0, skip compressing.") % (logfile)
-                self.logger.info(msg)
-                continue
-
-            # Execute compressing ...
-            msg = _("Compressing file '%(file)s' to '%(target)s' with '%(cmd)s' ...") \
-                    % {'file': logfile, 'target': target, 'cmd': command}
-            self.logger.info(msg)
-
-            if command == 'internal_gzip':
-                self._compress_internal_gzip(logfile, target)
-            elif command == 'internal_bzip2':
-                self._compress_internal_bzip2(logfile, target)
-            elif command == 'internal_zip':
-                self._compress_internal_zip(logfile, target)
-            else:
-                self._compress_external(logfile, target, command, compress_opts)
-
-        return
-
-    #------------------------------------------------------------
-    def _compress_external(self, source, target, command, options):
-        '''
-        Compression of the given source file to the target file
-        with an external command.
-
-        It raises a LogrotateHandlerError on uncoverable errors.
-
-        @param source: the source file to compress
-        @type source:  str
-        @param target: the filename of the compressed file.
-        @type target:  str
-        @param command: the OS command to use to compress
-        @type command:  str
-        @param options: additional options to the compress command
-                        possible placeholders inside the options:
-                            - {}: placeholder for sourcefile
-                            - []: placeholder for targetfile
-        @type options:  str
-
-        @return: success or not
-        @rtype:  bool
-        '''
-
-        _ = self.t.lgettext
-
-        if self.verbose > 1:
-            msg = _("Compressing source '%(source)s' to target'%(target)s' with command '%(cmd)s'.") \
-                    % {'source': source, 'target': target, 'cmd': command}
-            self.logger.debug(msg)
-
-        if options is None:
-            options = ''
-
-        # substituting [] in compressoptions with qouted target file name
-        match = re.search(r'\[\]', options)
-        if match:
-            if self.verbose > 3:
-                msg = _("Substituting '[]' in compressoptions with '%s'.") % ('"' + target + '"')
-                self.logger.debug(msg)
-            options = re.sub(r'\[\]', '"' + target + '"', options)
-
-        # substituting or trailing command with quoted source file name
-        match = re.search(r'\{\}', options)
-        if match:
-            if self.verbose > 3:
-                msg = _("Substituting '{}' in compressoptions with '%s'.") % ('"' + source + '"')
-                self.logger.debug(msg)
-            options = re.sub(r'\{\}', '"' + source + '"', options)
-        else:
-            options += ' "' + source + '"'
-
-        if self.verbose > 2:
-            msg = _("Compress options: '%s'.") % (options)
-            self.logger.debug(msg)
-
-        cmd = command + ' ' + options
-
-        src_statinfo = os.stat(source)
-
-        if not self._execute_command(cmd):
-            return False
-
-        if not self.test:
-            if not os.path.exists(target):
-                msg = _("Target '%s' of compression doesn't exists after executing compression command.") \
-                        % (target)
-                self.logger.error(msg)
-                return False
-
-        if os.path.exists(source):
-
-            self._copy_file_metadata(source=source, target=target)
-
-            # And last, but not least, delete uncompressed file
-            if self.verbose > 1:
-                msg = _("Deleting uncompressed file '%s' ...") % (source)
-                self.logger.debug(msg)
-
-            if not self.test:
-                try:
-                    os.remove(source)
-                except OSError, e:
-                    msg = _("Error removing uncompressed file '%(file)s': %(msg)") \
-                            % {'file': source, 'msg': str(e) }
-                    self.logger.error(msg)
-                    return False
-
-        else:
-
-            self._copy_file_metadata(target=target, statinfo=src_statinfo)
-
-        return True
-    #------------------------------------------------------------
-    def _copy_file_metadata(self, target, source=None, statinfo=None):
-        '''
-        Copy all metadata (owner, permissions, timestamps a.s.o) from
-        a source file onto a target file.
-        The target file must be exists.
-        Either an existing source file (parameter 'source') or the
-        statinfo of a former existing file (parameter 'statinfo') must
-        be given.
-
-        It raises a LogrotateHandlerError on uncoverable errors.
-
-        @param target: filename of an existing target file or directory
-        @type target:  str
-        @param source: filename of an existing source file or directory
-                       or None, if statinfo was given,
-                       has precedence before a given statinfo
-        @type source:  str or None
-        @param statinfo: stat object from os.stat() or None, if source was given
-        @type statinfo:  stat-object or None
-
-        @return: success or not
-        @rtype:  bool
-        '''
-
-        _ = self.t.lgettext
-
-        if source is None and statinfo is None:
-            msg = _("Neither 'target' nor 'statinfo' was given on calling _copy_file_metadata().")
-            raise LogrotateHandlerError(msg)
-            return False
-
-        if not os.path.exists(target):
-            msg = _("File or directory '%s' doesn't exists.") % (target)
-            if self.test:
-                self.logger.info(msg)
-                return True
-            self.logger.error(msg)
-            return False
-
-        new_statinfo = statinfo
-        old_statinfo = os.stat(target)
-
-        msg = _("Copying all file metadata to target '%s' ...") % (target)
-        self.logger.info(msg)
-
-        if source is not None:
-
-            # a source object was given
-
-            if not os.path.exists(source):
-                msg = _("File or directory '%s' doesn't exists.") % (source)
-                self.logger.error(msg)
-                return False
-
-            new_statinfo = os.stat(source)
-
-            # Copying permissions and timestamps from source to target
-            if self.verbose > 1:
-                msg = _("Copying permissions and timestamps from source '%(src)s' to target '%(target)s'.") \
-                        % {'src': source, 'target': target}
-                self.logger.debug(msg)
-            if not self.test:
-                shutil.copystat(source, target)
-
-        else:
-
-            # a source statinfo was given
-
-            atime = new_statinfo.st_atime
-            mtime = new_statinfo.st_mtime
-            mode  = new_statinfo.st_mode
-
-            # Setting atime and mtime
-            if self.verbose > 1:
-                msg = _("Setting atime and mtime of target '%s'.") % (target)
-                self.logger.debug(msg)
-            if not self.test:
-                try:
-                    os.utime(target, (atime, mtime))
-                except OSError, e:
-                    msg = _("Error on setting times on target file '%(target)s': %(err)s") \
-                            % {'target': target, 'err': e.strerror}
-                    self.logger.warning(msg)
-                    return False
-
-            # Setting permissions
-            old_mode = old_statinfo.st_mode
-            if mode != old_mode:
-                if self.verbose > 1:
-                    msg = _("Setting permissions of '%(target)s' to %(mode)4o.") \
-                            % {'target': target, 'mode': new_mode}
-                    self.logger.info(msg)
-                if not self.test:
-                    try:
-                        os.chmod(target, mode)
-                    except OSError, e:
-                        msg = _("Error on chmod of '%(target)s': %(err)s") \
-                                % {'target': target, 'err': e.strerror}
-                        self.logger.warning(msg)
-                        return False
-
-        # Copying ownership from source to target
-        new_uid = new_statinfo.st_uid
-        new_gid = new_statinfo.st_gid
-        old_uid = old_statinfo.st_uid
-        old_gid = old_statinfo.st_gid
-
-        if (old_uid != new_uid) or (old_gid != new_gid):
-            if self.verbose > 1:
-                msg = _("Copying ownership from source to target.")
-                self.logger.debug(msg)
-            myuid = os.geteuid()
-            if myuid != 0:
-                msg = _("Only root may execute chown().")
-                if self.test:
-                    self.logger.info(msg)
-                    return True
-                else:
-                    self.logger.warning(msg)
-                    return False
-            if not self.test:
-                try:
-                    os.chown(target, old_uid, old_gid)
-                except OSError, e:
-                    msg = _("Error on chown of '%(file)s': %(err)s") \
-                            % {'file': target, 'err': e.strerror}
-                    self.logger.warning(msg)
-                    return False
-
-        return True
-
-    #------------------------------------------------------------
-    def _compress_internal_zip(self, source, target):
-        '''
-        Compression of the given source file to the target file
-        with the Python module zipfile.
-
-        It raises a LogrotateHandlerError on some errors.
-
-        @param source: the source file to compress
-        @type source:  str
-        @param target: the filename of the compressed file.
-        @type target:  str
-
-        @return: success or not
-        @rtype:  bool
-        '''
-
-        _ = self.t.lgettext
-
-        if self.verbose > 1:
-            msg = _("Compressing source '%(source)s' to target'%(target)s' with module zipfile.") \
-                    % {'source': source, 'target': target}
-            self.logger.debug(msg)
-
-        if not self.test:
-
-            # open target for writing
-            f_out = None
-            try:
-                f_out = zipfile.ZipFile(
-                            file=target,
-                            mode='w',
-                            compression=zipfile.ZIP_DEFLATED
-                )
-            except IOError, e:
-                msg = _("Error on open file '%(file)s' on writing: %(err)s") \
-                        % {'file': target, 'err': str(e)}
-                self.logger.error(msg)
-                return False
-
-            basename = os.path.basename(source)
-            f_out.write(source, basename)
-            f_out.close()
-
-        self._copy_file_metadata(source=source, target=target)
-
-        # And last, but not least, delete uncompressed file
-        if self.verbose > 1:
-            msg = _("Deleting uncompressed file '%s' ...") % (source)
-            self.logger.debug(msg)
-
-        if not self.test:
-            try:
-                os.remove(source)
-            except OSError, e:
-                msg = _("Error removing uncompressed file '%(file)s': %(msg)") \
-                        % {'file': source, 'msg': str(e) }
-                self.logger.error(msg)
-                return False
-
-        return True
-
-    #------------------------------------------------------------
-    def _compress_internal_gzip(self, source, target):
-        '''
-        Compression of the given source file to the target file
-        with the Python module gzip.
-        As compression level is allways used 9 (highest compression).
-
-        It raises a LogrotateHandlerError on some errors.
-
-        @param source: the source file to compress
-        @type source:  str
-        @param target: the filename of the compressed file.
-        @type target:  str
-
-        @return: success or not
-        @rtype:  bool
-        '''
-
-        _ = self.t.lgettext
-
-        if self.verbose > 1:
-            msg = _("Compressing source '%(source)s' to target'%(target)s' with module gzip.") \
-                    % {'source': source, 'target': target}
-            self.logger.debug(msg)
-
-        if not self.test:
-            # open source for reading
-            f_in = None
-            try:
-                f_in = open(source, 'rb')
-            except IOError, e:
-                msg = _("Error on open file '%(file)s' on reading: %(err)s") \
-                        % {'file': source, 'err': str(e)}
-                self.logger.error(msg)
-                return False
-
-            # open target for writing
-            f_out = None
-            try:
-                f_out = gzip.open(target, 'wb')
-            except IOError, e:
-                msg = _("Error on open file '%(file)s' on writing: %(err)s") \
-                        % {'file': target, 'err': str(e)}
-                self.logger.error(msg)
-                f_in.close()
-                return False
-
-            # compress and write target
-            f_out.writelines(f_in)
-            # close both files
-            f_out.close()
-            f_in.close()
-
-        self._copy_file_metadata(source=source, target=target)
-
-        # And last, but not least, delete uncompressed file
-        if self.verbose > 1:
-            msg = _("Deleting uncompressed file '%s' ...") % (source)
-            self.logger.debug(msg)
-
-        if not self.test:
-            try:
-                os.remove(source)
-            except OSError, e:
-                msg = _("Error removing uncompressed file '%(file)s': %(msg)") \
-                        % {'file': source, 'msg': str(e) }
-                self.logger.error(msg)
-                return False
-
-        return True
-
-    #------------------------------------------------------------
-    def _compress_internal_bzip2(self, source, target):
-        '''
-        Compression of the given source file to the target file
-        with the Python module bz2.
-        As compression level is allways used 9 (highest compression).
-
-        It raises a LogrotateHandlerError on some errors.
-
-        @param source: the source file to compress
-        @type source:  str
-        @param target: the filename of the compressed file.
-        @type target:  str
-
-        @return: success or not
-        @rtype:  bool
-        '''
-
-        _ = self.t.lgettext
-
-        if self.verbose > 1:
-            msg = _("Compressing source '%(source)s' to target'%(target)s' with module bz2.") \
-                    % {'source': source, 'target': target}
-            self.logger.debug(msg)
-
-        if not self.test:
-            # open source for reading
-            f_in = None
-            try:
-                f_in = open(source, 'rb')
-            except IOError, e:
-                msg = _("Error on open file '%(file)s' on reading: %(err)s") \
-                        % {'file': source, 'err': str(e)}
-                self.logger.error(msg)
-                return False
-
-            # open target for writing
-            f_out = None
-            try:
-                f_out = bz2.BZ2File(target, 'w')
-            except IOError, e:
-                msg = _("Error on open file '%(file)s' on writing: %(err)s") \
-                        % {'file': target, 'err': str(e)}
-                self.logger.error(msg)
-                f_in.close()
-                return False
-
-            # compress and write target
-            f_out.writelines(f_in)
-            # close both files
-            f_out.close()
-            f_in.close()
-
-        self._copy_file_metadata(source=source, target=target)
-
-        # And last, but not least, delete uncompressed file
-        if self.verbose > 1:
-            msg = _("Deleting uncompressed file '%s' ...") % (source)
-            self.logger.debug(msg)
-
-        if not self.test:
-            try:
-                os.remove(source)
-            except OSError, e:
-                msg = _("Error removing uncompressed file '%(file)s': %(msg)") \
-                        % {'file': source, 'msg': str(e) }
-                self.logger.error(msg)
-                return False
-
-        return True
-
-
-    #------------------------------------------------------------
-    def send_logfiles(self):
-        '''
-        Sending all mails, they should be sent, to their recipients.
-        '''
-
-        _ = self.t.lgettext
-
-        if self.verbose > 1:
-            pp = pprint.PrettyPrinter(indent=4)
-            msg = _("Struct files2send:") + "\n" + pp.pformat(self.files2send)
-            self.logger.debug(msg)
-
-        for filename in self.files2send.keys():
-            self.mailer.send_file(filename, self.files2send[filename][0], self.files2send[filename][1])
-
-        return
-
-#========================================================================
-
-if __name__ == "__main__":
-    pass
-
-
-#========================================================================
-
-# vim: fileencoding=utf-8 filetype=python ts=4 expandtab
diff --git a/LogRotateMailer.py b/LogRotateMailer.py
deleted file mode 100755 (executable)
index 9ff2628..0000000
+++ /dev/null
@@ -1,574 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-# $Id$
-# $URL$
-
-'''
-@author: Frank Brehm
-@contact: frank@brehm-online.com
-@license: GPL3
-@copyright: (c) 2010-2011 by Frank Brehm, Berlin
-@version: 0.0.2
-@summary: module for a logrotate mailer object to send
-          rotated logfiles per mail to a reciepient
-'''
-
-import re
-import logging
-import pprint
-import gettext
-import os
-import os.path
-import sys
-import pwd
-import socket
-import csv
-
-from datetime import datetime
-
-import mimetypes
-import email.utils
-from email import encoders
-from email.message import Message
-from email.mime.base import MIMEBase
-from email.mime.multipart import MIMEMultipart
-from email.mime.nonmultipart import MIMENonMultipart
-from email.mime.text import MIMEText
-
-from quopri import encodestring as _encodestring
-
-from LogRotateCommon import email_valid
-
-revision = '$Revision$'
-revision = re.sub( r'\$', '', revision )
-revision = re.sub( r'Revision: ', r'r', revision )
-revision = re.sub( r'\s*$', '', revision )
-
-__author__    = 'Frank Brehm'
-__copyright__ = '(C) 2011 by Frank Brehm, Berlin'
-__contact__    = 'frank@brehm-online.com'
-__version__    = '0.1.0 ' + revision
-__license__    = 'GPL3'
-
-#========================================================================
-
-class LogRotateMailerError(Exception):
-    '''
-    Base class for exceptions in this module.
-    '''
-
-#========================================================================
-
-class LogRotateMailer(object):
-    '''
-    Class for a mailer object to send
-    rotated logfiles per mail to a reciepient
-
-    @author: Frank Brehm
-    @contact: frank@brehm-online.com
-    '''
-
-    #-------------------------------------------------------
-    def __init__( self, local_dir = None,
-                        verbose   = 0,
-                        test_mode = False,
-                        mailer_version = None,
-    ):
-        '''
-        Constructor.
-
-        @param local_dir:      The directory, where the i18n-files (*.mo)
-                               are located. If None, then system default
-                               (/usr/share/locale) is used.
-        @type local_dir:       str or None
-        @param verbose:        verbosity (debug) level
-        @type verbose:         int
-        @param test_mode:      test mode - no write actions are made
-        @type test_mode:       bool
-        @param mailer_version: version of the X-Mailer tag in the mail header
-        @type mailer_version:  str
-
-        @return: None
-        '''
-
-        self.t = gettext.translation(
-            'LogRotateMailer',
-            local_dir,
-            fallback = True
-        )
-        '''
-        @ivar: a gettext translation object
-        @type: gettext.translation
-        '''
-
-        _ = self.t.lgettext
-
-        self.verbose = verbose
-        '''
-        @ivar: verbosity level (0 - 9)
-        @type: int
-        '''
-
-        self.test_mode = test_mode
-        '''
-        @ivar: test mode - no write actions are made
-        @type: bool
-        '''
-
-        self.logger = logging.getLogger('pylogrotate.mailer')
-        '''
-        @ivar: logger object
-        @type: logging.getLogger
-        '''
-
-        self._sendmail = None
-        '''
-        @ivar: file name of the sendmail executable
-               ('/usr/sbin/sendmail' or '/usr/lib/sendmail')
-               used for sending the mails.
-               if None, the mails will sended via SMTP
-        @type: str or None
-        '''
-        self._init_sendmail()
-
-        self._from_address = ('me', 'info@uhu-banane.de')
-        '''
-        @ivar: Mailaddress of the sender, tuple with the real name of
-               the sender and his mail address as the second value
-        @type: tuple
-        '''
-        self._init_from_address()
-
-        self._smtp_host = 'localhost'
-        '''
-        @ivar: the hostname to use for SMTP (smarthost), if no
-               sendmail binary was found
-        @type: str
-        '''
-
-        self._smtp_port = 25
-        '''
-        @ivar: the port to use for SMTP to the smarthost
-        @type: int
-        '''
-
-        self._smtp_tls  = False
-        '''
-        @ivar: use TLS for sending via SMTP to smarthost
-        @type: bool
-        '''
-
-        self.smtp_user = None
-        '''
-        @ivar: Authentication username for SMTP
-        @type: str or None
-        '''
-
-        self.smtp_passwd = None
-        '''
-        @ivar: Authentication password for SMTP
-        @type: str or None
-        '''
-
-        self.mailer_version = __version__
-        '''
-        @ivar: version of the X-Mailer tag in the mail header
-        @type: str
-        '''
-        if mailer_version is not None:
-            self.mailer_version = mailer_version
-
-    #------------------------------------------------------------
-    # Defintion of some properties
-
-    #------------------------------------------------------------
-    # Property 'from'
-    def _get_from_address(self):
-        '''
-        Getter method for property 'from_address'
-        '''
-        return email.utils.formataddr(self._from_address)
-
-    def _set_from_address(self, value):
-        '''
-        Setter method for property 'from_address'
-        '''
-        _ = self.t.lgettext
-        if value is None:
-            msg = _("The 'From' address may not set to None.")
-            raise LogRotateMailerError(msg)
-        pair = ('', '')
-        if isinstance(value, tuple):
-            if len(value) < 2:
-                pair = email.utils.parseaddr(value[0])
-            else:
-                pair = (value[0], value[1])
-        else:
-            pair = email.utils.parseaddr(value)
-
-        if ( (pair[0] is None or pair[0] == '') and
-             (pair[1] is None or pair[1] == '') ):
-            msg = _("Invalid mail address given: '%s'.") % (str(value))
-            raise LogRotateMailerError(msg)
-
-        if not email_valid(pair[1]):
-            msg = _("Invalid mail address given: '%s'.") % (str(value))
-            raise LogRotateMailerError(msg)
-
-        self._from_address = pair
-        if self.verbose > 3:
-            addr = email.utils.formataddr(pair)
-            msg = _("Set sender mail address to: '%s'.") % (addr)
-            self.logger.debug(msg)
-
-    def _del_from_address(self):
-        '''
-        Deleter method for property 'from_address'
-        '''
-        self._init_from_address()
-
-    from_address = property(_get_from_address, _set_from_address, _del_from_address, "The mail address of the sender")
-
-    #------------------------------------------------------------
-    # Property 'sendmail'
-    def _get_sendmail(self):
-        '''
-        Getter method for property 'sendmail'
-        '''
-        return self._sendmail
-
-    def _set_sendmail(self, value):
-        '''
-        Setter method for property 'sendmail'
-        '''
-        _ = self.t.lgettext
-        if value is None or value == '':
-            self._sendmail = None
-            return
-
-        if os.path.isabs(value):
-            if os.path.exists(value):
-                cmd = os.path.normpath(value)
-                if os.access(cmd, os.X_OK):
-                    msg = _("Using '%s' as the sendmail command.") % (cmd)
-                    self.logger.debug(msg)
-                    self._sendmail = cmd
-                    return
-                else:
-                    msg = _("No execute permissions to '%s'.") % (cmd)
-                    self.logger.warning(msg)
-                    return
-            else:
-                msg = _("Sendmail command '%s' not found.") % (value)
-                self.logger.warning(msg)
-                return
-        else:
-            msg = _("Only absolute path allowed for a sendmail command: '%s'.") % (value)
-            self.logger.warning(msg)
-            return
-
-    def _del_sendmail(self):
-        '''
-        Deleter method for property 'from_address'
-        '''
-        self._sendmail = None
-
-    sendmail = property(_get_sendmail, _set_sendmail, _del_sendmail, "The sendmail executable for sending mails local")
-
-    #------------------------------------------------------------
-    # Property 'smtp_host'
-    def _get_smtp_host(self):
-        '''
-        Getter method for property 'smtp_host'
-        '''
-        return self._smtp_host
-
-    def _set_smtp_host(self, value):
-        '''
-        Setter method for property 'smtp_host'
-        '''
-        _ = self.t.lgettext
-        if value:
-            self._smtp_host = value
-
-    smtp_host = property(_get_smtp_host, _set_smtp_host, None, "The hostname to use for sending mails via SMTP (smarthost)")
-
-    #------------------------------------------------------------
-    # Property 'smtp_port'
-    def _get_smtp_port(self):
-        '''
-        Getter method for property 'smtp_port'
-        '''
-        return self._smtp_port
-
-    def _set_smtp_port(self, value):
-        '''
-        Setter method for property 'smtp_port'
-        '''
-        _ = self.t.lgettext
-        if value:
-            port = 25
-            try:
-                port = int(value)
-            except ValueError, e:
-                return
-            if port < 1 or port >= 2**15:
-                return
-            self._smtp_port = port
-
-    smtp_port = property(_get_smtp_port, _set_smtp_port, None, "The port to use for sending mails via SMTP")
-
-    #------------------------------------------------------------
-    # Property 'smtp_tls'
-    def _get_smtp_tls(self):
-        '''
-        Getter method for property 'smtp_tls'
-        '''
-        return self._smtp_tls
-
-    def _set_smtp_tls(self, value):
-        '''
-        Setter method for property 'smtp_tls'
-        '''
-        self._smtp_tls = bool(value)
-
-    smtp_tls = property(_get_smtp_tls, _set_smtp_tls, None, "Use TLS for sending mails via SMTP (smarthost)")
-
-    #------------------------------------------------------------
-    # Other Methods
-
-    #-------------------------------------------------------
-    def __del__(self):
-        '''
-        Destructor.
-        '''
-
-        _ = self.t.lgettext
-        if self.verbose > 2:
-            msg = _("Mailer object will destroyed.")
-            self.logger.debug(msg)
-
-    #------------------------------------------------------------
-    def __str__(self):
-        '''
-        Typecasting function for translating object structure
-        into a string
-
-        @return: structure as string
-        @rtype:  str
-        '''
-
-        pp = pprint.PrettyPrinter(indent=4)
-        structure = self.as_dict()
-        return pp.pformat(structure)
-
-    #-------------------------------------------------------
-    def as_dict(self):
-        '''
-        Transforms the elements of the object into a dict
-
-        @return: structure as dict
-        @rtype:  dict
-        '''
-
-        res = {}
-        res['t']              = self.t
-        res['verbose']        = self.verbose
-        res['test_mode']      = self.test_mode
-        res['logger']         = self.logger
-        res['sendmail']       = self.sendmail
-        res['from']           = self.from_address
-        res['smtp_host']      = self.smtp_host
-        res['smtp_port']      = self.smtp_port
-        res['smtp_tls']       = self.smtp_tls
-        res['smtp_user']      = self.smtp_user
-        res['smtp_passwd']    = self.smtp_passwd
-        res['mailer_version'] = self.mailer_version
-
-        return res
-
-    #-------------------------------------------------------
-    def _init_from_address(self):
-        '''
-        Initialises the sender mail address
-        '''
-
-        _ = self.t.lgettext
-
-        cur_user = pwd.getpwuid(os.getuid())[0]
-        cur_host = socket.getfqdn()
-        addr = cur_user + '@' + cur_host
-
-        if self.verbose > 3:
-            msg = _("Using <%s> as the sender mail address.") % (addr)
-            self.logger.debug(msg)
-
-        self._from_address = (None, addr)
-
-    #-------------------------------------------------------
-    def _init_sendmail(self):
-        '''
-        Initialises the sendmail with 
-        '''
-
-        _ = self.t.lgettext
-
-        progs = [
-            os.sep + os.path.join('usr', 'sbin', 'sendmail'),
-            os.sep + os.path.join('usr', 'lib', 'sendmail'),
-        ]
-
-        if self.verbose > 3:
-            msg = _("Initial search for the sendmail executable ...")
-            self.logger.debug(msg)
-
-        for prog in progs:
-
-            if self.verbose > 3:
-                msg = _("Testing for '%s' ...") % (prog)
-                self.logger.debug(msg)
-
-            if os.path.exists(prog):
-                if os.access(prog, os.X_OK):
-                    if self.verbose > 1:
-                            msg = _("Using '%s' as the sendmail command.") % (prog)
-                            self.logger.debug(msg)
-                    self._sendmail = prog
-                    break
-                else:
-                    msg = _("No execute permissions to '%s'.") % (prog)
-                    self.logger.warning(msg)
-
-        return
-
-    #-------------------------------------------------------
-    def send_file(self,
-            filename,
-            addresses,
-            original=None,
-            mime_type='text/plain',
-            rotate_date=None,
-            charset=None
-            ):
-        '''
-        Mails the file with the given file name as an attachement
-        to the given recipient(s).
-
-        Raises a LogRotateMailerError on harder errors.
-
-        @param filename:  The file name of the file to send (the existing,
-                          rotated and maybe compressed logfile).
-        @type filename:   str
-        @param addresses: A list of tuples of a pair in the form
-                          of the return value of email.utils.parseaddr()
-        @type addresses:  list
-        @param original:  The file name of the original (unrotated) logfile for
-                          informational purposes.
-                          If not given, filename is used instead.
-        @type original:   str or None
-        @param mime_type: MIME type (content type) of the original logfile,
-                          defaults to 'text/plain'
-        @type mime_type:  str
-        @param rotate_date: datetime object of rotation, defaults to now()
-        @type rotate_date:  datetime or None
-        @param charset: character set of (uncompreesed) logfile, if the
-                        mime_type is 'text/plain', defaults to 'utf-8'
-        @type charset:  str or None
-
-        @return: success of sending
-        @rtype:  bool
-        '''
-
-        _ = self.t.lgettext
-
-        if not os.path.exists(filename):
-            msg = _("File '%s' dosn't exists.") % (filename)
-            self.logger.error(msg)
-            return False
-
-        if not os.path.isfile(filename):
-            msg = _("File '%s' is not a regular file.") % (filename)
-            self.logger.warning(msg)
-            return False
-
-        basename = os.path.basename(filename)
-        if not original:
-            original = os.path.abspath(filename)
-
-        if not rotate_date:
-            rotate_date = datetime.now()
-
-        msg = _("Sending mail with attached file '%(file)s' to: %(rcpt)s") \
-                % {'file': basename,
-                   'rcpt': ', '.join(map(lambda x: '"' + email.utils.formataddr(x) + '"', addresses))}
-        self.logger.debug(msg)
-
-        mail_container = MIMEMultipart()
-        mail_container['Subject']  = ( "Rotated logfile '%s'" % (filename) )
-        mail_container['X-Mailer'] = ( "pylogrotate version %s" % (self.mailer_version) )
-        mail_container['From']     = self.from_address
-        mail_container['To']       = ', '.join(map(lambda x: email.utils.formataddr(x), addresses))
-        mail_container.preamble = 'You will not see this in a MIME-aware mail reader.\n'
-
-        # Generate Text of the first part of mail body
-        mailtext = "Rotated Logfile:\n\n"
-        mailtext += "\t - " + filename + "\n"
-        mailtext += "\t   (" + original + ")\n"
-        mailtext += "\n"
-        mailtext += "Date of rotation: " + rotate_date.isoformat(' ')
-        mailtext += "\n"
-        mailtext = _encodestring(mailtext, quotetabs=False)
-        mail_part = MIMENonMultipart('text', 'plain', charset=sys.getdefaultencoding())
-        mail_part.set_payload(mailtext)
-        mail_part['Content-Transfer-Encoding'] = 'quoted-printable'
-        mail_container.attach(mail_part)
-
-        ctype, encoding = mimetypes.guess_type(filename)
-        if self.verbose > 3:
-            msg = _("Guessed content-type: '%(ctype)s' and encoding '%(encoding)s'.") \
-                    % {'ctype': ctype, 'encoding': encoding }
-            self.logger.debug(msg)
-
-        if encoding:
-            if encoding == 'gzip':
-                ctype = 'application/x-gzip'
-            elif encoding == 'bzip2':
-                ctype = 'application/x-bzip2'
-            else:
-                ctype = 'application/octet-stream'
-
-        if not ctype:
-            ctype = mime_type
-
-        maintype, subtype = ctype.split('/', 1)
-        fp = open(filename, 'rb')
-        mail_part = MIMEBase(maintype, subtype)
-        mail_part.set_payload(fp.read())
-        fp.close()
-        if maintype == 'text':
-            msgtext = mail_part.get_payload()
-            msgtext =  _encodestring(msgtext, quotetabs=False)
-            mail_part.set_payload(msgtext)
-            mail_part['Content-Transfer-Encoding'] = 'quoted-printable'
-        else:
-            encoders.encode_base64(mail_part)
-        mail_part.add_header('Content-Disposition', 'attachment', filename=basename)
-        mail_container.attach(mail_part)
-
-        composed = mail_container.as_string()
-        if self.verbose > 4:
-            msg = _("Generated E-mail:") + "\n" + composed
-            self.logger.debug(msg)
-
-        return True
-
-#========================================================================
-
-if __name__ == "__main__":
-    pass
-
-
-#========================================================================
-
-# vim: fileencoding=utf-8 filetype=python ts=4 expandtab
diff --git a/LogRotateScript.py b/LogRotateScript.py
deleted file mode 100755 (executable)
index 34268ca..0000000
+++ /dev/null
@@ -1,550 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-# $Id$
-# $URL$
-
-'''
-@author: Frank Brehm
-@contact: frank@brehm-online.com
-@license: GPL3
-@copyright: (c) 2010-2011 by Frank Brehm, Berlin
-@version: 0.0.2
-@summary: module for a logrotate script object
-         (for pre- and postrotate actions)
-'''
-import re
-import logging
-import subprocess
-import pprint
-import gettext
-
-revision = '$Revision$'
-revision = re.sub( r'\$', '', revision )
-revision = re.sub( r'Revision: ', r'r', revision )
-revision = re.sub( r'\s*$', '', revision )
-
-__author__    = 'Frank Brehm'
-__copyright__ = '(C) 2011 by Frank Brehm, Berlin'
-__contact__    = 'frank@brehm-online.com'
-__version__    = '0.1.0 ' + revision
-__license__    = 'GPL3'
-
-#========================================================================
-
-class LogRotateScriptError(Exception):
-    '''
-    Base class for exceptions in this module.
-    '''
-
-#========================================================================
-
-class LogRotateScript(object):
-    '''
-    Class for encapsulating a logrotate script
-    (for pre- and postrotate actions)
-
-    @author: Frank Brehm
-    @contact: frank@brehm-online.com
-    '''
-
-    #-------------------------------------------------------
-    def __init__( self, name,
-                        local_dir = None,
-                        verbose   = 0,
-                        test_mode = False,
-    ):
-        '''
-        Constructor.
-
-        @param name:      the name of the script as an identifier
-        @type name:       str
-        @param local_dir: The directory, where the i18n-files (*.mo)
-                          are located. If None, then system default
-                          (/usr/share/locale) is used.
-        @type local_dir:  str or None
-        @param verbose:   verbosity (debug) level
-        @type verbose:    int
-        @param test_mode: test mode - no write actions are made
-        @type test_mode:  bool
-
-        @return: None
-        '''
-
-        self.t = gettext.translation(
-            'LogRotateScript',
-            local_dir,
-            fallback = True
-        )
-        '''
-        @ivar: a gettext translation object
-        @type: gettext.translation
-        '''
-
-        _ = self.t.lgettext
-
-        self.verbose = verbose
-        '''
-        @ivar: verbosity level (0 - 9)
-        @type: int
-        '''
-
-        self._name = name
-        '''
-        @ivar: the name of the script as an identifier
-        @type: str
-        '''
-
-        self.test_mode = test_mode
-        '''
-        @ivar: test mode - no write actions are made
-        @type: bool
-        '''
-
-        self.logger = logging.getLogger('pylogrotate.script')
-        '''
-        @ivar: logger object
-        @type: logging.getLogger
-        '''
-
-        self._cmd = []
-        '''
-        @ivar: List of commands to execute
-        @type: list
-        '''
-
-        self._post_files = 0
-        '''
-        @ivar: Number of logfiles referencing to this script
-               as a postrotate script
-        @type: int
-        '''
-
-        self._last_files = 0
-        '''
-        @ivar: Number of logfiles referencing to this script
-               as a lastaction script
-        @type: int
-        '''
-
-        self._done_firstrun = False
-        '''
-        @ivar: Flag, whether the script was executed as
-               a firstaction script
-        @type: bool
-        '''
-
-        self._done_prerun = False
-        '''
-        @ivar: Flag, whether the script was executed as
-               a prerun script
-        @type: bool
-        '''
-
-        self._done_postrun = False
-        '''
-        @ivar: Flag, whether the script was executed as
-               a postrun script
-        @type: bool
-        '''
-
-        self._done_lastrun = False
-        '''
-        @ivar: Flag, whether the script was executed as
-               a lastaction script
-        @type: bool
-        '''
-
-        self._do_post = False
-        '''
-        Runtime flag, that the script should be executed
-        as an postrun script
-        '''
-
-        self._do_last = False
-        '''
-        Runtime flag, that the script should be executed
-        as an lastaction script
-        '''
-
-    #------------------------------------------------------------
-    # Defintion of some properties
-
-    #------------------------------------------------------------
-    # Property 'name'
-    def _get_name(self):
-        '''
-        Getter method for property 'name'
-        '''
-        return self._name
-
-    name = property(_get_name, None, None, "Name of the script as an identifier")
-
-    #------------------------------------------------------------
-    # Property 'cmd'
-    def _get_cmd(self):
-        '''
-        Getter method for property 'cmd'
-        '''
-        if len(self._cmd):
-            return "\n".join(self._cmd)
-        else:
-            return None
-
-    def _set_cmd(self, value):
-        '''
-        Setter method for property 'cmd'
-        '''
-        if value:
-            if isinstance(value, list):
-                self._cmd = value[:]
-            else:
-                self._cmd = [value]
-        else:
-            self._cmd = []
-
-    def _del_cmd(self):
-        '''
-        Deleter method for property 'cmd'
-        '''
-        self._cmd = []
-
-    cmd = property(_get_cmd, _set_cmd, _del_cmd, "the commands to execute")
-
-    #------------------------------------------------------------
-    # Property 'post_files'
-    def _get_post_files(self):
-        '''
-        Getter method for property 'post_files'
-        '''
-        return self._post_files
-
-    def _set_post_files(self, value):
-        '''
-        Setter method for property 'post_files'
-        '''
-        _ = self.t.lgettext
-        if isinstance(value, int):
-            self._post_files = value
-        else:
-            msg = _("Invalid value for property '%s' given.") % ('post_files')
-            raise LogRotateScriptError(msg)
-
-    post_files = property(
-                    _get_post_files,
-                    _set_post_files,
-                    None,
-                    "Number of logfiles referencing to this script as a postrotate script."
-    )
-
-    #------------------------------------------------------------
-    # Property 'last_files'
-    def _get_last_files(self):
-        '''
-        Getter method for property 'last_files'
-        '''
-        return self._last_files
-
-    def _set_last_files(self, value):
-        '''
-        Setter method for property 'last_files'
-        '''
-        _ = self.t.lgettext
-        if isinstance(value, int):
-            self._last_files = value
-        else:
-            msg = _("Invalid value for property '%s' given.") % ('last_files')
-            raise LogRotateScriptError(msg)
-
-    last_files = property(
-                    _get_last_files,
-                    _set_last_files,
-                    None,
-                    "Number of logfiles referencing to this script as a lastaction script."
-    )
-
-    #------------------------------------------------------------
-    # Property 'done_firstrun'
-    def _get_done_firstrun(self):
-        '''
-        Getter method for property 'done_firstrun'
-        '''
-        return self._done_firstrun
-
-    def _set_done_firstrun(self, value):
-        '''
-        Setter method for property 'done_firstrun'
-        '''
-        self._done_firstrun = bool(value)
-
-    done_firstrun = property(
-                    _get_done_firstrun,
-                    _set_done_firstrun,
-                    None,
-                    "Flag, whether the script was executed as a firstaction script."
-    )
-
-    #------------------------------------------------------------
-    # Property 'done_prerun'
-    def _get_done_prerun(self):
-        '''
-        Getter method for property 'done_prerun'
-        '''
-        return self._done_prerun
-
-    def _set_done_prerun(self, value):
-        '''
-        Setter method for property 'done_prerun'
-        '''
-        self._done_prerun = bool(value)
-
-    done_prerun = property(
-                    _get_done_prerun,
-                    _set_done_prerun,
-                    None,
-                    "Flag, whether the script was executed as a prerun script."
-    )
-
-    #------------------------------------------------------------
-    # Property 'done_postrun'
-    def _get_done_postrun(self):
-        '''
-        Getter method for property 'done_postrun'
-        '''
-        return self._done_postrun
-
-    def _set_done_postrun(self, value):
-        '''
-        Setter method for property 'done_postrun'
-        '''
-        self._done_postrun = bool(value)
-
-    done_postrun = property(
-                    _get_done_postrun,
-                    _set_done_postrun,
-                    None,
-                    "Flag, whether the script was executed as a postrun script."
-    )
-
-    #------------------------------------------------------------
-    # Property 'done_lastrun'
-    def _get_done_lastrun(self):
-        '''
-        Getter method for property 'done_lastrun'
-        '''
-        return self._done_lastrun
-
-    def _set_done_lastrun(self, value):
-        '''
-        Setter method for property 'done_lastrun'
-        '''
-        self._done_lastrun = bool(value)
-
-    done_lastrun = property(
-                    _get_done_lastrun,
-                    _set_done_lastrun,
-                    None,
-                    "Flag, whether the script was executed as a lastaction script."
-    )
-
-    #------------------------------------------------------------
-    # Property 'do_post'
-    def _get_do_post(self):
-        '''
-        Getter method for property 'do_post'
-        '''
-        return self._do_post
-
-    def _set_do_post(self, value):
-        '''
-        Setter method for property 'do_post'
-        '''
-        self._do_post = bool(value)
-
-    do_post = property(
-                    _get_do_post,
-                    _set_do_post,
-                    None,
-                    "Flag, whether the script should be executed as a postrun script."
-    )
-
-    #------------------------------------------------------------
-    # Property 'do_last'
-    def _get_do_last(self):
-        '''
-        Getter method for property 'do_last'
-        '''
-        return self._do_last
-
-    def _set_do_last(self, value):
-        '''
-        Setter method for property 'do_last'
-        '''
-        self._do_last = bool(value)
-
-    do_last = property(
-                    _get_do_last,
-                    _set_do_last,
-                    None,
-                    "Flag, whether the script should be executed as a lastaction script."
-    )
-
-    #------------------------------------------------------------
-    # Other Methods
-
-    #-------------------------------------------------------
-    def __del__(self):
-        '''
-        Destructor.
-        Checks, whether the script should even be run as
-        a postrun or a lastaction script
-        '''
-
-        _ = self.t.lgettext
-        if self.verbose > 2:
-            msg = _("Logrotate script object '%s' will destroyed.") % (self.name)
-            self.logger.debug(msg)
-
-        self.check_for_execute()
-
-    #------------------------------------------------------------
-    def __str__(self):
-        '''
-        Typecasting function for translating object structure
-        into a string
-
-        @return: structure as string
-        @rtype:  str
-        '''
-
-        pp = pprint.PrettyPrinter(indent=4)
-        structure = self.as_dict()
-        return pp.pformat(structure)
-
-    #-------------------------------------------------------
-    def as_dict(self):
-        '''
-        Transforms the elements of the object into a dict
-
-        @return: structure as dict
-        @rtype:  dict
-        '''
-
-        res = {}
-        res['t']             = self.t
-        res['verbose']       = self.verbose
-        res['name']          = self.name
-        res['test_mode']     = self.test_mode
-        res['logger']        = self.logger
-        res['cmd']           = self._cmd[:]
-        res['post_files']    = self.post_files
-        res['last_files']    = self.last_files
-        res['done_firstrun'] = self.done_firstrun
-        res['done_prerun']   = self.done_prerun
-        res['done_postrun']  = self.done_postrun
-        res['done_lastrun']  = self.done_lastrun
-        res['do_post']       = self.do_post
-        res['do_last']       = self.do_last
-
-        return res
-
-    #------------------------------------------------------------
-    def add_cmd(self, cmd):
-        '''
-        Adding a command to the list self._cmd
-
-        @param cmd: the command to add to self._cmd
-        @type cmd:  str
-
-        @return: None
-        '''
-        self._cmd.append(cmd)
-
-    #------------------------------------------------------------
-    def execute(self, force=False, expected_retcode=0):
-        '''
-        Executes the command as an OS command in a shell.
-
-        @param force: force executing command even
-                      if self.test_mode == True
-        @type force:    bool
-        @param expected_retcode: expected returncode of the command
-                                 (should be 0)
-        @type expected_retcode:  int
-
-        @return: Success of the comand (shell returncode == 0)
-        @rtype:  bool
-        '''
-
-        _ = self.t.lgettext
-        cmd = self.cmd
-        if cmd is None:
-            msg = _("No command to execute defined in script '%s'.") % (self.name)
-            raise LogRotateScriptError(msg)
-            return False
-        if self.verbose > 3:
-            msg = _("Executing script '%(name)s' with command: '%(cmd)s'") \
-                    % {'name': self.name, 'cmd': cmd}
-            self.logger.debug(msg)
-        if not force:
-            if self.test_mode:
-                return True
-        try:
-            retcode = subprocess.call(command, shell=True)
-            if self.verbose > 3:
-                msg = _("Got returncode for script '%(name)s': '%(retcode)s'") \
-                        % {'name': self.name, 'retcode': retcode}
-                self.logger.debug(msg)
-            if retcode < 0:
-                msg = _("Child in script '%(name)s' was terminated by signal %(retcode)d") \
-                        % {'name': self.name, 'retcode': -retcode}
-                self.logger.error(msg)
-                return False
-            if retcode != expected_retcode:
-                return False
-            return True
-        except OSError, e:
-            msg = _("Execution of script '%(name)s' failed: %(error)s") \
-                    % {'name': self.name, 'error': str(e)}
-            self.logger.error(msg)
-            return False
-
-        return False
-
-    #------------------------------------------------------------
-    def check_for_execute(self, force=False, expected_retcode=0):
-        '''
-        Checks, whether the script should executed.
-
-        @param force: force executing command even
-                      if self.test_mode == True
-        @type force:    bool
-        @param expected_retcode: expected returncode of the command
-                                 (should be 0)
-        @type expected_retcode:  int
-
-        @return: Success of execution
-        @rtype:  bool
-        '''
-
-        _ = self.t.lgettext
-        msg = _("Checking, whether the script '%s' should be executed.") % (self.name)
-        self.logger.debug(msg)
-
-        if self.do_post or self.do_last:
-            result = self.execute(force=force, expected_retcode=expected_retcode)
-            self.do_post = False
-            self.do_last = False
-            return result
-
-        return True
-
-#========================================================================
-
-if __name__ == "__main__":
-    pass
-
-
-#========================================================================
-
-# vim: fileencoding=utf-8 filetype=python ts=4 expandtab
diff --git a/LogRotateStatusFile.py b/LogRotateStatusFile.py
deleted file mode 100755 (executable)
index 5dc4b3c..0000000
+++ /dev/null
@@ -1,575 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-# $Id$
-# $URL$
-
-'''
-@author: Frank Brehm
-@contact: frank@brehm-online.com
-@license: GPL3
-@copyright: (c) 2010-2011 by Frank Brehm, Berlin
-@version: 0.0.2
-@summary: module for operations with the logrotate state file
-'''
-
-import re
-import sys
-import os
-import os.path
-import gettext
-import logging
-import pprint
-
-from datetime import tzinfo, timedelta, datetime, date, time
-
-from LogRotateCommon import split_parts 
-
-revision = '$Revision$'
-revision = re.sub( r'\$', '', revision )
-revision = re.sub( r'Revision: ', r'r', revision )
-revision = re.sub( r'\s*$', '', revision )
-
-__author__    = 'Frank Brehm'
-__copyright__ = '(C) 2011 by Frank Brehm, Berlin'
-__contact__    = 'frank@brehm-online.com'
-__version__    = '0.1.0 ' + revision
-__license__    = 'GPL3'
-
-#========================================================================
-
-class LogrotateStatusFileError(Exception):
-    '''
-    Base class for exceptions in this module.
-    '''
-
-#========================================================================
-
-ZERO = timedelta(0)
-
-class UTC(tzinfo):
-    """UTC"""
-
-    def utcoffset(self, dt):
-        return ZERO
-
-    def tzname(self, dt):
-        return "UTC"
-
-    def dst(self, dt):
-        return ZERO
-
-utc = UTC()
-
-
-#========================================================================
-
-class LogrotateStatusFile(object):
-    '''
-    Class for operations with the logrotate state file
-
-    @author: Frank Brehm
-    @contact: frank@brehm-online.com
-    '''
-
-    #-------------------------------------------------------
-    def __init__( self, file_name,
-                        local_dir  = None,
-                        verbose    = 0,
-                        test_mode  = False,
-    ):
-        '''
-        Constructor.
-
-        @param file_name: the file name of the status file
-        @type file_name:  str
-        @param verbose:   verbosity (debug) level
-        @type verbose:    int
-        @param test_mode: test mode - no write actions are made
-        @type test_mode:  bool
-        @param local_dir: The directory, where the i18n-files (*.mo)
-                          are located. If None, then system default
-                          (/usr/share/locale) is used.
-        @type local_dir:  str or None
-
-        @return: None
-        '''
-
-        self.local_dir = local_dir
-        '''
-        @ivar: The directory, where the i18n-files (*.mo) are located.
-        @type: str or None
-        '''
-
-        self.t = gettext.translation(
-            'LogRotateStatusFile',
-            local_dir,
-            fallback = True
-        )
-        '''
-        @ivar: a gettext translation object
-        @type: gettext.translation
-        '''
-
-        _ = self.t.lgettext
-
-        self.verbose = verbose
-        '''
-        @ivar: verbosity level (0 - 9)
-        @type: int
-        '''
-
-        self.file_name = file_name
-        '''
-        @ivar: the initial file name of the status file to use
-        @type: str
-        '''
-
-        self.file_name_is_absolute = False
-        '''
-        @ivar: flag, that shows, that the file name is now an absolute path
-        @type: bool
-        '''
-
-        self.fd = None
-        '''
-        @ivar: the file object of the opened status file, or None, if not opened
-        @type: file or None
-        '''
-
-        self.was_read = False
-        '''
-        @ivar: flag, whether the status file was read
-        @type: bool
-        '''
-
-        self.status_version = None
-        '''
-        @ivar: the version of the status file (2 or 3)
-        @type: int or None
-        '''
-
-        self.test_mode = test_mode
-        '''
-        @ivar: test mode - no write actions are made
-        @type: bool
-        '''
-
-        self.has_changed = False
-        '''
-        @ivar: flag, whether something has changed and needs to be written
-        @type: bool
-        '''
-
-        self.logger = logging.getLogger('pylogrotate.status_file')
-        '''
-        @ivar: logger object
-        @type: logging.getLogger
-        '''
-
-        self.file_state = {}
-        '''
-        @ivar: the last rotation date of every particular log file
-               keys are the asolute filenames (without globbing)
-               and the values are datetime objects of the last rotation
-               referencing to UTC
-               If no rotation was made, value is datetime.min().
-        @type: dict
-        '''
-
-        # Initial read and check for permissions
-        self.read(must_exists = False)
-        self._check_permissions()
-
-    #-------------------------------------------------------
-    def __del__(self):
-        '''
-        Destructor.
-        Enforce saving of status file, if something has changed.
-        '''
-
-        _ = self.t.lgettext
-        msg = _("Status file object will destroyed.")
-        self.logger.debug(msg)
-
-        if self.has_changed:
-            self.write()
-
-    #-------------------------------------------------------
-    def as_dict(self):
-        '''
-        Transforms the elements of the object into a dict
-
-        @return: structure as dict
-        @rtype:  dict
-        '''
-
-        res = {}
-        res['local_dir']             = self.local_dir
-        res['t']                     = self.t
-        res['verbose']               = self.verbose
-        res['file_name']             = self.file_name
-        res['file_name_is_absolute'] = self.file_name_is_absolute
-        res['fd']                    = self.fd
-        res['status_version']        = self.status_version
-        res['test_mode']             = self.test_mode
-        res['logger']                = self.logger
-        res['file_state']            = self.file_state
-        res['was_read']              = self.was_read
-        res['has_changed']           = self.has_changed
-
-        return res
-
-    #------------------------------------------------------------
-    def get_rotation_date(self, logfile):
-        '''
-        Gives back the date of the last rotation of a particular logfile.
-        If this logfile is not found in the state file, datetime.min() is given back.
-
-        @param logfile: the logfile to query
-        @type logfile:  str
-
-        @return: date of last rotation of this logfile
-        @rtype:  datetime
-        '''
-
-        if not self.was_read:
-            self.read(must_exists = False)
-
-        rotate_date = datetime.min.replace(tzinfo=utc)
-        if logfile in self.file_state:
-            rotate_date = self.file_state[logfile]
-
-        return rotate_date
-
-    #------------------------------------------------------------
-    def set_rotation_date(self, logfile, rotate_date = None):
-        '''
-        Sets the rotation date of the given logfile.
-        If the rotation date is not given, datetime.utcnow() is used.
-
-        @param logfile:     the logfile to set
-        @type logfile:      str
-        @param rotate_date: the rotation date of this logfile
-        @type rotate_date:  datetime or None
-
-        @return: date of rotation of this logfile (relative to UTC)
-        @rtype:  datetime
-        '''
-
-        date_utc = datetime.utcnow()
-        if rotate_date:
-            date_utc = rotate_date.astimezone(utc)
-
-        _ = self.t.lgettext
-        msg = _("Setting rotation date of '%(file)s' to '%(date)s' ...") \
-                % {'file': logfile, 'date': date_utc.isoformat(' ') }
-        self.logger.debug(msg)
-
-        #self.read(must_exists = False)
-        self.file_state[logfile] = date_utc
-        self.has_changed = True
-
-        #self.write()
-
-        return date_utc
-
-    #------------------------------------------------------------
-    def write(self):
-        '''
-        Writes the content of self.file_state in the state file.
-
-        @return:    success of writing
-        @rtype:     bool
-        '''
-
-        _ = self.t.lgettext
-
-        # setting a failing version of the status file
-        if not self.status_version:
-            self.status_version = 3
-
-        max_length = 1
-
-        # Retrieving the maximum length of the logfiles for version 3
-        if self.status_version == 3:
-            for logfile in self.file_state:
-                if len(logfile) > max_length:
-                    max_length = len(logfile)
-            max_length += 2
-
-        fd = None
-        # Big try block for ensure closing open status file
-        try:
-
-            msg = _("Open status file '%s' for writing ...") % (self.file_name)
-            self.logger.debug(msg)
-
-            # open status file for writing
-            if not self.test_mode:
-                try:
-                    fd = open(self.file_name, 'w')
-                except IOError, e:
-                    msg = _("Could not open status file '%s' for write: ") % (self.file_name) + str(e)
-                    raise LogrotateStatusFileError(msg)
-
-            # write logrotate version line
-            line = 'Logrotate State -- Version 3'
-            if self.status_version == 2:
-                line = 'logrotate state -- version 2'
-            if self.verbose > 2:
-                msg = _("Writing version line '%s'.") % (line)
-                self.logger.debug(msg)
-            line += '\n'
-            if fd:
-                fd.write(line)
-
-            # iterate over logfiles in self.file_state
-            for logfile in sorted(self.file_state.keys(), lambda x,y: cmp(x.lower(), y.lower())):
-                rotate_date = self.file_state[logfile]
-                date_str = "%d-%d-%d" % (rotate_date.year, rotate_date.month, rotate_date.day)
-                if self.status_version == 3:
-                    date_str = ( "%d-%02d-%02d_%02d:%02d:%02d" %
-                                (rotate_date.year, rotate_date.month, rotate_date.day,
-                                 rotate_date.hour, rotate_date.minute, rotate_date.second))
-                line = '%-*s %s' % (max_length, ('"' + logfile + '"'), date_str)
-                if self.verbose > 2:
-                    msg = _("Writing line '%s'.") % (line)
-                    self.logger.debug(msg)
-                if fd:
-                    fd.write(line + "\n")
-
-        finally:
-            if fd:
-                fd.close()
-                fd = None
-
-        self.has_changed = False
-        return True
-
-    #------------------------------------------------------------
-    def __str__(self):
-        '''
-        Typecasting function for translating object structure
-        into a string
-
-        @return: structure as string
-        @rtype:  str
-        '''
-
-        pp = pprint.PrettyPrinter(indent=4)
-        return pp.pformat(self.as_dict())
-
-    #------------------------------------------------------------
-    def _check_permissions(self):
-        '''
-        Checks the permissions of the state file and/or his parent directory.
-        Throws a LogrotateStatusFileError on a error.
-
-        @return:    success of check
-        @rtype:     bool
-        '''
-
-        _ = self.t.lgettext
-        msg = _("Checking permissions of status file '%s' ...") % (self.file_name)
-        self.logger.debug(msg)
-
-        if os.path.exists(self.file_name):
-            # Check for write access to the status file
-            if os.access(self.file_name, os.W_OK):
-                msg = _("Access to status file '%s' is OK.") % (self.file_name)
-                self.logger.debug(msg)
-                return True
-            else:
-                msg = _("No write access to status file '%s'.") % (self.file_name)
-                if self.test_mode:
-                    self.logger.error(msg)
-                else:
-                    raise LogrotateStatusFileError(msg)
-                return False
-
-        parent_dir = os.path.dirname(self.file_name)
-        msg = _("Checking permissions of parent directory '%s' ...") % (parent_dir)
-        self.logger.debug(msg)
-
-        # Check for existence of parent dir
-        if not os.path.exists(parent_dir):
-            msg = _("Directory '%s' doesn't exists.") % (parent_dir)
-            if self.test_mode:
-                self.logger.error(msg)
-            else:
-                raise LogrotateStatusFileError(msg)
-            return False
-
-        # Check whether parent dir is a directory
-        if not os.path.isdir(parent_dir):
-            msg = _("Parent directory '%(dir)s' of status file '%(file)s' is not a directory.") \
-                    % {'dir': parent_dir, 'file': self.file_name }
-            if self.test_mode:
-                self.logger.error(msg)
-            else:
-                raise LogrotateStatusFileError(msg)
-            return False
-
-        # Check for write access to parent dir
-        if not os.access(parent_dir, os.W_OK):
-            msg = _("No write access to parent directory '%(dir)s' of status file '%(file)s'.") \
-                    % {'dir': parent_dir, 'file': self.file_name }
-            if self.test_mode:
-                self.logger.error(msg)
-            else:
-                raise LogrotateStatusFileError(msg)
-            return False
-
-        msg = _("Permissions to parent directory '%s' are OK.") % (parent_dir)
-        self.logger.debug(msg)
-        return True
-
-    #-------------------------------------------------------
-    def read(self, must_exists = True):
-        '''
-        Reads the status file and put the results in the dict self.file_state.
-        Puts back the absolute path of the status file in self.file_name on success.
-
-        Throws a LogrotateStatusFileError on a error.
-
-        @param must_exists: throws an exception, if true and the status file
-                            doesn't exists
-        @type must_exists:  bool
-
-        @return:    success of reading
-        @rtype:     bool
-        '''
-
-        self.file_state = {}
-        _ = self.t.lgettext
-
-        # Check for existence of status file
-        if not os.path.exists(self.file_name):
-            msg = _("Status file '%s' doesn't exists.") % (self.file_name)
-            if must_exists:
-                raise LogrotateStatusFileError(msg)
-            else:
-                self.logger.info(msg)
-            return False
-
-        # makes the name of the status file an absolute path
-        if not self.file_name_is_absolute:
-            self.file_name = os.path.abspath(self.file_name)
-            self.file_name_is_absolute = True
-            if self.verbose > 2:
-                msg = _("Absolute path of status file is now '%s'.") % (self.file_name)
-                self.logger.debug(msg)
-
-        # Checks, that the status file is a regular file
-        if not os.path.isfile(self.file_name):
-            msg = _("Status file '%s' is not a regular file.") % (self.file_name)
-            raise LogrotateStatusFileError(msg)
-            return False
-
-        msg = _("Reading status file '%s' ...") % (self.file_name)
-        self.logger.debug(msg)
-
-        fd = None
-        try:
-            fd = open(self.file_name, 'Ur')
-        except IOError, e:
-            msg = _("Could not read status file '%s': ") % (self.file_name) + str(e)
-            raise LogrotateStatusFileError(msg)
-        self.fd = fd
-
-        try:
-            # Reading the lines of the status file
-            i = 0
-            for line in fd:
-                i += 1
-                line = line.strip()
-                if self.verbose > 4:
-                    msg = _("Performing status file line '%(line)s' (file: '%(file)s', row: %(row)d)") \
-                            % {'line': line, 'file': self.file_name, 'row': i, }
-                    self.logger.debug(msg)
-
-                # check for file heading
-                if i == 1:
-                    match = re.search(r'^logrotate\s+state\s+-+\s+version\s+([23])$', line, re.IGNORECASE)
-                    if match:
-                        # Correct file header
-                        self.status_version = int(match.group(1))
-                        if self.verbose > 1:
-                            msg = _("Idendified version of status file: %d") % (self.status_version)
-                            self.logger.debug(msg)
-                        continue
-                    else:
-                        # Wrong header
-                        msg = _("Incompatible version of status file '%(file)s': %(header)s") \
-                                % { 'file': self.file_name, 'header': line }
-                        fd.close()
-                        raise LogrotateStatusFileError(msg)
-
-                if line == '':
-                    continue
-
-                parts = split_parts(line)
-                logfile = parts[0]
-                rdate   = parts[1]
-                if self.verbose > 2:
-                    msg = _("Found logfile '%(file)s' with rotation date '%(date)s'.") \
-                            % { 'file': logfile, 'date': rdate }
-                    self.logger.debug(msg)
-
-                if logfile and rdate:
-                    match = re.search(r'\s*(\d+)[_\-](\d+)[_\-](\d+)(?:[\s\-_]+(\d+)[_\-:](\d+)[_\-:](\d+))?', rdate)
-                    if not match:
-                        msg = _("Could not determine date format: '%(date)s' (file: '%(file)s', row: %(row)d)") \
-                                % {'date': rdate, 'file': logfile, 'row': i, }
-                        self.logger.warning(msg)
-                        continue
-                    d = {
-                        'Y': int(match.group(1)),
-                        'm': int(match.group(2)),
-                        'd': int(match.group(3)),
-                        'H': 0,
-                        'M': 0,
-                        'S': 0,
-                    }
-                    if match.group(4) is not None:
-                        d['H'] = int(match.group(4))
-                    if match.group(5) is not None:
-                        d['M'] = int(match.group(5))
-                    if match.group(6) is not None:
-                        d['S'] = int(match.group(6))
-
-                    dt = None
-                    try:
-                        dt = datetime(d['Y'], d['m'], d['d'], d['H'], d['M'], d['S'], tzinfo = utc)
-                    except ValueError, e:
-                        msg = _("Invalid date: '%(date)s' (file: '%(file)s', row: %(row)d)") \
-                                % {'date': rdate, 'file': logfile, 'row': i, }
-                        self.logger.warning(msg)
-                        continue
-
-                    self.file_state[logfile] = dt
-
-                else:
-
-                    msg = _("Neither a logfile nor a date found in line '%(line)s' (file: '%(file)s', row: %(row)d)") \
-                            % {'line': line, 'file': logfile, 'row': i, }
-                    self.logger.warning(msg)
-
-        finally:
-            fd.close
-
-        self.fd = None
-        self.was_read = True
-
-        return True
-
-#========================================================================
-
-if __name__ == "__main__":
-    pass
-
-
-#========================================================================
-
-# vim: fileencoding=utf-8 filetype=python ts=4 expandtab
index c252ec07fa6e01967eb90d9874ac818d70e7e48f..2c2f96202c254d7a1653e4221cefbe71a3b932a9 100755 (executable)
@@ -9,7 +9,7 @@
 @contact: frank@brehm-online.com
 @license: GPL3
 @copyright: (c) 2010-2011 by Frank Brehm, Berlin
-@version: 0.2.2
+@version: 0.5.3
 @summary: rotates and compress system logs
 '''
 
@@ -21,13 +21,13 @@ import os
 import os.path
 from datetime import datetime
 
-from LogRotateGetopts import LogrotateOptParser
-from LogRotateGetopts import LogrotateOptParserError
+from LogRotate.Getopts import LogrotateOptParser
+from LogRotate.Getopts import LogrotateOptParserError
 
-from LogRotateHandler import LogrotateHandler
-from LogRotateHandler import LogrotateHandlerError
+from LogRotate.Handler import LogrotateHandler
+from LogRotate.Handler import LogrotateHandlerError
 
-import LogRotateCommon
+import LogRotate.Common
 
 revision = '$Revision$'
 revision = re.sub( r'\$', '', revision )
@@ -36,7 +36,7 @@ revision = re.sub( r'Revision: ', r'r', revision )
 __author__    = 'Frank Brehm'
 __copyright__ = '(C) 2011 by Frank Brehm, Berlin'
 __contact__    = 'frank@brehm-online.com'
-__version__    = '0.5.2 ' + revision
+__version__    = '0.5.3 ' + revision
 __license__    = 'GPL3'
 
 
@@ -53,7 +53,7 @@ def main():
         local_dir = None
     #print "Locale-Dir: %s" % ( local_dir )
 
-    LogRotateCommon.locale_dir = local_dir
+    LogRotate.Common.locale_dir = local_dir
 
     t = gettext.translation('pylogrotate', local_dir, fallback=True)
     _ = t.lgettext