"Fossies" - the Fresh Open Source Software Archive

Member "spambayes-1.1a6/windows/pop3proxy_service.py" (7 Dec 2008, 11457 Bytes) of archive /windows/mail/spambayes-1.1a6.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "pop3proxy_service.py" see the Fossies "Dox" file reference documentation.

    1 # Run the sb_server as a WinNT service.  Should work on Windows 2000
    2 # and Windows XP.
    3 #
    4 # * Install as a service using "pop3proxy_service.py install"
    5 # * Start the service (Use Control Panel etc, or
    6 #   "pop3proxy_service.py start".  Check the event
    7 #   log should anything go wrong.
    8 # * To debug the service: "pop3proxy_service.py debug"
    9 #   Service then runs in the command prompt, showing all
   10 #   print statements.
   11 # * To remove the service: "pop3proxy_service.py remove"
   12 
   13 # This module is part of the spambayes project, which is Copyright 2002-2007
   14 # The Python Software Foundation and is covered by the Python Software
   15 # Foundation license.
   16 
   17 # Originally written by Mark Hammond.
   18 
   19 import os
   20 import sys
   21 import logging
   22 
   23 import servicemanager
   24 try:
   25     servicemanager.LogInfoMsg(os.getcwd())
   26     servicemanager.LogInfoMsg(__file__)
   27     servicemanager.LogInfoMsg(sys.argv[0])
   28 except:
   29     pass
   30 
   31 class ServiceEventLogHandler(logging.Handler):
   32     """Dispatches logging events to the win32 services event log.
   33 
   34     Requires pywin32.    
   35     """
   36     import servicemanager
   37     def emit(self, record):
   38         """Emit a record.
   39 
   40         If a formatter is specified, it is used to format the record.
   41         This record is then written to the win32 services event log,
   42         with the type set to the appropriate type based on the level.
   43         """
   44         try:
   45             servicemgr = self.servicemanager
   46             level = record.levelno
   47             msg = self.format(record)
   48             if level >= logging.ERROR:
   49                 servicemgr.LogErrorMsg(msg)
   50             elif level >= logging.WARNING:
   51                 servicemgr.LogWarningMsg(msg)
   52             elif level >= logging.INFO:
   53                 servicemgr.LogInfoMsg(msg)
   54             elif level >= logging.DEBUG:
   55                 # What should we do with this?  It's very low-level
   56                 # to be going into the log, but then it only gets
   57                 # added if the logger's level is set low enough.
   58                 # For now, nothing (absorb), and reconsider this
   59                 # when we are actually using the logging module properly.
   60                 pass
   61             else:
   62                 # Really low; just absorb these for now.
   63                 pass
   64         except:
   65             self.handleError(record)
   66 
   67     def handleError(self, record):
   68         """
   69         Handle errors which occur during an emit() call.
   70 
   71         sys.stderr does nowwhere, so redirect this into the event log, too.
   72         """
   73         if raiseExceptions:
   74             try:
   75                 import cStringIO as StringIO
   76             except ImportError:
   77                 import StringIO
   78             import traceback
   79             ei = sys.exc_info()
   80             msg = StringIO.StringIO()
   81             traceback.print_exception(ei[0], ei[1], ei[2], None, msg)
   82             msg.seek(0)
   83             self.servicemanager.LogErrorMsg(msg)
   84             del ei
   85 
   86 
   87 class ServiceEventLogHandlerWrapper(object):
   88     """Pretend that the ServiceEventLogHandler is a file-like object,
   89     so we can use it while we don't use the proper logging module."""
   90     def __init__(self, service_name, level=logging.INFO):
   91         self.log = ServiceEventLogHandler()
   92         self.name = service_name
   93         self.level = level
   94         self.data = ""
   95     def write(self, data):
   96         # This could use the higher-up stuff, but don't for now.
   97         # Buffer until newline.
   98         self.data += data
   99         if '\n' not in data:
  100             return
  101         # Skip blank lines
  102         if not self.data.strip():
  103             return
  104         record = logging.LogRecord(self.name, self.level, "", "",
  105                                    self.data, None, None)
  106         self.log.emit(record)
  107         self.data = ""
  108 
  109 
  110 # Messages from pop3proxy will go nowhere when executed as a service
  111 # Try and detect that print will go nowhere and redirect.
  112 # redirect output somewhere useful when running as a service.
  113 import win32api
  114 try:
  115     win32api.GetConsoleTitle()
  116 except win32api.error:
  117     # No console - if we are running from Python sources,
  118     # redirect to win32traceutil, but if running from a binary
  119     # install, redirect to the services event log.
  120     # We used to redirect to log files (in the temp folder, in
  121     # the form SpamBayesService%d.log), but that is apparently
  122     # not necessarily a good place, so we moved to the official
  123     # location.
  124     # Want to move to logging module later, so for now, we
  125     # hack together a simple logging strategy.
  126     if hasattr(sys, "frozen"):
  127         sys.stdout = ServiceEventLogHandlerWrapper("pop3proxy")
  128         sys.stderr = ServiceEventLogHandlerWrapper("pop3proxy",
  129                                                    logging.ERROR)
  130     else:
  131         import win32traceutil
  132 
  133 # If running from sources, patch up sys.path
  134 if not hasattr(sys, "frozen"):
  135     # We are in the 'spambayes\win32' directory.  We
  136     # need the parent on sys.path, so 'spambayes.spambayes' is a package,
  137     # and 'pop3proxy' is a module
  138     this_filename = __file__
  139 
  140     sb_dir = os.path.dirname(os.path.dirname(this_filename))
  141     sb_scripts_dir = os.path.join(sb_dir,"scripts")
  142 
  143     sys.path.insert(0, sb_dir)
  144     sys.path.insert(-1, sb_scripts_dir)
  145     # and change directory here, so sb_server uses the correct
  146     # config file etc
  147     # If the "SpamBayesData" directory that we create exists, change to
  148     # that, otherwise into the spambayes directory itself.
  149     if os.path.exists(os.path.join(sb_dir, "SpamBayesData")):
  150         os.chdir(os.path.join(sb_dir, "SpamBayesData"))
  151     else:
  152         os.chdir(sb_dir)
  153 
  154     # Fix to handle problem if there is a zlib.dll in the SYSTEM32 directory.
  155     # (The Python DLL directory must come before that in sys.path)
  156     # This is a bit hackish, but shouldn't do any real harm.
  157     from win32com.shell import shell, shellcon
  158     sys32path = shell.SHGetFolderPath(0, shellcon.CSIDL_SYSTEM, 0, 0)
  159     for path in sys.path[:-1]:
  160         if path == sys32path:
  161             sys.path.remove(path)
  162             assert path not in sys.path, \
  163                    "Please remove multiple copies of windows\system32 in path"
  164             sys.path.append(path) # put it at the *end*
  165     del sys32path
  166     del shell
  167     del shellcon
  168     del path
  169 
  170 # Rest of the standard Python modules we use.
  171 import traceback
  172 import threading
  173 import cStringIO
  174 
  175 # The spambayes imports we need.
  176 import sb_server
  177 
  178 # The win32 specific modules.
  179 import win32serviceutil, win32service
  180 import pywintypes, win32con, winerror
  181 from ntsecuritycon import *
  182 
  183 class Service(win32serviceutil.ServiceFramework):
  184     # The script name was changed to "sb_server" but I'll leave this as pop3proxy
  185     # overwise people might accidently run two proxies.
  186     _svc_name_ = "pop3proxy"
  187     _svc_display_name_ = "SpamBayes Service"
  188     _svc_deps_ =  ['tcpip'] # We depend on the tcpip service.
  189     def __init__(self, args):
  190         win32serviceutil.ServiceFramework.__init__(self, args)
  191         self.event_stopped = threading.Event()
  192         self.event_stopping = threading.Event()
  193         self.thread = None
  194 
  195     def SvcStop(self):
  196         self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
  197         self.event_stopping.set()
  198         sb_server.stop()
  199 
  200     def SvcDoRun(self):
  201         import servicemanager
  202         # Setup our state etc
  203         try:
  204             sb_server.prepare(can_stop=False)
  205         except sb_server.AlreadyRunningException:
  206             msg = "The SpamBayes proxy service could not be started, as "\
  207                   "another SpamBayes server is already running on this machine"
  208             servicemanager.LogErrorMsg(msg)
  209             errCode = winerror.ERROR_SERVICE_SPECIFIC_ERROR
  210             self.ReportServiceStatus(win32service.SERVICE_STOPPED,
  211                                      win32ExitCode=errCode, svcExitCode=1)
  212             return
  213         assert not sb_server.state.launchUI, "Service can't launch a UI"
  214 
  215         # Start the thread running the server.
  216         thread = threading.Thread(target=self.ServerThread)
  217         thread.start()
  218 
  219         # Write an event log record - in debug mode we will also
  220         # see this message printed.
  221         from spambayes.Options import optionsPathname
  222         extra = " as user '%s', using config file '%s'" \
  223                 % (win32api.GetUserName(),
  224                    optionsPathname)
  225         servicemanager.LogMsg(
  226             servicemanager.EVENTLOG_INFORMATION_TYPE,
  227             servicemanager.PYS_SERVICE_STARTED,
  228             (self._svc_name_, extra)
  229             )
  230 
  231         try:
  232             # Thread running - wait for the stopping event.
  233             self.event_stopping.wait()
  234             # Either user requested stop, or thread done - wait for it
  235             # to actually stop, but reporting we are still alive.
  236             # Wait up to 60 seconds for shutdown before giving up and
  237             # exiting uncleanly - we wait for current proxy connections
  238             # to close, but you have to draw the line somewhere.
  239             for i in range(60):
  240                 self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
  241                 self.event_stopped.wait(1)
  242                 if self.event_stopped.isSet():
  243                     break
  244                 print "The service is still shutting down..."
  245             else:
  246                 # eeek - we timed out - give up in disgust.
  247                 print "The worker failed to stop - aborting it anyway"
  248         except KeyboardInterrupt:
  249             pass
  250 
  251         # Write another event log record.
  252         s = sb_server.state
  253         status = " after %d sessions (%d ham, %d spam, %d unsure)" % \
  254                 (s.totalSessions, s.numHams, s.numSpams, s.numUnsure)
  255 
  256         servicemanager.LogMsg(
  257             servicemanager.EVENTLOG_INFORMATION_TYPE,
  258             servicemanager.PYS_SERVICE_STOPPED,
  259             (self._svc_name_, status)
  260             )
  261 
  262     def ServerThread(self):
  263         try:
  264             try:
  265                 sb_server.start()
  266             except SystemExit:
  267                 # user requested shutdown
  268                 print "pop3proxy service shutting down due to user request"
  269             except:
  270                 # Otherwise an error we should log.
  271                 ob = cStringIO.StringIO()
  272                 traceback.print_exc(file=ob)
  273 
  274                 message = "The pop3proxy service failed with an " \
  275                           "unexpected error\r\n\r\n" + ob.getvalue()
  276 
  277                 # print it too, so any other log we have gets it.
  278                 print message
  279                 # Log an error event to the event log.
  280                 import servicemanager
  281                 servicemanager.LogErrorMsg(message)
  282         finally:
  283             self.event_stopping.set()
  284             self.event_stopped.set()
  285 
  286 if __name__=='__main__':
  287     if "install" in sys.argv:
  288         # Installing the service also creates a directory (if it does not
  289         # already exist) in which the data will be placed, unless an
  290         # existing configuration file can be found.
  291         from spambayes.Options import optionsPathname
  292         if not os.path.exists(optionsPathname):
  293             data_directory = os.path.join(os.path.dirname(sys.argv[0]),
  294                                           "..", "SpamBayesData")
  295             data_directory = os.path.abspath(data_directory)
  296             if not os.path.exists(data_directory):
  297                 print "Creating data directory at", data_directory
  298                 os.makedirs(data_directory)
  299     win32serviceutil.HandleCommandLine(Service)