#!/usr/bin/python
# -*- coding: UTF-8 -*-
# vim:tabstop=8 shiftwidth=4 softtabstop=4 smarttab expandtab
# Copyright 2007 Thomas de Klein <Thomas@deKlein.de>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
"""%prog [filename] [options]
    sxgreplog searches through the Scalix audit log (or, at a basic level in
    any block-oriented logfile) and presents all matching blocks.

    Provide the filename of the logfile, or data on STDIN.
    
    You can limit the shown blocks to those with a certain operation indicator.
    According to HP OpenMail Technical Reference Guide pp. 81 valid operation
    indicators are:
    bulletin, delivery, desk-in, desk-out, dirsync-in, dirsync-out, notes-in, 
    notes-out, omscan, request, routing, search, sms-in, sms-out,
    subsystem-start, subsystem-stop, unix-in, unix-out, usersignoff,
    usersignon, x400-in, x400-out, 
    In Scalix usersign* is replaced by user-signon and user-signoff
"""

__version__ = "1.2"
__author__ = "Thomas de Klein <Thomas@deKlein.de>"

import sys, commands, re, logging
from optparse import OptionParser

## setup commandline switches
parser = OptionParser(usage = __doc__)

parser.add_option("-v", "--verbose", \
    action="store_true", \
    dest="verbose", \
    default=False, \
    help="be verbose")
parser.add_option("-d", "--debug", \
    action="store_true", \
    dest="debug", \
    default=False, \
    help="show debug info")
parser.add_option("-L", "--line", \
    action="store_true", \
    dest="linemode", \
    default=False,\
    help="output each block as a single line")
parser.add_option("-e", "--expression", \
    action="store", \
    dest="expression", \
    nargs=1, \
    default="",\
    help="Expression to search for")
parser.add_option("-o", "--opindicator", \
    action="store", \
    dest="opind", \
    nargs=1, \
    default=False,\
    help="Only show blocks with this operation indicator")
parser.add_option("-c", "--casesensitive", \
    action="store_true", \
    dest="casesensitive", \
    default=False,\
    help="Be casesensitive")

# get cmdline options
(options, args) = parser.parse_args()
if options.verbose:
    logging.basicConfig(level=logging.INFO)
elif options.debug:
    logging.basicConfig(level=logging.DEBUG)
else:
    logging.basicConfig(level=logging.WARNING)

#######################################
def searchBlock(block):
    """search a given block
    """
    # Shall we search only blocks with a specific operation indicator and is 
    # this one of them?
    if (config["opind"]) and (block[0] != config["opind"]):
        # yes, we shall, and no, its not
        return False
    for line in block:
        if (not config["casesensitive"]) and (re.search(config["expression"], line, re.IGNORECASE)):
            return True    
        elif (config["casesensitive"]) and (re.search(config["expression"], line)):
            return True
    return False

#######################################
def printBlock(block):
    """print the given block either as a block, or as a single line
    """
    if config["linemode"]: 
        print "; ".join(block)
    else:
        for line in block:
            print line
        print
    return

########### Main

config = {}
config["sxbindir"] = "/opt/scalix/bin"
config["omshowu"] = "%s/omshowu" %(config["sxbindir"], )
config["omshowmn"] = "%s/omshowu" %(config["sxbindir"], )
config["linemode"] = options.linemode
config["expression"] = options.expression
config["casesensitive"] = options.casesensitive
config["seperator"] = "\n"
config["valid_opind"] = ( "bulletin", "delivery", "desk-in", "desk-out", \
    "dirsync-in", "dirsync-out", "notes-in", "notes-out", "omscan", \
    "request", "routing", "search", "sms-in", "sms-out", "subsystem-start", \
    "subsystem-stop", "unix-in", "unix-out", "usersignoff", "usersignon", \
    "user-signoff", "user-signon", "x400-in", "x400-out")
config["opind"] = options.opind
# if the provided operation indicator ist not a valid one, say so and quit
if (not options.opind == False) and (not options.opind in config["valid_opind"]):
    logging.critical("'%s' is not a valid operation indicator" % (options.opind,))
    sys.exit(1)
    
# Do we read from a file or from STDIN?
try:
    INPUTfile = open(args[0],"r")
except IndexError: # no filename provided
    logging.info("No inputfile, using input from STDIN")
    INPUTfile = sys.stdin
except IOError: # filename provided, but not readable
    logging.critical("Could not open file %s" %(args[0],))
    sys.exit(1)

block = []

# read the input blockwise and search it
for line in INPUTfile:
    if line == config["seperator"]:
        if searchBlock(block):
            printBlock(block)
        block = []
        continue
    # get rid of the linebreak at the end while appending it.
    block.append(line.strip())
