#!/usr/bin/python

'''
sagator's summary reporter
(c) 2005-2008 Jan ONDREJ (SAL) <ondrejj(at)salstar.sk>
 
  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.
'''

__pychecker__ = 'unusednames=_ \
                 blacklist=StringIO \
                 maxreturns=20 maxlines=300 \
                 no-local no-argsused no-stringiter no-abstract no-isliteral \
                 no-stdlib no-callinit no-badexcept'

import sys, re, socket, gzip, urllib
from StringIO import StringIO
from avlib import *
from aglib import find_service, getopt
from email.parser import Parser

# load config
try:
  from etc import *
except ImportError,import_es:
  if str(import_es)[-6:]=="etc":
    print "ERROR! Config file not found! Exiting now."
    sys.exit(1)
  else:
    raise

if __name__ == '__main__':
  # parse command line
  debug.set_level(DEBUG_LEVEL)
  safe.ROOT_PATH=CHROOT
  TEST_MODE=False
  SAVE_MARK=True
  SCAN_BACKWARD=1
  try:
    opts,files=getopt.gnu_getopt(sys.argv[1:],'',
      ['help','debug=','test','nomark','age='])
  except getopt.GetoptError,(msg,opt):
    print "Error:",msg
    sys.exit(1)
  for key,value in opts:
    if key=='--help':
      print "SAGATOR's reporter script"
      print "(c) Jan ONDREJ (SAL) <ondrejj(at)salstar.sk>"
      print "Licensed under GNU GPL."
      print ""
      print "Parameters: --help         this help"
      print "            --debug=X      set debug level to X"
      print "            --test         do not send reports, only show info"
      print "            --nomark       do not save report marker into config"
      print "            --age=X        scan older logs X logs back"
      sys.exit(0)
    elif key=='--debug':
      debug.set_level(int(value))
    elif key=='--test':
      print "Running in test mode."
      TEST_MODE=True
      SAVE_MARK=False
    elif key=='--nomark':
      SAVE_MARK=False
    elif key=='--age':
      SCAN_BACKWARD=int(value)

  # parse log
  users={}
  reg_marker=re.compile('^ *[0-9]+: REPORT-MARKER')
  reg_report=re.compile(
    "^ *[0-9]+: REPORT: datetime='(.+)', level='(.+)', virname='(.+)', status='(.+)', scanner='(.*)', size='([0-9]+)', sender='(.+)', recipients='(.+)', sentby_ip='(.*)', qname='(.*)'$"
  )
  LOGFILES=[LOGFILE+x for x in \
    ['.%d.gz' % i for i in range(SCAN_BACKWARD,0,-1)]+
    ['.%d' % i for i in range(SCAN_BACKWARD,0,-1)]+
    ['']]
  REPORTER_SERVICE=find_service(SRV, 'reporter()')
  if 'body' not in REPORTER_SERVICE.init_args.keys():
    # BODY not updated, try to check if webq() service is configured
    try:
      find_service(SRV, 'webq()')
      # webq() service configured, update BODY
      REPORTER_SERVICE.BODY += \
        '     Review:     %s/action.kid?qname=%%(QQNAME)s\n' \
        % REPORTER_SERVICE.WEBQ_URL
    except TypeError:
      pass # webq() service not defined
  # precompile groups
  groups=[]
  for key, value in REPORTER_SERVICE.GROUPS:
    groups.append([re.compile(key, re.I), value])
  for fname in LOGFILES:
    try:
      if fname[-3:]=='.gz':
        f=gzip.open(fname)
      else:
        f=open(fname)
    except IOError,err:
      if err[0]==2:
        continue
      else:
        raise
    while True:
      l=f.readline()
      if not l: break
      r=reg_report.search(l)
      if r:
        groups_done=[]
        for user in r.group(8).split(','):
          # find group
          group=user
          for key,value in groups:
            if key.search(user):
              group=value
              break
          if not group:
            continue # enpty groups are ignored
          elif group in groups_done:
            continue # already processed
          else:
            groups_done.append(group)
          # check include and exclude on user (not on group)
          if REPORTER_SERVICE.INCLUDE_FX(user):
            if not REPORTER_SERVICE.EXCLUDE_FX(user):
              try:
                users[group].append(r.groups())
              except KeyError:
                users[group]=[r.groups()]
      elif reg_marker.search(l):
        users={}
    f.close()

  # save marker
  if len(users)>0:
    if SAVE_MARK:
      debug.set_logfile(LOGFILE)
    debug.echo(1,"REPORT-MARKER: sending reports to %d user(s)" % len(users))

  # send reports
  smtp.SMTP_SERVER=SMTP_SERVER
  for recipient,data in users.items():
    report_vars={
      'REPORT_RECIPIENT': recipient,
      'BEGIN': users[recipient][0][0],
      'END': users[recipient][-1][0],
      'VERSION': SG_VER_REL,
      'SHORTVER': version.VERSION,
      'SGUSER': USER,
      'RANDOM': randomchars(10),
      'MYHOSTNAME': socket.gethostname(),
      'MYDOMAIN': '.'.join(socket.gethostname().split('.')[1:]),
      'MSG_COUNT': len(data)
    }
    report_text=StringIO()
    report_text.write(replace_tmpl(REPORTER_SERVICE.BEGIN,report_vars))
    counter=0
    for item in data:
      counter+=1
      # read quarantine file for headers
      headers = {}
      qf = open(safe.fn(item[9]), 'r')
      while True:
        line = qf.readline()
        if not line:
          break
        if line[:4]=='DATA':
          # message header found
          headers = Parser().parse(qf, True) # headersonly
          break
      # create variables
      report_text.write(replace_tmpl(REPORTER_SERVICE.BODY,
        {
          'DATETIME': item[0],
          'LEVEL': item[1],
          'VIRNAME': item[2],
          'STATUS': item[3],
          'SCANNER_NAME': item[4],
          'SIZE': item[5],
          'SENDER': item[6],
          'RECIPIENTS': item[7],
          'SUBJECT': headers.get('Subject'),
          'SENTBY_IP': item[8],
          'QNAME': item[9],
          'QQNAME': urllib.quote_plus(item[9]),
          'COUNTER': "%3d" % counter
        }
      ))
    report_text.write(replace_tmpl(REPORTER_SERVICE.END,report_vars))
    try:
      if TEST_MODE:
        debug.echo(7,report_text.getvalue())
      else:
        smtpc().sendmail("<%s@%s>" % (USER,socket.gethostname()),
                         ["<%s>" % recipient],
                         report_text.getvalue())
      debug.echo(4,"reporter: Sent report to: %s [%d msgs]" % (recipient,len(data)))
    except:
      debug.echo(1,"reporter: Error sending report to: %s [%d msgs]" % (recipient,len(data)))
      debug.traceback(3,"reporter: ")
