[Spambayes-checkins] spambayes pop3proxy.py,1.9,1.10
Richie Hindle
richiehindle@users.sourceforge.net
Tue Nov 5 22:18:59 2002
Update of /cvsroot/spambayes/spambayes
In directory usw-pr-cvs1:/tmp/cvs-serv23270
Modified Files:
pop3proxy.py
Log Message:
First cut of the HTML user interface - see the docstring for -b and -u.
Now reads the classification header and its values from the options.
Added TOP support to the test server (to make 40tude Dialog happy).
Index: pop3proxy.py
===================================================================
RCS file: /cvsroot/spambayes/spambayes/pop3proxy.py,v
retrieving revision 1.9
retrieving revision 1.10
diff -C2 -d -r1.9 -r1.10
*** pop3proxy.py 2 Nov 2002 21:00:21 -0000 1.9
--- pop3proxy.py 5 Nov 2002 22:18:56 -0000 1.10
***************
*** 15,19 ****
-p FILE : use the named data file
-d : the file is a DBM file rather than a pickle
! -l port : listen on this port number (default 110)
pop3proxy -t
--- 15,22 ----
-p FILE : use the named data file
-d : the file is a DBM file rather than a pickle
! -l port : proxy listens on this port number (default 110)
! -u port : User interface listens on this port number
! (default 8880; Browse http://localhost:8880/)
! -b : Launch a web browser showing the user interface.
pop3proxy -t
***************
*** 35,40 ****
! import sys, re, operator, errno, getopt, cPickle, time
! import socket, asyncore, asynchat
import classifier, tokenizer, hammie
from Options import options
--- 38,43 ----
! import sys, re, operator, errno, getopt, cPickle, cStringIO, time
! import socket, asyncore, asynchat, cgi, urlparse, webbrowser
import classifier, tokenizer, hammie
from Options import options
***************
*** 42,47 ****
# HEADER_EXAMPLE is the longest possible header - the length of this one
# is added to the size of each message.
! HEADER_FORMAT = '%s: %%s\r\n' % hammie.DISPHEADER
! HEADER_EXAMPLE = '%s: Unsure\r\n' % hammie.DISPHEADER
--- 45,57 ----
# HEADER_EXAMPLE is the longest possible header - the length of this one
# is added to the size of each message.
! HEADER_FORMAT = '%s: %%s\r\n' % options.hammie_header_name
! HEADER_EXAMPLE = '%s: xxxxxxxxxxxxxxxxxxxx\r\n' % options.hammie_header_name
!
! # This keeps the global status of the module - the command-line options,
! # how many mails have been classified, how many active connections there
! # are, and so on.
! class Status:
! pass
! status = Status()
***************
*** 61,65 ****
self.set_socket(s, socketMap)
self.set_reuse_addr()
! print "Listening on port %d." % port
self.bind(('', port))
self.listen(5)
--- 71,75 ----
self.set_socket(s, socketMap)
self.set_reuse_addr()
! print "%s listening on port %d." % (self.__class__.__name__, port)
self.bind(('', port))
self.listen(5)
***************
*** 73,80 ****
self.factory(*args)
! class POP3ProxyBase(asynchat.async_chat):
"""An async dispatcher that understands POP3 and proxies to a POP3
! server, calling `self.onTransaction( request, response )` for each
transaction. Responses are not un-byte-stuffed before reaching
self.onTransaction() (they probably should be for a totally generic
--- 83,107 ----
self.factory(*args)
+ class BrighterAsyncChat(asynchat.async_chat):
+ """An asynchat.async_chat that doesn't give spurious warnings on
+ receiving an incoming connection, and lets SystemExit cause an
+ exit."""
! def handle_connect(self):
! """Suppress the asyncore "unhandled connect event" warning."""
! pass
!
! def handle_error(self):
! """Let SystemExit cause an exit."""
! type, v, t = sys.exc_info()
! if type == SystemExit:
! raise
! else:
! asynchat.async_chat.handle_error(self)
!
!
! class POP3ProxyBase(BrighterAsyncChat):
"""An async dispatcher that understands POP3 and proxies to a POP3
! server, calling `self.onTransaction(request, response)` for each
transaction. Responses are not un-byte-stuffed before reaching
self.onTransaction() (they probably should be for a totally generic
***************
*** 88,92 ****
def __init__(self, clientSocket, serverName, serverPort):
! asynchat.async_chat.__init__(self, clientSocket)
self.request = ''
self.set_terminator('\r\n')
--- 115,119 ----
def __init__(self, clientSocket, serverName, serverPort):
! BrighterAsyncChat.__init__(self, clientSocket)
self.request = ''
self.set_terminator('\r\n')
***************
*** 96,103 ****
self.push(self.serverIn.readline())
- def handle_connect(self):
- """Suppress the asyncore "unhandled connect event" warning."""
- pass
-
def onTransaction(self, command, args, response):
"""Overide this. Takes the raw request and the response, and
--- 123,126 ----
***************
*** 221,232 ****
self.close_when_done()
- def handle_error(self):
- """Let SystemExit cause an exit."""
- type, v, t = sys.exc_info()
- if type == SystemExit:
- raise
- else:
- asynchat.async_chat.handle_error(self)
-
class BayesProxyListener(Listener):
--- 244,247 ----
***************
*** 276,279 ****
--- 291,296 ----
self.handlers = {'STAT': self.onStat, 'LIST': self.onList,
'RETR': self.onRetr, 'TOP': self.onTop}
+ status.totalSessions += 1
+ status.activeSessions += 1
def send(self, data):
***************
*** 290,293 ****
--- 307,314 ----
return data
+ def close(self):
+ status.activeSessions -= 1
+ POP3ProxyBase.close(self)
+
def onTransaction(self, command, args, response):
"""Takes the raw request and response, and returns the
***************
*** 343,352 ****
# Now find the spam disposition and add the header.
prob = self.bayes.spamprob(tokenizer.tokenize(message))
if prob < options.ham_cutoff:
! disposition = "No"
elif prob > options.spam_cutoff:
! disposition = "Yes"
else:
! disposition = "Unsure"
headers, body = re.split(r'\n\r?\n', response, 1)
--- 364,381 ----
# Now find the spam disposition and add the header.
prob = self.bayes.spamprob(tokenizer.tokenize(message))
+ if command == 'RETR':
+ status.numEmails += 1
if prob < options.ham_cutoff:
! disposition = options.header_ham_string
! if command == 'RETR':
! status.numHams += 1
elif prob > options.spam_cutoff:
! disposition = options.header_spam_string
! if command == 'RETR':
! status.numSpams += 1
else:
! disposition = options.header_unsure_string
! if command == 'RETR':
! status.numUnsure += 1
headers, body = re.split(r'\n\r?\n', response, 1)
***************
*** 368,372 ****
! def main(serverName, serverPort, proxyPort, pickleName, useDB):
"""Runs the proxy forever or until a 'KILL' command is received or
someone hits Ctrl+Break."""
--- 397,646 ----
! class UserInterfaceListener(Listener):
! """Listens for incoming web browser connections and spins off
! UserInterface objects to serve them."""
!
! def __init__(self, uiPort, bayes):
! uiArgs = (bayes,)
! Listener.__init__(self, uiPort, UserInterface, uiArgs)
!
!
! # Until the user interface has had a wider audience, I won't pollute the
! # project with .gif files and the like. Here's the viking helmet.
! import base64
! helmet = base64.decodestring(
! """R0lGODlhIgAYAPcAAEJCRlVTVGNaUl5eXmtaVm9lXGtrZ3NrY3dvZ4d0Znt3dImHh5R+a6GDcJyU
! jrSdjaWlra2tra2tta+3ur2trcC9t7W9ysDDyMbGzsbS3r3W78bW78be78be973e/8bn/86pjNav
! kc69re/Lrc7Ly9ba4vfWveTh5M7e79be79bn797n7+fr6+/v5+/v7/f3787e987n987n/9bn99bn
! /9bv/97n997v++fv9+f3/+/v9+/3//f39/f/////9////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
! AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
! AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
! AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
! AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
! AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
! AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
! AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
! AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
! AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
! AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAB4ALAAAAAAiABgA
! AAj+AD0IHEiwoMGDA2XI8PBhxg2EECN+YJHjwwccOz5E3FhQBgseMmK44KGRo0kaLHzQENljoUmO
! NE74uGHDxQ8aL2GmzFHzZs6NNFr8yKHC5sOfEEUOVcHiR8aNFksi/LCCx1KZPXAilLHBAoYMMSB6
! 9DEUhsyhUgl+wOBAwQIHFsIapGpzaIcTVnvcSOsBhgUFBgYUMKAgAgqNH2J0aPjxR9YPJerqlYEi
! w4YYExQM2FygwIHCKVBgiBChBIsXP5wu3HD2Bw8MC2JD0CygAIHOnhU4cLDA7QWrqfd6iBE5dQsH
! BgJvHiDgNoID0A88V6AAAQSyjl16QIHXBwnNAwDIBAhAwDmDBAjQHyiAIPkC7DnUljhxwkGAAQHE
! B+icIAGD8+clUMByCNjUUkEdlHCBAvflF0BtB/zHQAMSCjhYYBXsoFVBMWAQWH4AAFBbAg2UWOID
! FK432AEO2ABRBwtsFuKDBTSAYgMghBDCAwwgwB4CClQAQ0R/4RciAQjYyMADIIwwAggN+PeWBTPw
! VdAHHEjA4IMR8ojjCCaEEGUCFcygnUQxaEndbhBAwKQIFVAAgQMQHPZTBxrkqUEHfHLAAZ+AdgBR
! QAAAOw==""")
!
!
! class UserInterface(BrighterAsyncChat):
! """Serves the HTML user interface of the proxy."""
!
! header = """<html><head><title>Spambayes proxy: %s</title>
! <style>
! body { font: 90%% arial, swiss, helvetica }
! table { font: 90%% arial, swiss, helvetica }
! form { margin: 0 }
! .banner { background: #c0e0ff; padding=5; padding-left: 15 }
! .header { font-size: 133%% }
! .content { margin: 15 }
! .sectiontable { border: 1px solid #808080; width: 95%% }
! .sectionheading { background: fffae0; padding-left: 1ex;
! border-bottom: 1px solid #808080;
! font-weight: bold }
! .sectionbody { padding: 1em }
! </style>
! </head>\n"""
!
! bodyStart = """<body style='margin: 0'>
! <div class='banner'>
! <img src='/helmet.gif' align='absmiddle'>
! <span class='header'>Spambayes proxy: %s</span></div>
! <div class='content'>\n"""
!
! footer = """</div>
! <form action='/shutdown'>
! <table width='100%%' cellspacing='0'>
! <tr><td class='banner'> Spambayes Proxy, %s.
! <a href='http://www.spambayes.org/'>Spambayes.org</a></td>
! <td align='right' class='banner'>
! <input type='submit' value='Shutdown now'>
! </td></tr></table></form>\n"""
!
! pageSection = """<table class='sectiontable' cellspacing='0'>
! <tr><td class='sectionheading'>%s</td></tr>
! <tr><td class='sectionbody'>%s</td></tr></table>
! <br>\n"""
!
! wordQuery = """<form action='/wordquery'>
! <input name='word' type='text' size='30'>
! <input type='submit' value='Tell me about this word'>
! </form>"""
!
! def __init__(self, clientSocket, bayes):
! BrighterAsyncChat.__init__(self, clientSocket)
! self.bayes = bayes
! self.request = ''
! self.set_terminator('\r\n\r\n')
! self.helmet = helmet
!
! def collect_incoming_data(self, data):
! """Asynchat override."""
! self.request = self.request + data
!
! def found_terminator(self):
! """Asynchat override.
! Read and parse the HTTP request and call an on<Command> handler."""
! requestLine, headers = self.request.split('\r\n', 1)
! try:
! method, url, version = requestLine.strip().split()
! except ValueError:
! self.pushError(400, "Malformed request: '%s'" % requestLine) # XXX: 400??
! self.close_when_done()
! else:
! method = method.upper()
! _, _, path, _, query, _ = urlparse.urlparse(url)
! params = cgi.parse_qs(query, keep_blank_values=True)
! if self.get_terminator() == '\r\n\r\n' and method == 'POST':
! # We need to read a body; set a numeric async_chat terminator.
! match = re.search(r'(?i)content-length:\s*(\d+)', headers)
! self.set_terminator(int(match.group(1)))
! self.request = self.request + '\r\n\r\n'
! return
!
! if type(self.get_terminator()) is type(1):
! # We've just read the body of a POSTed request.
! self.set_terminator('\r\n\r\n')
! body = self.request.split('\r\n\r\n', 1)[1]
! match = re.search(r'(?i)content-type:\s*([^\r\n]+)', headers)
! contentTypeHeader = match.group(1)
! contentType, pdict = cgi.parse_header(contentTypeHeader)
! if contentType == 'multipart/form-data':
! # multipart/form-data - probably a file upload.
! bodyFile = cStringIO.StringIO(body)
! params.update(cgi.parse_multipart(bodyFile, pdict))
! else:
! # A normal x-www-form-urlencoded.
! params.update(cgi.parse_qs(body, keep_blank_values=True))
!
! # Convert the cgi params into a simple dictionary.
! plainParams = {}
! for name, value in params.iteritems():
! plainParams[name] = value[0]
! self.onRequest(path, plainParams)
! self.close_when_done()
!
! def onRequest(self, path, params):
! """Handles a decoded HTTP request."""
! if path == '/':
! path = '/Home'
!
! if path == '/helmet.gif':
! self.pushOKHeaders('image/gif')
! self.push(self.helmet)
! else:
! try:
! name = path[1:].capitalize()
! handler = getattr(self, 'on' + name)
! except AttributeError:
! self.pushError(404, "Not found: '%s'" % url)
! else:
! # This is a request for a valid page; run the handler.
! self.pushOKHeaders('text/html')
! self.pushPreamble(name)
! handler(params)
! timeString = time.asctime(time.localtime())
! self.push(self.footer % timeString)
!
! def pushOKHeaders(self, contentType):
! self.push("HTTP/1.0 200 OK\r\n")
! self.push("Content-Type: %s\r\n" % contentType)
! self.push("\r\n")
!
! def pushError(self, code, message):
! self.push("HTTP/1.0 %d Error\r\n" % code)
! self.push("Content-Type: text/html\r\n")
! self.push("\r\n")
! self.push("<html><body><p>%d %s</p></body></html>" % (code, message))
!
! def pushPreamble(self, name):
! self.push(self.header % name)
! if name == 'Home':
! homeLink = name
! else:
! homeLink = "<a href='/'>Home</a> > %s" % name
! self.push(self.bodyStart % homeLink)
!
! def onHome(self, params):
! summary = """POP3 proxy running on port <b>%(proxyPort)d</b>,
! proxying to <b>%(serverName)s:%(serverPort)d</b>.<br>
! Active POP3 conversations: <b>%(activeSessions)d</b>.<br>
! POP3 conversations this session:
! <b>%(totalSessions)d</b>.<br>
! Emails classified this session: <b>%(numSpams)d</b> spam,
! <b>%(numHams)d</b> ham, <b>%(numUnsure)d</b> unsure.
! """ % status.__dict__
!
! train = """<form action='/upload' method='POST'
! enctype='multipart/form-data'>
! Either upload a message file:
! <input type='file' name='file'><br>
! Or paste the whole message (incuding headers) here:<br>
! <textarea name='text' rows='3' cols='60'></textarea><br>
! Is this message
! <input type='radio' name='which' value='ham'>Ham</input> or
! <input type='radio'
! name='which' value='spam' checked>Spam</input>?<br>
! <input type='submit' value='Train on this message'>
! </form>"""
!
! body = (self.pageSection % ('Status', summary) +
! self.pageSection % ('Word query', self.wordQuery) +
! self.pageSection % ('Train', train))
! self.push(body)
!
! def onShutdown(self, params):
! self.push("<p><b>Shutdown.</b> Goodbye.</p>")
! self.push(' ') # Acts as a flush for small buffers.
! self.shutdown(2)
! self.close()
! raise SystemExit
!
! def onUpload(self, params):
! message = params.get('file') or params.get('text')
! isSpam = (params['which'] == 'spam')
! self.bayes.learn(tokenizer.tokenize(message), isSpam, True)
! self.push("""<p>Trained on your message. Saving database...</p>""")
! self.push(" ") # Flush... must find out how to do this properly...
! if not status.useDB and status.pickleName:
! fp = open(status.pickleName, 'wb')
! cPickle.dump(self.bayes, fp, 1)
! fp.close()
! self.push("<p>Done.</p><p><a href='/'>Home</a></p>")
!
! def onWordquery(self, params):
! word = params['word']
! try:
! # Must be a better way to get __dict__ for a new-style class...
! wi = self.bayes.wordinfo[word]
! members = dict(map(lambda n: (n, getattr(wi, n)), wi.__slots__))
! members['atime'] = time.asctime(time.localtime(members['atime']))
! info = """Number of spam messages: <b>%(spamcount)d</b>.<br>
! Number of ham messages: <b>%(hamcount)d</b>.<br>
! Number of times used to classify: <b>%(killcount)s</b>.<br>
! Probability that a message containing this word is spam:
! <b>%(spamprob)f</b>.<br>
! Last used: <b>%(atime)s</b>.<br>""" % members
! except KeyError:
! info = "'%s' does not appear in the database." % word
!
! body = (self.pageSection % ("Statistics for '%s':" % word, info) +
! self.pageSection % ('Word query', self.wordQuery))
! self.push(body)
!
!
! def main(serverName, serverPort, proxyPort,
! uiPort, launchUI, pickleName, useDB):
"""Runs the proxy forever or until a 'KILL' command is received or
someone hits Ctrl+Break."""
***************
*** 375,378 ****
--- 649,655 ----
print "Done."
BayesProxyListener(serverName, serverPort, proxyPort, bayes)
+ UserInterfaceListener(uiPort, bayes)
+ if launchUI:
+ webbrowser.open_new("http://localhost:%d/" % uiPort)
asyncore.loop()
***************
*** 424,430 ****
! class TestPOP3Server(asynchat.async_chat):
! """Minimal POP3 server, for testing purposes. Doesn't support TOP
! or UIDL. USER, PASS, APOP, DELE and RSET simply return "+OK"
without doing anything. Also understands the 'KILL' command, to
kill it. The mail content is the example messages above.
--- 701,707 ----
! class TestPOP3Server(BrighterAsyncChat):
! """Minimal POP3 server, for testing purposes. Doesn't support
! UIDL. USER, PASS, APOP, DELE and RSET simply return "+OK"
without doing anything. Also understands the 'KILL' command, to
kill it. The mail content is the example messages above.
***************
*** 434,439 ****
# Grumble: asynchat.__init__ doesn't take a 'map' argument,
# hence the two-stage construction.
! asynchat.async_chat.__init__(self)
! asynchat.async_chat.set_socket(self, clientSocket, socketMap)
self.maildrop = [spam1, good1]
self.set_terminator('\r\n')
--- 711,716 ----
# Grumble: asynchat.__init__ doesn't take a 'map' argument,
# hence the two-stage construction.
! BrighterAsyncChat.__init__(self)
! BrighterAsyncChat.set_socket(self, clientSocket, socketMap)
self.maildrop = [spam1, good1]
self.set_terminator('\r\n')
***************
*** 442,453 ****
self.handlers = {'STAT': self.onStat,
'LIST': self.onList,
! 'RETR': self.onRetr}
self.push("+OK ready\r\n")
self.request = ''
- def handle_connect(self):
- """Suppress the asyncore "unhandled connect event" warning."""
- pass
-
def collect_incoming_data(self, data):
"""Asynchat override."""
--- 719,727 ----
self.handlers = {'STAT': self.onStat,
'LIST': self.onList,
! 'RETR': self.onRetr,
! 'TOP': self.onTop}
self.push("+OK ready\r\n")
self.request = ''
def collect_incoming_data(self, data):
"""Asynchat override."""
***************
*** 466,469 ****
--- 740,745 ----
self.close_when_done()
if command == 'KILL':
+ self.shutdown(2)
+ self.close()
raise SystemExit
else:
***************
*** 472,483 ****
self.request = ''
- def handle_error(self):
- """Let SystemExit cause an exit."""
- type, v, t = sys.exc_info()
- if type == SystemExit:
- raise
- else:
- asynchat.async_chat.handle_error(self)
-
def onStat(self, command, args):
"""POP3 STAT command."""
--- 748,751 ----
***************
*** 502,514 ****
return '\r\n'.join(returnLines) + '\r\n'
! def onRetr(self, command, args):
! """POP3 RETR command."""
! number = int(args)
if 0 < number <= len(self.maildrop):
message = self.maildrop[number-1]
return "+OK\r\n%s\r\n.\r\n" % message
else:
return "-ERR no such message\r\n"
def onUnknown(self, command, args):
"""Unknown POP3 command."""
--- 770,793 ----
return '\r\n'.join(returnLines) + '\r\n'
! def _getMessage(self, number, maxLines):
! """Implements the POP3 RETR and TOP commands."""
if 0 < number <= len(self.maildrop):
message = self.maildrop[number-1]
+ headers, body = message.split('\n\n', 1)
+ bodyLines = body.split('\n')[:maxLines]
+ message = headers + '\r\n\r\n' + '\n'.join(bodyLines)
return "+OK\r\n%s\r\n.\r\n" % message
else:
return "-ERR no such message\r\n"
+ def onRetr(self, command, args):
+ """POP3 RETR command."""
+ return self._getMessage(int(args), 12345)
+
+ def onTop(self, command, args):
+ """POP3 RETR command."""
+ number, lines = map(int, args.split())
+ return self._getMessage(number, lines)
+
def onUnknown(self, command, args):
"""Unknown POP3 command."""
***************
*** 564,568 ****
while response.find('\n.\r\n') == -1:
response = response + proxy.recv(1000)
! assert response.find(hammie.DISPHEADER) != -1
# Kill the proxy and the test server.
--- 843,847 ----
while response.find('\n.\r\n') == -1:
response = response + proxy.recv(1000)
! assert response.find(options.hammie_header_name) != -1
# Kill the proxy and the test server.
***************
*** 580,592 ****
# Read the arguments.
try:
! opts, args = getopt.getopt(sys.argv[1:], 'htdp:l:')
except getopt.error, msg:
print >>sys.stderr, str(msg) + '\n\n' + __doc__
sys.exit()
! pickleName = hammie.DEFAULTDB
! proxyPort = 110
! useDB = False
! runTestServer = False
for opt, arg in opts:
if opt == '-h':
--- 859,880 ----
# Read the arguments.
try:
! opts, args = getopt.getopt(sys.argv[1:], 'htdbp:l:u:')
except getopt.error, msg:
print >>sys.stderr, str(msg) + '\n\n' + __doc__
sys.exit()
! status.pickleName = hammie.DEFAULTDB
! status.proxyPort = 110
! status.uiPort = 8880
! status.serverPort = 110
! status.useDB = False
! status.runTestServer = False
! status.launchUI = False
! status.totalSessions = 0
! status.activeSessions = 0
! status.numEmails = 0
! status.numSpams = 0
! status.numHams = 0
! status.numUnsure = 0
for opt, arg in opts:
if opt == '-h':
***************
*** 594,604 ****
sys.exit()
elif opt == '-t':
! runTestServer = True
elif opt == '-d':
! useDB = True
elif opt == '-p':
! pickleName = arg
elif opt == '-l':
! proxyPort = int(arg)
# Do whatever we've been asked to do...
--- 882,896 ----
sys.exit()
elif opt == '-t':
! status.runTestServer = True
! elif opt == '-b':
! status.launchUI = True
elif opt == '-d':
! status.useDB = True
elif opt == '-p':
! status.pickleName = arg
elif opt == '-l':
! status.proxyPort = int(arg)
! elif opt == '-u':
! status.uiPort = int(arg)
# Do whatever we've been asked to do...
***************
*** 608,623 ****
print "Self-test passed." # ...else it would have asserted.
! elif runTestServer:
print "Running a test POP3 server on port 8110..."
TestListener()
asyncore.loop()
! elif len(args) == 1:
! # Named POP3 server, default port.
! main(args[0], 110, proxyPort, pickleName, useDB)
!
! elif len(args) == 2:
! # Named POP3 server, named port.
! main(args[0], int(args[1]), proxyPort, pickleName, useDB)
else:
--- 900,915 ----
print "Self-test passed." # ...else it would have asserted.
! elif status.runTestServer:
print "Running a test POP3 server on port 8110..."
TestListener()
asyncore.loop()
! elif 1 <= len(args) <= 2:
! # Normal usage, with optional server port number.
! status.serverName = args[0]
! if len(args) == 2:
! status.serverPort = int(args[1])
! main(status.serverName, status.serverPort, status.proxyPort,
! status.uiPort, status.launchUI, status.pickleName, status.useDB)
else: