'''
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,socket
from match import match_any

__all__=['report','report_recipients']

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

# MESSAGE REPORT TEMPLATE
REPORT_MSG_TEMPLATE='''\
From: $FROM
To: $TO
Subject: ALERT, $VIRNAME FROM $SENTBY_IP!

                             VIRUS FOUND!
---------------------------------------------------------------------
STATUS: $STATUS
QUARANTINED AS: $QNAME
---------------------------------------------------------------------
SMTP COMMUNICATION:
$SMTP_COMM
---------------------------------------------------------------------
SCANNER: $SCANNER_NAME
$SCANNER_OUTPUT
---------------------------------------------------------------------
HEADER OF MESSAGE:
$MSG_HEADER
'''

class report(match_any):
  '''
  Report any message to admin, user or anybody.

  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
    $SENTBY_IP          sender's IP
    $SENTBY_NAME        sender's hostname
    $SENTBY_HELO        sender's HELO/EHLO string
  
  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>',...]
           You can use variables mentioned above in this array, but only
           $SENDER can be used logically.
         msg is an message template, you can use report.MSG_TMPL
         cond_scanner is a scanner, which defines, when report may be sent

  Examples:
    - send report to admin@localhost:
        report(['<admin@localhost>'], report.MSG_TMPL, ... )
    - send report to email sender:
        report(['$FROM'], report.MSG_TMPL, ... )
  '''
  # 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 ifscan(self,scanner):
      self.IFSCAN=scanner
      return self
  def ifscan_main(self,buffer,args={}):
      try:
        level,detected,virlist=self.IFSCAN.scanbuffer(buffer,args)
      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 scanbuffer(self,buffer,args={}):
      level,detected,virlist=match_any.scanbuffer(self,buffer,args)
      if globals.scan_only:
        return level,detected,virlist
      if not self.ifscan_main(buffer,args):
        return level,detected,virlist
      if not is_infected(level,detected):
        return level,detected,virlist
      if self.RECIPIENTS:
        sender=mail.getsender()
        repl_vars={
          'FROM':		self.SENDER,
          'VIRNAME':		detected,
          'SMTP_COMM':		mail.noop_connect_from()+mail.comm.rstrip(),
          'STATUS':		globals.action(level),
          'QNAME':		globals.QFNAME,
          'SCANNER_OUTPUT':	"".join(virlist),
          'SCANNER_NAME':	globals.found_by.name,
          'MSG_HEADER':		mail.data[:mail.bodypos].rstrip(),
          'MSG_BODY':		mail.data[mail.bodypos:],
          'RANDOM':		randomchars(10),
          'SENDER':             mail.sender,
          'RECIPIENTS':         ','.join(mail.recip),
          'VERSION':		SG_VER_REL,
          'SENTBY_IP':		sender['ADDR'],
          'SENTBY_NAME':	sender['NAME'],
          'SENTBY_HELO':	sender['HELO']
        }
        recipients=[replace_tmpl(x,repl_vars) for x in self.RECIPIENTS]
        repl_vars['TO']=',\r\n\t'.join(recipients)
        msg=replace_tmpl(self.MSG, repl_vars)
        try:
          smtpc().sendmail(self.SENDER, recipients, msg)
        except SmtpcError,(ses,es):
          debug.echo(1,"report(): AdminReport: ", ses)
      return level,detected,virlist

class report_recipients(report):
  '''
  Report any message to email recipients.

  This module can be used to report an message to mail recipients.
  For message description see report() scanner.
 
  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
  '''
  # Templates
  MSG_TMPL=REPORT_MSG_TEMPLATE
  # scanner
  name='report_recipients()'
  def __init__(self,msg,*scanners):
      self.MSG=msg
      self.SENDER='<vscan@'+socket.gethostname()+'>'
      match_any.__init__(self,scanners)
  def scanbuffer(self,buffer,args={}):
      level,detected,virlist=match_any.scanbuffer(self,buffer,args)
      if globals.scan_only:
        return level,detected,virlist
      if not self.ifscan_main(buffer,args):
        return level,detected,virlist
      if not is_infected(level,detected):
        return level,detected,virlist
      sender=mail.getsender()
      repl_vars={
          'FROM':		self.SENDER,
          'VIRNAME':		detected,
          'SMTP_COMM':		mail.noop_connect_from()+mail.comm.rstrip(),
          'STATUS':		globals.action(level),
          'QNAME':		globals.QFNAME,
          'SCANNER_OUTPUT':	"".join(virlist),
          'SCANNER_NAME':	globals.found_by.name,
          'MSG_HEADER':		mail.data[:mail.bodypos].rstrip(),
          'MSG_BODY':		mail.data[mail.bodypos:],
          'RANDOM':		randomchars(10),
          'SENDER':             mail.sender,
          'RECIPIENTS':         ','.join(mail.recip),
          'TO':			',\r\n\t'.join(mail.recip),
          'VERSION':		SG_VER_REL,
          'SENTBY_IP':		sender['ADDR'],
          'SENTBY_NAME':	sender['NAME'],
          'SENTBY_HELO':	sender['HELO']
      }
      msg=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
