'''
libclamav, version 1.2.0
 
(c) 2003-2007 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.
'''

cdef extern from "const_types.h":
     ctypedef char constchar

cdef extern from "clamav.h":
     enum:
            CL_CLEAN
            CL_VIRUS
            CL_SUCCESS
            CL_BREAK
            CL_EMAXREC
            CL_EMAXSIZE
            CL_EMAXFILES
            CL_ERAR
            CL_EZIP
            CL_EGZIP
            CL_EBZIP
            CL_EOLE2
            CL_EMSCOMP
            CL_EMSCAB
            CL_EACCES
            CL_ENULLARG
            CL_ETMPFILE
            CL_EFSYNC
            CL_EMEM
            CL_EOPEN
            CL_EMALFDB
            CL_EPATSHORT
            CL_ETMPDIR
            CL_ECVD
            CL_ECVDEXTR
            CL_EMD5
            CL_EDSIG
            CL_EIO
            CL_EFORMAT
            CL_ESUPPORT
            CL_ELOCKDB
            # NodalCore
            CL_ENCINIT
            CL_ENCLOAD
            CL_ENCIO
            # db options
            CL_DB_NCORE
            CL_DB_PHISHING
            CL_DB_ACONLY
            CL_DB_PHISHING_URLS
            CL_DB_STDOPT
            # scan options
            CL_SCAN_RAW
            CL_SCAN_ARCHIVE
            CL_SCAN_MAIL
            CL_SCAN_OLE2
            CL_SCAN_BLOCKENCRYPTED
            CL_SCAN_HTML
            CL_SCAN_PE
            CL_SCAN_BLOCKBROKEN
            CL_SCAN_MAILURL
            CL_SCAN_BLOCKMAX
            CL_SCAN_ALGORITHMIC
            CL_SCAN_PHISHING_DOMAINLIST
            CL_SCAN_PHISHING_BLOCKSSL
            CL_SCAN_PHISHING_BLOCKCLOAK
            CL_SCAN_ELF
            CL_SCAN_STDOPT
     struct cl_limits:
            int maxreclevel
            int maxfiles
            int maxmailrec
            int maxratio
            short archivememlim
            long int maxfilesize
     struct cl_stat:
            char *dir
            int no
            char *stattab
     struct cl_engine
     int cl_load(char *path, cl_engine **engine, unsigned int *signo, unsigned int options)
     char *cl_retdbdir()
     int cl_build(cl_engine *engine)
     cl_engine *cl_dup(cl_engine *engine)
     void cl_free(cl_engine *engine)
     int cl_statinidir(char *dirname, cl_stat *dbstat)
     int cl_statchkdir(cl_stat *dbstat)
     int cl_statfree(cl_stat *dbstat)
     int cl_scandesc(int desc, constchar **virname, unsigned long int *scanned,
                     cl_engine *engine, cl_limits *limits, int options)
     int cl_scanfile(char *filename, constchar **virname, unsigned long int *scanned,
                     cl_engine *engine, cl_limits *limits, int options)
     int cl_retflevel()
     char *cl_retver()
     cl_settempdir(constchar *dir, short leavetemps)
     char *cl_strerror(int clerror)

cdef extern from "string.h":
     cdef void *memset(void *s, int c, int n)

class ClamAVError(Exception):
      '''ClamAVError'''
      pass

CLEAN=CL_CLEAN
VIRUS=CL_VIRUS
SUCCESS=CL_SUCCESS
BREAK=CL_BREAK

EMAXREC=CL_EMAXREC
EMAXSIZE=CL_EMAXSIZE
EMAXFILES=CL_EMAXFILES
ERAR=CL_ERAR
EZIP=CL_EZIP
EGZIP=CL_EGZIP
EBZIP=CL_EBZIP
EOLE2=CL_EOLE2
EMSCOMP=CL_EMSCOMP
EMSCAB=CL_EMSCAB
EACCES=CL_EACCES
ENULLARG=CL_ENULLARG
ETMPFILE=CL_ETMPFILE
EFSYNC=CL_EFSYNC
EMEM=CL_EMEM
EOPEN=CL_EOPEN
EMALFDB=CL_EMALFDB
EPATSHORT=CL_EPATSHORT
ETMPDIR=CL_ETMPDIR
ECVD=CL_ECVD
ECVDEXTR=CL_ECVDEXTR
EMD5=CL_EMD5
EDSIG=CL_EDSIG
EIO=CL_EIO
EFORMAT=CL_EFORMAT
ESUPPORT=CL_ESUPPORT
ELOCKDB=CL_ELOCKDB

ENCINIT=CL_ENCINIT
ENCLOAD=CL_ENCLOAD
ENCIO=CL_ENCIO

DB_NCORE=CL_DB_NCORE
DB_PHISHING=CL_DB_PHISHING
DB_ACONLY=CL_DB_ACONLY
DB_PHISHING_URLS=CL_DB_PHISHING_URLS
DB_STDOPT=CL_DB_STDOPT

