#!/usr/bin/env python

# Copyright 2005,2006 Petru Paler (petru@paler.net)
#
# 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  USA

import logging, logging.handlers

logger = logging.getLogger("siqpolicyd")
hdlr = logging.handlers.SysLogHandler(address="/dev/log", facility=logging.handlers.SysLogHandler.LOG_MAIL)
formatter = logging.Formatter('%(filename)s: %(levelname)s: %(message)s')
hdlr.setFormatter(formatter)
logger.addHandler(hdlr)
#logger.setLevel(logging.DEBUG)
logger.setLevel(logging.INFO)

import sys
import traceback

from siq import siq_query, SIQD_UNKNOWN, SIQD_TEMPFAIL

threshold = 50
siq_server = "db.outboundindex.net"

def parse_request(f):
    logger.debug("parsing access policy request")
    attrs = {}
    while 1:
        l = f.readline()
        if len(l) <= 1:
            break
        l = l[:-1]
        name, value = l.split('=', 1)
        attrs[name] = value
    logger.debug("parsing complete")
    return attrs

def siq_report(client_address, domain, helo_name):
    logger.debug("siq_report called for %s, %s, %s" % (client_address, domain, helo_name))
    try:
        r = siq_query(domain, client_address, server=siq_server, helodom=helo_name)
        logger.debug("SIQ server reply: %r" % str(r))
        score, text, s1, s2, s3, hl, ml = r
        if score == SIQD_TEMPFAIL:
            decision = "TEMPFAIL"
        elif score == SIQD_UNKNOWN:
            decision = "UNKNOWN"
        elif score > threshold and score <= 100:
            decision = "YES"
        elif score <= threshold and score >= 0:
            decision = "NO"
    except:
        decision = "UNKNOWN"
        hl = ml = score = 0
        text = sys.exc_info()[1]
    return "pass=%s ip=%s dn=%s hl=%d ml=%d siq=%s score=%d text='%s'" % (decision, client_address, domain, hl, ml, siq_server, score, text)

def main():
    logger.debug("starting")
    attrs = parse_request(sys.stdin)
    try:
        mbox, domain = attrs['sender'].split('@')
    except:
        mbox = domain = None
    if attrs['protocol_state'] == 'RCPT' and domain:
        report = siq_report(attrs['client_address'], domain, attrs['helo_name'])
        logger.debug("got SIQ report: %s" % report)
        sys.stdout.write("action=prepend X-milter-siq-Report: %s\n\n" % report)
    else:
        logger.debug("not doing anything")
        sys.stdout.write("action=dunno\n\n")
    logger.debug("exiting")

def format_exc(limit=None):
    """From Python 2.4's traceback.py, for backwards compatibility"""
    try:
        etype, value, tb = sys.exc_info()
        return ''.join(traceback.format_exception(etype, value, tb, limit))
    finally:
        etype = value = tb = None

if __name__ == '__main__':
    try:
        main()
    except:
        logger.critical("Unhandled exception: %s" % format_exc())

