Mini Shell

Direktori : /opt/spamassassin/bin/
Upload File :
Current File : //opt/spamassassin/bin/sa_info

#!/opt/imh-python/bin/python
import sys
import re
import json
import argparse

if sys.stdout.isatty():
    ANSI = {'bold_red': '', 'reset': '', 'bold': ''}
else:
    ANSI = {'bold_red': '', 'reset': '', 'bold': ''}

def load_sa_db():
    """Load SpamAssassin test info"""
    with open('/opt/spamassassin/etc/spam_tests.json', 'r') as db:
        sa_data = json.loads(db.read())

    try:
        with open('/etc/mail/spamassassin/imh_custom.cf') as custom_rules:
            for line in custom_rules.read().splitlines():
                if line.startswith('score'):
                    try:
                        discard, id, score = line.split()
                    except ValueError:
                        continue

                    try:
                        sa_data[id.strip()]['score'] = score.strip()
                    except KeyError:
                        sa_data[id.strip()] = {'score': score.strip()}
    except IOError:
        pass

    return sa_data

def lookup_sa_id(id):
    """Prints info about a specific SpamAssassin test"""
    nodata = "No Data"
    print "{bold}{0}{reset}".format(id, bold=ANSI['bold'], reset=ANSI['reset'])
    if id in SA_DATA:
        entry = SA_DATA[id]
        print "{:>15}".format("Area Scanned:"),
        try:
            print entry['area']
        except KeyError:
            print nodata

        print "{:>15}".format("Description:"),
        try:
            print entry['desc']
        except KeyError:
            print nodata

        print "{:>15}".format("Score (Max):"),
        try:
            print entry['score']
        except KeyError:
            print nodata

        if 'wiki' in entry and entry['wiki']:
            print "{:>15} {}".format("More Info:",
            "%s/%s" % (SA_DATA['wiki_url'], id))
    else:
        print "\n".join(("  No entry found in the database for %s." % id,
              "  Information may be available from the SpamAssassin wiki",
              "{:>15} {}".format("More Info:",
                  "%s/%s" % (SA_DATA['wiki_url'], id))))
    print


def summarize_rejected_mail(address):
    addr = re.compile('(?i)F=<%s>' % address)
    new_record = re.compile('^\d{4}-\d{2}-\d{2}')
    messages = []
    num = 0
    append = False
    cur_record = None
    hr = "".join(['=' for i in xrange(80)])


    with open('/var/log/exim_rejectlog') as rejectlog:
        for line in rejectlog:
            if addr.search(line):
                messages.append({'header': [line]})
                append = True
                cur_record = messages[num]
                num += 1
                continue
            if new_record.search(line):
                append = False
                continue
            elif append and cur_record:
                cur_record['header'].append(line)
                if line.startswith('I '):
                    msg_id = line.split()[-1]
                    cur_record['id'] = msg_id

    if not messages:
        return

    with open('/var/log/maillog') as maillog:
        for line in maillog:
            if not 'user=cpaneleximscanner' in line:
                continue
            for message in messages:
                try:
                    if 'mid=%s' % message['id'] in line:
                        log_chunks = line.split()
                        message['score'] = log_chunks[8]
                        message['flags'] = log_chunks[10]
                        break
                except Exception:
                    pass
    
    if messages:
        print "%s= Summary of unique rejected outbound mail for %s =%s" % \
            (ANSI['bold'], address, ANSI['reset'])
        count = 1   
        for message in messages:
            if 'flags' in message:
                print "%s== Headers from message %d ==%s\n" % \
                    (ANSI['bold'], count, ANSI['reset'])
                print "".join(message['header'])
                print "%s== Summary of SpamAssassin tests ==%s" % \
                    (ANSI['bold'], ANSI['reset'])
                print "   Spam Score: %s\n" % message['score']
                
                for flag in message['flags'].split(','):
                    lookup_sa_id(flag)
                count += 1
                print hr, "\n"

if __name__ == '__main__':
    global SA_DATA
    SA_DATA = load_sa_db()
    parser = argparse.ArgumentParser(
        description='Aids in understanding why a message has been flagged as spam',
        epilog='To look up multiple rule IDs or email addresses, separate each with a space.')
    optgroup = parser.add_mutually_exclusive_group(required=True)
    optgroup.add_argument('-r', '--rule', metavar='RULE', type=str, nargs='+',
        help='SpamAssassin rule ID(s) to look up')
    optgroup.add_argument('-a', '--address', metavar='EMAIL', type=str, nargs='+',
        dest='address', help='search for bounces from a specific email address or addresses')
    options = parser.parse_args()
    
    if options.address:
        for address in options.address:
            summarize_rejected_mail(address)
    elif options.rule:
        for rule in options.rule:
            lookup_sa_id(rule.upper())


Zerion Mini Shell 1.0