'''
Report interscanners for sagator, version 0.6.2

(c) 2003-2004 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.
    
'''

from avlib import *
import re,string,socket
from match import match_any

__all__=['report','report_recipients']

#####################################################################
### REPORT class

# MESSAGE REPORT TEMPLATE
REPORT_MSG_TEMPLATE='''\
From: $FROM1
To: $TO1
Subject: ALERT, $VIRNAME1 FOUND!

                             VIRUS FOUND!
---------------------------------------------------------------------
STATUS: $STATUS1
QUARANTINED AS: $QNAME1
---------------------------------------------------------------------
SMTP COMMUNICATION:
$SMTP_COMM1
---------------------------------------------------------------------
HEADER OF MESSAGE:
$MSG_HEADER1
---------------------------------------------------------------------
SCANNER: $SCANNER_NAME1
$SCANNER_OUTPUT1
'''

class report(match_any):
  '''
  report() interscanner - report any message to admin, user or anybody
  
  usage: report(recipients, msg, scanners)
  or:    report(...).sender('<email@of.sender.dom>')
  or:    report(...).ifscan(cond_scanner)

  where: recipients is an array of recipients,
           like: ['<r1@dom>','<r2@dom>',...]
         msg is an message template, you can use report.MSG_TMPL
         cond_scanner is a scanner, which defines, when report may be sent

  This module can be used to report an message to administrator
  or to any user.

  You can use following variables in report messages:
    $FROM		report sender
    $VIRNAME		detected virus name
    $SMTP_COMM		SMTP communication
    $STATUS		status of this message (REJECTED, DROPPED, ...)
    $QNAME		filename in quarantine
    $SCANNER_OUTPUT	returned scanner output
    $SCANNER_NAME	name of the scanner
    $MSG_HEADER		virus/spam header
    $MSG_BODY		virus/spam body (without header)
    $RANDOM		10 random characters (useable to generate a boundary)
    $SENDER		virus/spam sender
    $RECIPIETNS		virus/spam recipients joined by comma (',')
    $TO			report recipeints
    $VERSION            sagator's version
  '''
  # Templates
  MSG_TMPL=REPORT_MSG_TEMPLATE
  # scanner
  name='report()'
  def __init__(self,recipients,msg,*scanners):
      self.MSG=msg
      self.RECIPIENTS=recipients
      self.SENDER='<vscan@'+socket.gethostname()+'>'
      match_any.__init__(self,scanners)
  def sender(self,email):
      self.SENDER=email
      return self
  def replace_tmpl(self,msg,vars):
      idx={}
      for v in vars.keys():
        try:
          idx[msg.index('$'+v)]=v
        except ValueError:
          pass
        for c in '0123456789':
          try:
            idx[msg.index('$'+v+c)]=v+c
          except ValueError:
            pass
      keys=idx.keys() # replace it from last to first
      keys.sort()
      keys.reverse()
      for k in keys:
        idxk=idx[k]
        if idxk[-1] in '0123456789':
          idxk=idxk[:-1]
        msg=msg[:k]+vars[idxk]+msg[k+len(idx[k])+1:]
      return msg
  def ifscan(self,scanner):
      self.IFSCAN=scanner
      return self
  def ifscan_main(self,stream):
      try:
        level,detected,virlist=self.IFSCAN.scanstream(stream)
      except (NameError,AttributeError):
        return True
      if is_infected(level,detected):
        debug.echo(6,'report(): condition: True (%f,%s)' % (level,detected))
        return True
      else:
        debug.echo(6,'report(): condition: False (%f,%s)' % (level,detected))
        return False
  def scanstream(self,stream):
      level,detected,virlist=match_any.scanstream(self,stream)
      if globals.scan_only:
        return level,detected,virlist
      if not self.ifscan_main(stream):
        return level,detected,virlist
      if not is_infected(level,detected):
        return level,detected,virlist
      if self.RECIPIENTS:
        repl_vars={
          'FROM':		self.SENDER,
          'VIRNAME':		detected,
          'SMTP_COMM':		mail.addr+mail.comm.rstrip(),
          'STATUS':		globals.action(level),
          'QNAME':		globals.QFNAME,
          'SCANNER_OUTPUT':	string.join(virlist,""),
          'SCANNER_NAME':	globals.found_by.name,
          'MSG_HEADER':		mail.header.rstrip(),
          'MSG_BODY':		mail.data[mail.bodypos:],
          'RANDOM':		randomchars(10),
          'SENDER':             mail.sender,
          'RECIPIENTS':         string.join(mail.recip,','),
          'TO':			string.join(self.RECIPIENTS,',\r\n\t'),
          'VERSION':		SG_VER_REL
        }
        msg=self.replace_tmpl(self.MSG,repl_vars)
        try:
          smtpc().sendmail(self.SENDER,self.RECIPIENTS,msg)
        except SmtpcError,(ses,es):
          debug.echo(1,"report(): AdminReport: ",ses)
      return level,detected,virlist

class report_recipients(report):
  '''
  report_recipients() interscanner - report any message to mail recipients
 
  usage: report_recipients(msg, scanners)
  or:    report_recipients(...).sender('<email@of.sender.dom>')
  or:    report(...).ifscan(cond_scanner)

  where: msg is an message template, you can use report.MSG_TMPL
          scanners are scanners which are used
         cond_scanner is a scanner, which defines, when report may be sent

  This module can be used to report an message to mail recipients.
  For message description see report() scanner.
  '''
  # Templates
  MSG_TMPL=REPORT_MSG_TEMPLATE
  # scanner
  name='report()'
  def __init__(self,msg,*scanners):
      self.MSG=msg
      self.SENDER='<vscan@'+socket.gethostname()+'>'
      match_any.__init__(self,scanners)
  def scanstream(self,stream):
      level,detected,virlist=match_any.scanstream(self,stream)
      if globals.scan_only:
        return level,detected,virlist
      if not self.ifscan_main(stream):
        return level,detected,virlist
      if not is_infected(level,detected):
        return level,detected,virlist
      repl_vars={
          'FROM':		self.SENDER,
          'VIRNAME':		detected,
          'SMTP_COMM':		mail.addr+mail.comm.rstrip(),
          'STATUS':		globals.action(level),
          'QNAME':		globals.QFNAME,
          'SCANNER_OUTPUT':	string.join(virlist,""),
          'SCANNER_NAME':	globals.found_by.name,
          'MSG_HEADER':		mail.header.rstrip(),
          'MSG_BODY':		mail.data[mail.bodypos:],
          'RANDOM':		randomchars(10),
          'SENDER':             mail.sender,
          'RECIPIENTS':         string.join(mail.recip,','),
          'TO':			string.join(mail.recip,',\r\n\t'),
          'VERSION':		SG_VER_REL
      }
      msg=self.replace_tmpl(self.MSG,repl_vars)
      try:
        smtpc().sendmail(self.SENDER,mail.recip,msg)
      except SmtpcError,(ses,es):
        debug.echo(1,"report(): UserReportRecipients: ",ses)
      return level,detected,virlist
