[Spambayes] A most peculair problem with SB 1
tameyer at ihug.co.nz
Fri Nov 12 01:04:14 CET 2004
> Namely some nursery school instructions on how to apply the two
> changes: do I simply open the scripts in an editor and cut/paste the
> changes into place
Either that, or if there is a 'patch' tool there you can give the diff and
the original to it and it'll do it for you. Anyway, to save the bother,
attached is a changed version (slightly further along) of the script - just
replace the 1.0 one with this one.
> Is there anything else I need to do afterwards?
Shouldn't be, no.
Please always include the list (spambayes at python.org) in your replies
(reply-all), and please don't send me personal mail about SpamBayes.
http://www.massey.ac.nz/~tameyer/writing/reply_all.html explains this.
-------------- next part --------------
# Run the sb_server as a WinNT service. Should work on Windows 2000
# and Windows XP.
# * Install as a service using "pop3proxy_service.py install"
# * Start the service (Use Control Panel etc, or
# "pop3proxy_service.py start". Check the event
# log should anything go wrong.
# * To debug the service: "pop3proxy_service.py debug"
# Service then runs in the command prompt, showing all
# print statements.
# * To remove the service: "pop3proxy_service.py remove"
# This module is part of the spambayes project, which is Copyright 2002-4
# The Python Software Foundation and is covered by the Python Software
# Foundation license.
# Originally written by Mark Hammond.
"""Dispatches logging events to the win32 services event log.
def emit(self, record):
"""Emit a record.
If a formatter is specified, it is used to format the record.
This record is then written to the win32 services event log,
with the type set to the appropriate type based on the level.
servicemgr = self.servicemanager
level = record.levelno
msg = self.format(record)
if level >= logging.ERROR:
elif level >= logging.WARNING:
elif level >= logging.INFO:
elif level >= logging.DEBUG:
# What should we do with this? It's very low-level
# to be going into the log, but then it only gets
# added if the logger's level is set low enough.
# For now, nothing (absorb), and reconsider this
# when we are actually using the logging module properly.
# Really low; just absorb these for now.
def handleError(self, record):
Handle errors which occur during an emit() call.
sys.stderr does nowwhere, so redirect this into the event log, too.
import cStringIO as StringIO
ei = sys.exc_info()
msg = StringIO.StringIO()
traceback.print_exception(ei, ei, ei, None, msg)
"""Pretend that the ServiceEventLogHandler is a file-like object,
so we can use it while we don't use the proper logging module."""
def __init__(self, service_name, level=logging.INFO):
self.log = ServiceEventLogHandler()
self.name = service_name
self.level = level
self.data = ""
def write(self, data):
# This could use the higher-up stuff, but don't for now.
# Buffer until newline.
self.data += data
if '\n' not in data:
# Skip blank lines
if not self.data.strip():
record = logging.LogRecord(self.name, self.level, "", "",
self.data, None, None)
self.data = ""
# Messages from pop3proxy will go nowhere when executed as a service
# Try and detect that print will go nowhere and redirect.
# redirect output somewhere useful when running as a service.
# No console - if we are running from Python sources,
# redirect to win32traceutil, but if running from a binary
# install, redirect to the services event log.
# We used to redirect to log files (in the temp folder, in
# the form SpamBayesService%d.log), but that is apparently
# not necessarily a good place, so we moved to the official
# Want to move to logging module later, so for now, we
# hack together a simple logging strategy.
if hasattr(sys, "frozen"):
sys.stdout = ServiceEventLogHandlerWrapper("pop3proxy")
sys.stderr = ServiceEventLogHandlerWrapper("pop3proxy",
# If running from sources, patch up sys.path
if not hasattr(sys, "frozen"):
# We are in the 'spambayes\win32' directory. We
# need the parent on sys.path, so 'spambayes.spambayes' is a package,
# and 'pop3proxy' is a module
# module imported by service manager, or 2.3 (in which __main__
# exists, *and* sys.argv is always already absolute)
this_filename = sys.argv
if not os.path.isabs(sys.argv):
# Python 2.3 __main__
# patch up sys.argv, as our cwd will confuse service registration code
sys.argv = os.path.abspath(sys.argv)
this_filename = sys.argv
sb_dir = os.path.dirname(os.path.dirname(this_filename))
sb_scripts_dir = os.path.join(sb_dir,"scripts")
# and change directory here, so pop3proxy uses the default
# config file etc
# Fix to handle problem if there is a zlib.dll in the SYSTEM32 directory.
# (The Python DLL directory must come before that in sys.path)
# This is a bit hackish, but shouldn't do any real harm.
from win32com.shell import shell, shellcon
sys32path = shell.SHGetFolderPath(0, shellcon.CSIDL_SYSTEM, 0, 0)
for path in sys.path[:-1]:
if path == sys32path:
assert path not in sys.path, \
"Please remove multiple copies of windows\system32 in path"
sys.path.append(path) # put it at the *end*
# Rest of the standard Python modules we use.
# The spambayes imports we need.
# The win32 specific modules.
import win32serviceutil, win32service
import pywintypes, win32con, winerror
from ntsecuritycon import *
# The script name was changed to "sb_server" but I'll leave this as pop3proxy
# overwise people might accidently run two proxies.
_svc_name_ = "pop3proxy"
_svc_display_name_ = "SpamBayes Service"
_svc_deps_ = ['tcpip'] # We depend on the tcpip service.
def __init__(self, args):
self.event_stopped = threading.Event()
self.event_stopping = threading.Event()
self.thread = None
# Setup our state etc
msg = "The SpamBayes proxy service could not be started, as "\
"another SpamBayes server is already running on this machine"
errCode = winerror.ERROR_SERVICE_SPECIFIC_ERROR
assert not sb_server.state.launchUI, "Service can't launch a UI"
# Start the thread running the server.
thread = threading.Thread(target=self.ServerThread)
# Write an event log record - in debug mode we will also
# see this message printed.
from spambayes.Options import optionsPathname
extra = " as user '%s', using config file '%s'" \
# Thread running - wait for the stopping event.
# Either user requested stop, or thread done - wait for it
# to actually stop, but reporting we are still alive.
# Wait up to 60 seconds for shutdown before giving up and
# exiting uncleanly - we wait for current proxy connections
# to close, but you have to draw the line somewhere.
for i in range(60):
print "The service is still shutting down..."
# eeek - we timed out - give up in disgust.
print "The worker failed to stop - aborting it anyway"
# Write another event log record.
s = sb_server.state
status = " after %d sessions (%d ham, %d spam, %d unsure)" % \
(s.totalSessions, s.numHams, s.numSpams, s.numUnsure)
# user requested shutdown
print "pop3proxy service shutting down due to user request"
# Otherwise an error we should log.
ob = cStringIO.StringIO()
message = "The pop3proxy service failed with an " \
"unexpected error\r\n\r\n" + ob.getvalue()
# print it too, so any other log we have gets it.
# Log an error event to the event log.
More information about the Spambayes