# 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
# The Python Software Foundation and is covered by the Python Software
# Foundation license.
# Originally written by Mark Hammond.
import sys, os
# 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.
import win32api
try:
win32api.GetConsoleTitle()
except win32api.error:
# No console - if we are running from Python sources,
# redirect to win32traceutil, but if running from a binary
# install, redirect to a log file.
# Want to move to logging module later, so for now, we
# hack together a simple logging strategy.
if hasattr(sys, "frozen"):
temp_dir = win32api.GetTempPath()
for i in range(3,0,-1):
try: os.unlink(os.path.join(temp_dir, "SpamBayesService%d.log" % (i+1)))
except os.error: pass
try:
os.rename(
os.path.join(temp_dir, "SpamBayesService%d.log" % i),
os.path.join(temp_dir, "SpamBayesService%d.log" % (i+1))
)
except os.error: pass
# Open this log, as unbuffered so crashes still get written.
sys.stdout = open(os.path.join(temp_dir,"SpamBayesService1.log"), "wt", 0)
sys.stderr = sys.stdout
else:
import win32traceutil
# 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
try:
# module imported by service manager, or 2.3 (in which __main__
# exists, *and* sys.argv[0] is always already absolute)
this_filename=__file__
except NameError:
this_filename = sys.argv[0]
if not os.path.isabs(sys.argv[0]):
# Python 2.3 __main__
# patch up sys.argv, as our cwd will confuse service registration code
sys.argv[0] = os.path.abspath(sys.argv[0])
this_filename = sys.argv[0]
sb_dir = os.path.dirname(os.path.dirname(this_filename))
sb_scripts_dir = os.path.join(sb_dir,"scripts")
sys.path.insert(0, sb_dir)
sys.path.insert(-1, sb_scripts_dir)
# and change directory here, so pop3proxy uses the default
# config file etc
os.chdir(sb_dir)
# Rest of the standard Python modules we use.
import traceback
import threading
import cStringIO
# The spambayes imports we need.
import sb_server
# The win32 specific modules.
import win32serviceutil, win32service
import pywintypes, win32con, winerror
from ntsecuritycon import *
class Service(win32serviceutil.ServiceFramework):
# 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):
win32serviceutil.ServiceFramework.__init__(self, args)
self.event_stopped = threading.Event()
self.event_stopping = threading.Event()
self.thread = None
def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
self.event_stopping.set()
sb_server.stop()
def SvcDoRun(self):
import servicemanager
# Setup our state etc
try:
sb_server.prepare()
except sb_server.AlreadyRunningException:
msg = "The SpamBayes proxy service could not be started, as "\
"another SpamBayes server is already running on this machine"
servicemanager.LogErrorMsg(msg)
errCode = winerror.ERROR_SERVICE_SPECIFIC_ERROR
self.ReportServiceStatus(win32service.SERVICE_STOPPED,
win32ExitCode=errCode, svcExitCode = 1)
return
assert not sb_server.state.launchUI, "Service can't launch a UI"
# Start the thread running the server.
thread = threading.Thread(target=self.ServerThread)
thread.start()
# 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'" \
% (win32api.GetUserName(),
optionsPathname)
servicemanager.LogMsg(
servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_, extra)
)
try:
# Thread running - wait for the stopping event.
self.event_stopping.wait()
# 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):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
self.event_stopped.wait(1)
if self.event_stopped.isSet():
break
print "The service is still shutting down..."
else:
# eeek - we timed out - give up in disgust.
print "The worker failed to stop - aborting it anyway"
except KeyboardInterrupt:
pass
# 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)
servicemanager.LogMsg(
servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STOPPED,
(self._svc_name_, status)
)
def ServerThread(self):
try:
try:
sb_server.start()
except SystemExit:
# user requested shutdown
print "pop3proxy service shutting down due to user request"
except:
# Otherwise an error we should log.
ob = cStringIO.StringIO()
traceback.print_exc(file=ob)
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.
print message
# Log an error event to the event log.
import servicemanager
servicemanager.LogErrorMsg(message)
finally:
self.event_stopping.set()
self.event_stopped.set()
if __name__=='__main__':
win32serviceutil.HandleCommandLine(Service)
syntax highlighted by Code2HTML, v. 0.9.1