"""Email proxy for Avaya's Voicemail Pro (which embeds G-Lock's EasyMail Pro). Voicemail Pro has the capability to send email alerts when a voicemail message is left in a given voicemail box. We use this capability at Amor Ministries, for example, to run an "emergency extension"--if one of our customers has an emergency after hours, they can leave a voicemail message in this box, and various people will be paged to address the issue. Unfortunately, the emails that Voicemail Pro sends out don't follow RFC 821, which requires "MAIL FROM" before "DATA". This causes Exim, which requires spec compliance, to choke. This module runs as an SMTP proxy, fixing up the email from Voicemail Pro and forwarding it on to a designated recipient. It only runs on localhost for security reasons. """ def log_error(): import traceback f = open(r"C:\diefile.txt", "wb") traceback.print_exc(file=f) f.close() try: import asyncore import smtpd import threading import win32serviceutil import win32service import win32event import servicemanager class win32log: def write(self, msg): servicemanager.LogInfoMsg('%s (%s): %s' % (SMTPProxyService._svc_name_, SMTPProxyService._svc_display_name_, msg)) def flush(self): pass win32log = win32log() ##smtpd.DEBUGSTREAM = win32log class VoicemailProProxy(smtpd.PureProxy): def process_message(self, peer, mailfrom, rcpttos, data): # Fixup the mailfrom; # Exim requires that it contain a domain, but it's coming through as "Voicemail2". refused = self._deliver("vemergency@amor.org", rcpttos, data) # TBD: what to do with refused addresses? win32log.write("Delivery results: %s" % repr(refused)) return refused class SMTPProxyService(win32serviceutil.ServiceFramework): _svc_name_ = "vmpropager3" _svc_display_name_ = "Voicemail Pro Email Fixup 3" def __init__(self, args, *a, **kw): try: servicemanager.LogInfoMsg("entering init") win32serviceutil.ServiceFramework.__init__(self, args) servicemanager.LogInfoMsg("framework inited") # create an event that SvcDoRun can wait on and SvcStop can set. self.hWaitStop = win32event.CreateEvent(None, 0, 0, None) servicemanager.LogInfoMsg("event created") # create our proxy instance self.proxy = VoicemailProProxy(("localhost", 25), ("192.168.0.6", 25)) servicemanager.LogInfoMsg("proxy created") except: log_error() raise def SvcDoRun(self): # log a service started message servicemanager.LogMsg( servicemanager.EVENTLOG_INFORMATION_TYPE, servicemanager.PYS_SERVICE_STARTED, (self._svc_name_, ' (%s)' % self._svc_display_name_)) # Start the SMTP proxy listener loop in a separate thread t = threading.Thread(None, asyncore.loop) t.start() # Wait for a service stop request. win32event.WaitForSingleObject(self.hWaitStop, win32event.INFINITE) # signal stop and wait for the SMTP thread to stop self.proxy.close() t.join() # log a service stopped message servicemanager.LogMsg( servicemanager.EVENTLOG_INFORMATION_TYPE, servicemanager.PYS_SERVICE_STOPPED, (self._svc_name_, ' (%s) ' % self._svc_display_name_)) def SvcStop(self): self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) win32event.SetEvent(self.hWaitStop) SvcShutdown = SvcStop if __name__ == '__main__': import sys if sys.argv[1:] == ['test']: p = VoicemailProProxy(("localhost", 25), ("192.168.0.6", 25)) try: asyncore.loop() except KeyboardInterrupt: p.close() else: print "handling command line" win32serviceutil.HandleCommandLine(SMTPProxyService) else: # Don't use sys.stdout import win32traceutil except: log_error() raise