'''
dspam module, version 0.1

(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,string
import pwd,grp,os

try:
  import pydspam

  DSR_ISSPAM = pydspam.DSR_ISSPAM
  DSR_ISINNOCENT = pydspam.DSR_ISINNOCENT

  DSS_ERROR = pydspam.DSS_ERROR
  DSS_CORPUS = pydspam.DSS_CORPUS
  DSS_INOCULATION = pydspam.DSS_INOCULATION

  DST_TEFT = pydspam.DST_TEFT
  DST_TOE = pydspam.DST_TOE
  DST_TUM = pydspam.DST_TUM
  DST_NOTRAIN = pydspam.DST_NOTRAIN
  
  DSF_CHAINED = pydspam.DSF_CHAINED
  DSF_SIGNATURE = pydspam.DSF_SIGNATURE
  DSF_COPYBACK = pydspam.DSF_COPYBACK
  DSF_NOISE = pydspam.DSF_NOISE
  DSF_WHITELIST = pydspam.DSF_WHITELIST
  DSF_MERGED = pydspam.DSF_MERGED

  class dspam(ascanner):
    '''
    dspam realscanner - uses dspam library
    
    Usage: dspam(home,user,group,classify,source,train,flags)
    
    Where: home is dspam home dir ('/var/dspam')
           user is dspam user (user running sagator's process)
           group is dspam group (group running sagator's process)
           train is training mode (TEFT)
           flagh are dspam flags (DSF_SIGNATURE)

    For detailed description see DSPAM documentation.

    Examples:
      basic usage:
        dspam()
      training emails badly assigned as spams:
        drop('',dspam(classify=DSR_ISSPAM,source=DSS_ERROR,train=DST_TOE))
      training emails badly assinged as inoocent:
        drop('',dspam(classify=DSR_ISINNOCENT,source=DSS_ERROR,train=DST_TOE))
    '''
    name='dspam()'
    OP=pydspam.DSM_PROCESS
    FLAGS=pydspam.DSF_CHAINED|pydspam.DSF_NOISE
    CLASSIFICATION=pydspam.DSR_NONE
    SOURCE=pydspam.DSS_NONE
    TRAINING_MODE=DST_TEFT
    def __init__(self,home='/var/dspam',user=None,group=None,classify=None,source=None,train=None,flags=pydspam.DSF_SIGNATURE):
        self.FLAGS |= flags
        if not user:
          user=pwd.getpwuid(os.getuid())[0]
        if not group:
          group=grp.getgrgid(os.getgid())[0]
        self.DSPAM=pydspam.dspam(home,op=self.OP,flags=self.FLAGS,user=user,group=group)
        if classify:
          self.CLASSIFICATION=classify
        if self.CLASSIFICATION!=pydspam.DSR_NONE:
          self.DSPAM.classification(self.CLASSIFICATION)
        if source:
          self.SOURCE=source
        if self.SOURCE!=pydspam.DSS_NONE:
          self.DSPAM.source(self.SOURCE)
        if train:
          self.TRAINING_MODE=train
          self.DSPAM.training_mode(train)
    def __del__(self):
        self.DSPAM.__del__()
    def param(self,p):
        if p=='--dspam-source-corpus':
          self.SOURCE=pydspam.DSS_CORPUS
          self.DSPAM.source(self.SOURCE)
        elif p=='--dspam-source-error':
          self.SOURCE=pydspam.DSS_ERROR
          self.DSPAM.source(self.SOURCE)
        elif p=='--dspam-source-innoculation':
          self.SOURCE=pydspam.DSS_INOCULATION
          self.DSPAM.source(self.SOURCE)
        elif p=='--dspam-classify-spam':
          self.CLASSIFICATION=pydspam.DSR_ISSPAM
          self.DSPAM.classification(self.CLASSIFICATION)
        elif p=='--dspam-classify-innocent':
          self.CLASSIFICATION=pydspam.DSR_ISINNOCENT
          self.DSPAM.classification(self.CLASSIFICATION)
        elif p=='--dspam-training-teft':
          self.TRAINING_MODE=pydspam.DST_TEFT
          self.DSPAM.training_mode(pydspam.DST_TEFT)
        elif p=='--dspam-training-toe':
          self.TRAINING_MODE=pydspam.DST_TOE
          self.DSPAM.training_mode(pydspam.DST_TOE)
        elif p=='--dspam-training-tum':
          self.TRAINING_MODE=pydspam.DST_TUM
          self.DSPAM.training_mode(pydspam.DST_TUM)
        elif p=='--dspam-training-notrain':
          self.TRAINING_MODE=pydspam.DST_NOTRAIN
          self.DSPAM.training_mode(pydspam.DST_NOTRAIN)
        else:
          return 0
        return 1
    def scanstream(self,stream):
        debug.echo(4,self.name+": settings: DST=%s, DSS=%s, DSR=%s" % \
          (pydspam.DST[self.TRAINING_MODE],
           pydspam.DSS[self.SOURCE],
           pydspam.DSR[self.CLASSIFICATION]))
        sig=''
        if self.SOURCE in [pydspam.DSS_ERROR,pydspam.DSS_INOCULATION]:
          # try to get signature from meesage header
          reg_sig=re.compile('^X-DSPAM-Signature: *([a-z0-9]+)\r?$',re.I|re.M).search(stream)
          if reg_sig:
            sig=reg_sig.group(1)
            self.DSPAM.get_signature(sig)
          else:
            debug.echo(1,self.name+": ERROR: Can't get signature ID!")
        # process through dspam
        r,p,c=self.DSPAM.process(stream)
        # save signature, if it is made
        if self.CLASSIFICATION==pydspam.DSR_NONE:
          sig=self.DSPAM.save_signature()
        # simulate dspam output
        ret=['result='+str(r),'probability='+str(p),'confidence='+str(c),
             "sig='%s'" % str(sig)]
        debug.echo(4,self.name+": "+', '.join(ret))
        if self.CLASSIFICATION==pydspam.DSR_ISINNOCENT:
          return 0.0,'',['innocence classified']
        if self.CLASSIFICATION==pydspam.DSR_ISSPAM:
          return 1.0,'SPAM',['spam classified']
        mail.addheader('X-DSPAM-Confidence',str(c))
        mail.addheader('X-DSPAM-Probability',str(p))
        if r==pydspam.DSR_ISSPAM:
          mail.addheader('X-DSPAM-Result','Spam')
          mail.addheader('X-DSPAM-Signature',sig)
          return 1.0+p,'SPAM',ret
        elif r==pydspam.DSR_ISINNOCENT:
          mail.addheader('X-DSPAM-Result','Innocent')
          return p,'',ret
        debug.echo(3,self.name+": WARNING: Unknown return from dspam!")
        return 0.0,'',[]
  class dspam_classify(dspam):
    '''
    dspam_classify() realscanner
    
    This scanner can be used to classify messages as spams/hams.
    For parameters see dspam() scanner documentation.
    
    Example:
      configure SCANNERS=[ dspam_classify(source=DSS_CORPUS,flags=0) ]
      and you can run sgscan to learn messages from a box:
      Training ham (clean messages):
        sgscan --dspam-training-teft --dspam-source-corpus \
               --dspam-classify-innocent MAILBOX
      Training spam:
        sgscan --dspam-training-teft --dspam-source-corpus \
               --dspam-classify-spam MAILBOX
    '''
    name='dspam_classify()'
    #OP=pydspam.DSM_CLASSIFY
    #FLAGS=pydspam.DSF_CHAINED|pydspam.DSF_NOISE
    CLASSIFICATION=pydspam.DSR_ISSPAM
    SOURCE=pydspam.DSS_CORPUS
except ImportError,es:
  class dspam(ascanner):
    '''
    This method is undefined, because pydspam module is not found.
    Please recompile sagator, if you really need it.
    '''
    name='dspam()'
    errorstring="Importing of pydspammodule failed!"
    def __init__(self,*arg1,**arg2):
        pass
    def scanstream(self,stream):
        debug.echo(1,self.name+": scanstream(): "+self.errorstring," [",es,"]")
        raise ScannerError,self.errorstring
    def scanfile(self,files,dirname=''):
        debug.echo(1,self.name+": scanstream(): "+self.errorstring," [",es,"]")
        raise ScannerError,self.errorstring
  class dspam_classify(dspam):
    name='dspam_classify()'
