scripts/mailman/Handlers/SpamAssassin_crans.py

107 lines
4.4 KiB
Python

# Copyright (C) 2002-2003 by James Henstridge <james@daa.com.au>
#
# 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.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, US
"""Perform spam detection with SpamAssassin.
Messages are passed to a spamd (SpamAssassin) daemon for spam checking.
Depending on the score returned, messages may be rejected or held for
moderation.
"""
import string
import spamd
from Mailman import mm_cfg
from Mailman import Errors
from Mailman.Logging.Syslog import syslog
from Mailman.Handlers import Hold
from Mailman.Handlers.Moderate import matches_p
SPAMD_HOST = getattr(mm_cfg, 'SPAMASSASSIN_HOST', '')
DISCARD_SCORE = getattr(mm_cfg, 'SPAMASSASSIN_DISCARD_SCORE', 10)
HOLD_SCORE = getattr(mm_cfg, 'SPAMASSASSIN_HOLD_SCORE', 5)
MEMBER_BONUS = getattr(mm_cfg, 'SPAMASSASSIN_MEMBER_BONUS', 2)
class SpamAssassinDiscard(Errors.DiscardMessage):
'''The message was scored above the discard threshold'''
reason = 'SpamAssassin identified this message as spam'
rejection = 'Your message has been discarded as spam'
class SpamAssassinHold(Errors.HoldMessage):
'''The message was scored above the hold threshold'''
def __init__(self, score=-1, symbols=''):
Errors.HoldMessage.__init__(self)
self.reason = 'SpamAssassin identified this message as possible ' \
'spam (score %g)' % score
self.rejection = 'Your message was held for moderation because ' \
'SpamAssassin gave the message a score of %g ' \
'for the following reasons:\n\n%s' % \
(score, symbols)
def check_message(mlist, message):
'''Check a message against a SpamAssassin spamd process.
Returns a tuple of the form (score, symbols)'''
try:
connection = spamd.SpamdConnection(SPAMD_HOST)
# identify as the mailing list, to allow storing per-list
# AWL and bayes databases.
connection.addheader('User', mlist.internal_name())
res = connection.check(spamd.SYMBOLS, message)
score = connection.getspamstatus()[1]
symbols = connection.response_message.replace(',', ', ')
return score, symbols
except spamd.error, ex:
syslog('error', 'spamd: %s' % str(ex))
return -1, ''
def process(mlist, msg, msgdata):
if msgdata.get('approved'):
return
#Recuperation des parametres SpamAssassin de la liste
#Score modifie minimum pour que le message soit rejete
DISCARD_SCORE_LIST = getattr(mlist, 'SPAMASSASSIN_DISCARD_SCORE', DISCARD_SCORE)
#Score modifie minimum pour que le message soit mis en attente de moderation
HOLD_SCORE_LIST = getattr(mlist, 'SPAMASSASSIN_HOLD_SCORE', HOLD_SCORE)
#Modificateur du score de Spamassassin selon le nombre d'expediteur du message abonne a la liste.
MEMBER_BONUS_LIST = getattr(mlist, 'SPAMASSASSIN_MEMBER_BONUS', MEMBER_BONUS)
score, symbols = check_message(mlist, str(msg))
with open('/tmp/samailman', 'a') as fichier:
fichier.write("%s/%s/%s : %s\n"%(score, HOLD_SCORE_LIST, DISCARD_SCORE_LIST, mlist.internal_name()))
msg['X-Spam-Score'] = str(score)
if MEMBER_BONUS_LIST != 0:
for sender in msg.get_senders():
if mlist.isMember(sender) or \
matches_p(sender, mlist.accept_these_nonmembers, mlist.internal_name()):
score -= MEMBER_BONUS_LIST
break
if score > DISCARD_SCORE_LIST:
listname = mlist.real_name
sender = msg.get_sender()
syslog('vette', '%s post from %s discarded: '
'SpamAssassin score was %g (discard threshold is %g)'
% (listname, sender, score, DISCARD_SCORE_LIST))
raise SpamAssassinDiscard
elif score > HOLD_SCORE_LIST:
Hold.hold_for_approval(mlist, msg, msgdata,
SpamAssassinHold(score, symbols))