SCAN_RAW=CL_SCAN_RAW
SCAN_ARCHIVE=CL_SCAN_ARCHIVE
SCAN_MAIL=CL_SCAN_MAIL
SCAN_OLE2=CL_SCAN_OLE2
SCAN_BLOCKENCRYPTED=CL_SCAN_BLOCKENCRYPTED
SCAN_HTML=CL_SCAN_HTML
SCAN_PE=CL_SCAN_PE
SCAN_BLOCKBROKEN=CL_SCAN_BLOCKBROKEN
SCAN_MAILURL=CL_SCAN_MAILURL
SCAN_BLOCKMAX=CL_SCAN_BLOCKMAX
SCAN_ALGORITHMIC=CL_SCAN_ALGORITHMIC
SCAN_PHISHING_DOMAINLIST=CL_SCAN_PHISHING_DOMAINLIST
SCAN_PHISHING_BLOCKSSL=CL_SCAN_PHISHING_BLOCKSSL
SCAN_PHISHING_BLOCKCLOAK=CL_SCAN_PHISHING_BLOCKCLOAK
SCAN_ELF=CL_SCAN_ELF
SCAN_STDOPT=CL_SCAN_STDOPT

SCAN_DEFAULT = CL_SCAN_STDOPT

# compatibility aliases
CL_RAW=CL_SCAN_RAW
CL_ARCHIVE=CL_SCAN_ARCHIVE
CL_MAIL=CL_SCAN_MAIL
CL_OLE2=CL_SCAN_OLE2
CL_ENCRYPTED=None
CL_DEFAULT=CL_SCAN_STDOPT

cdef class clamav:
  cdef cl_engine *engine
  cdef readonly unsigned int virnum
  cdef char *virname
  cdef readonly status
  cdef unsigned long int size
  cdef cl_limits limits
  cdef cl_stat dbstat
  cdef object dirname
  def __init__(self,dirname=None):
      self.virnum=0
      self.engine=NULL
      self.statinidir(dirname)
      self.load(dirname)
      memset(&self.limits, 0, sizeof(self.limits)) # zero limits
      self.limits.maxreclevel=8
      self.limits.maxmailrec=64
      self.limits.maxfilesize=10485760 # 10 MB
      self.limits.maxfiles=1024
      self.limits.maxratio=250
      self.limits.archivememlim=1
  def __del__(self):
      self.statfree()
      self.free()
  def retver(self):
      return cl_retver()
  def free(self):
      cl_free(self.engine)
      self.engine=NULL
      self.virnum=0
  def load(self,dirname=None,options=CL_DB_STDOPT):
      if dirname:
        self.status=cl_load(dirname, &self.engine,
                            &self.virnum, options)
      else:
        self.status=cl_load(cl_retdbdir(), &self.engine,
                            &self.virnum, options)
      self.checkstatus()
      if self.virnum==0:
        raise ClamAVError,'No signatures loaded!'
      self.status=cl_build(self.engine)
      self.checkstatus()
  def checkstatus(self,ret=None):
      if self.status in [CL_CLEAN,CL_VIRUS]:
        return ret
      else:
        raise ClamAVError,self.strerror()
  def scandesc(self,desc,options=SCAN_DEFAULT):
      self.size,self.virname=0,''
      self.status=cl_scandesc(desc,<constchar**>&self.virname,&self.size,
                              self.engine,&self.limits,options)
      if self.virname==NULL:
        self.virname = ""
      return self.checkstatus(self.virname)
  def scanfile(self,filename,options=SCAN_DEFAULT):
      self.size,self.virname=0,''
      self.status=cl_scanfile(filename,<constchar**>&self.virname,&self.size,
                              self.engine,&self.limits,options)
      if self.virname==NULL:
        self.virname = ""
      return self.checkstatus(self.virname)
  def statinidir(self,dirname=None):
      self.dirname=dirname
      memset(&self.dbstat, 0, sizeof(self.dbstat))
      if dirname:
        self.status=cl_statinidir(dirname, &self.dbstat)
      else:
        self.status=cl_statinidir(cl_retdbdir(), &self.dbstat)
      self.checkstatus()
  def statchkdir(self):
      self.status=cl_statchkdir(&self.dbstat)
      return self.checkstatus(self.status)
  def statfree(self):
      self.status=cl_statfree(&self.dbstat)
      self.checkstatus()
  def strerror(self,clerror=None):
      if clerror==None:
        return cl_strerror(self.status)
      else:
        return cl_strerror(clerror)
  def reload(self,dirname=None):
      if dirname:
        self.dirname=dirname
      if self.statchkdir():
        self.statfree()
        self.free()
        self.statinidir(self.dirname)
        self.load(self.dirname)
        return 1
      else:
        return 0
  def setlimits(self,args={}):
      for key,value in args.items():
        if key=='maxreclevel':
          self.limits.maxreclevel=value
        elif key=='maxmailrec':
          self.limits.maxmailrec=value
        elif key=='maxfiles':
          self.limits.maxfiles=value
        elif key=='maxratio':
          self.limits.maxratio=value
        elif key=='archivememlim':
          self.limits.archivememlim=value
        elif key=='maxfilesize':
          self.limits.maxfilesize=value
