⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sb_bnfilter.py

📁 用python实现的邮件过滤器
💻 PY
字号:
#! /usr/bin/env python# This script has a similar interface and purpose to sb_filter, but avoids# re-initialising spambayes for consecutive requests using a short-lived# server process. This is intended to give the performance advantages of# sb_xmlrpcserver, without the administrative complications.## The strategy is:## * while we cant connect to a unix domain socket#     * fork a separate process that runs in the background#     * in the child process:#         * exec sb_bnserver. it listens on that same unix domain socket.#     * in the parent process:#         * sleep a little, to give the child chance to start up# * write the filtering/training command line options to the socket# * copy the content of stdin to the socket# * meanwhile..... sb_bnserver gets to work on that data in the same manner#   as sb_filter. it writes its response back through that socket# * read a line from the socket containing a success/failure code# * read a line from the socket containing a byte count# * copy the remainder of the content of the socket to stdout or stderr,#   depending on whether it reported success or failure.# * if the number of bytes read from the socket is different to the byte#   count, exit with an error# * if the reported exit code is non-zero, exit with an error## sb_bnfilter will only terminate with a zero exit code if everything# is ok. If it terminates with a non-zero exit code then its stdout should# be ignored.## sb_bnserver will close itself and remove its socket after a period of# inactivity to ensure it does not use up resources indefinitely.## Author: Toby Dickenson#"""Usage: %(program)s [options]Where:    -h        show usage and exit   *   -f        filter (default if no processing options are given)*   -g        [EXPERIMENTAL] (re)train as a good (ham) message*   -s        [EXPERIMENTAL] (re)train as a bad (spam) message*   -t        [EXPERIMENTAL] filter and train based on the result -- you must        make sure to untrain all mistakes later.  Not recommended.*   -G        [EXPERIMENTAL] untrain ham (only use if you've already trained        this message)*   -S        [EXPERIMENTAL] untrain spam (only use if you've already trained        this message)            -k FILE        Unix domain socket used to communicate with a short-lived server        process. Default is ~/.sbbnsock-<hostname>    These options will not take effect when connecting to a preloaded server:    -p FILE        use pickle FILE as the persistent store.  loads data from this file        if it exists, and saves data to this file at the end.    -d FILE        use DBM store FILE as the persistent store.    -o section:option:value        set [section, option] in the options database to value    -a seconds        timeout in seconds between requests before this server terminates    -A number        terminate this server after this many requests"""import sys, getopt, socket, errno, os, timedef usage(code, msg=''):    """Print usage message and sys.exit(code)."""    if msg:        print >> sys.stderr, msg        print >> sys.stderr    print >> sys.stderr, __doc__    sys.exit(code)        def main():    try:        opts, args = getopt.getopt(sys.argv[1:], 'hfgstGSd:p:o:a:A:k:')    except getopt.error, msg:        usage(2, msg)    # build the default socket filename from environment variables    filename = os.path.expanduser('~/.sbbnsock-'+socket.gethostname())        action_options = []    server_options = []    for opt, arg in opts:        if opt == '-h':            usage(0)        elif opt in ('-f', '-g', '-s', '-t', '-G', '-S'):            action_options.append(opt)        elif opt in ('-d', '-p', '-o', '-a', '-A'):            server_options.append(opt)            server_options.append(arg)        elif opt == '-k':            filename = arg    if args:        usage(2)            server_options.append(filename)    s = make_socket(server_options, filename)            # We have a connection to the existing shared server    w_file = s.makefile('w')    r_file = s.makefile('r')    # pass our command line on the first line into the socket    w_file.write(' '.join(action_options)+'\n')    # copy entire contents of stdin into the socket    while 1:        b = sys.stdin.read(1024*64)        if not b:            break        w_file.write(b)    w_file.flush()    w_file.close()    s.shutdown(1)    # expect to get back a line containing the size of the rest of the response    error = int(r_file.readline())    expected_size = int(r_file.readline())    if error:        output = sys.stderr    else:        output = sys.stdout    total_size = 0    # copy entire contents of socket into stdout or stderr    while 1:        b = r_file.read(1024*64)        if not b:            break        output.write(b)        total_size += len(b)    output.flush()    # If we didnt receive the right amount then something has gone wrong.    # exit now, and procmail will ignore everything we have sent to stdout.    # Note that this policy is different to the xmlrpc client, which    # tries to handle errors internally by constructing a stdout that is    # the same as stdin was.    if total_size != expected_size:        print >> sys.stderr, 'size mismatch %d != %d' % (total_size,                                                         expected_size)        sys.exit(3)    if error:        sys.exit(error)def make_socket(server_options, file):    refused_count = 0    no_server_count = 0    while 1:        try:            s = socket.socket(socket.AF_UNIX,socket.SOCK_STREAM)            s.connect(file)        except socket.error,e:            if e[0] == errno.EAGAIN:                # baaah                pass            elif e[0] == errno.ENOENT or not os.path.exists(file):                # We need to check os.path.exists for use on operating systems that                # never return ENOENT; linux 2.2.                #                # no such file.... no such server. create one.                no_server_count += 1                if no_server_count>4:                    raise                fork_server(server_options)            elif e[0] == errno.ECONNREFUSED:                # socket file exists but noone listening.                refused_count += 1                if refused_count == 6:                    # We have been waiting ages and still havent been able                    # to connect. Maybe that socket file has got                    # orphaned. remove it, wait, and try again. We need to                    # allow enough time for sb_bnserver to initialise the                    # rest of spambayes                    try:                        os.unlink(file)                    except EnvironmentError:                        pass                elif refused_count>6:                    raise            else:                raise # some other problem            time.sleep(0.2 * 2.0**no_server_count * 2.0**refused_count)        else:            return s                    def fork_server(options):    if os.fork():        # parent        return    os.close(0)    sys.stdin = sys.__stdin__ = open("/dev/null")    os.close(1)    sys.stdout = sys.__stdout__ = open("/dev/null", "w")    # leave stderr    # os.close(2)    # sys.stderr = sys.__stderr__ = open("/dev/null", "w")    os.setsid()    # Use exec rather than import here because eventually it may be nice to    # reimplement this one file in C    os.execv(sys.executable,[sys.executable,                             os.path.join(os.path.split(sys.argv[0])[0],                                          'sb_bnserver.py') ]+options)    # should never get here    sys._exit(1)    if __name__ == "__main__":    main()        

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -