#!/usr/bin/python
'''
ICAP module, version 0.2
 
(c) 2003 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 socket,re

__all__=['savse']

class icap:
  def __init__(self,host,port,path='AVSCAN?action=SCAN'):
      self.s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
      socket_settimeout(self.s,120)
      self.s.connect((host,port))
      self.f=self.s.makefile('rw',0)
      self.server=host+":"+str(port)
      self.path=path
  def check(self,stream,filename):
      level,virname,response=0.0,'',[]
      # send ICAP request
      self.s.sendall("RESPMOD icap://"+self.server+"/"+self.path+" ICAP/1.0\r\n")
      self.s.sendall("Host: "+self.server+"\r\n")
      self.s.sendall("Allow: 204\r\n")
      req="GET http://sagator.salstar.sk/"+filename+" HTTP/1.1\r\n\r\n"
      hdr="HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n"
      self.s.sendall("Encapsulated: req-hdr=0, res-hdr=%d, res-body=%d\r\n\r\n"
        % (len(req),len(req+hdr)))
      debug.echo(7,'icap(): ',req,hdr)
      self.s.sendall(req)
      self.s.sendall(hdr)
      # send data stream
      #i,l,s=0,len(stream),0xFF
      #while True:
      #  if (i+s)>=l:
      #    self.s.sendall("%X\r\n" % (len(stream[i:])))
      #    self.s.sendall(stream[i:])
      #    self.s.sendall("\r\n\r\n0\r\n\r\n")
      #    break
      #  else:
      #    self.s.sendall("%X\r\n" % s)
      #    self.s.sendall(stream[i:i+s])
      #    self.s.sendall("\r\n\r\n")
      #  i+=s
      self.s.sendall("%X\r\n" % (len(stream)))
      self.s.sendall(stream)
      self.s.sendall("\r\n\r\n0\r\n\r\n")
      # read protocol status
      ics=self.f.readline()
      debug.echo(7,"savse():",ics)
      try:
        icc=re.search("^ICAP/[0-9.]* ([0-9]{3}) ",ics).group(1)
      except:
        icc='000'
      if icc=='204':
        pass # it's clean
      elif (icc[:2]=='20'):
        # returned OK
        while 1:
          line=self.f.readline()
          if not line:
            break
          debug.echo(7,"savse():",line)
          reg=re.search("^X-Infection-Found: Type=([0-9]*); Resolution=([0-9]*); Threat=([^;]*);",line)
          if reg:
            if (reg.group(1)=='0'):
              virname+=reg.group(3)
              level+=1.0
              debug.echo(5,"savse(): found:",virname)
          else:
            reg1=re.search("^X-Violations-Found:",line)
            if reg1:
              while 1:
                line=self.f.readline()
                if not line:
                  break
                if (line[0]==' ') or (line[0]=='\t'):
                  response.append(line)
                else:
                  break
      else:
        raise 'e',ics
      return level,virname,response
  def close(self):
      self.s.shutdown(2)

class savse(ascanner):
  '''
  savse() realscanner - symantec antivirus scan engine scanner
  
  Usage: savse('host',port)
  
  Example: parsemail(savse('localhost',1344))
  
  Comments:
    You need to configure ICAP protocol on port 1344 (or another)
    to use this scanner properly.
    These options are suggested in symcscan.cfg:
      BindAddress=127.0.0.1
      Port=1344
      Protocol=ICAP
      ExtensionPolicy=0
      ICAPActionPolicy=SCAN
      ICAPResponse=1
  '''
  name='savse()'
  def __init__(self,host,port=1344):
      self.host=host
      self.port=port
  def scanstream(self,stream):
      c=icap(self.host,self.port)
      level,r,response=c.check(stream,self.filename)
      c.close()
      return level,r,response
