Update of /cvsroot/spambayes/spambayes/spambayes
In directory sc8-pr-cvs8.sourceforge.net:/tmp/cvs-serv7512/spambayes
Modified Files:
Options.py ProxyUI.py UserInterface.py dnscache.py storage.py
Added Files:
CorePlugin.py CoreUI.py XMLRPCPlugin.py
Log Message:
Merge CORESVR branch to HEAD. This adds a new app, scripts/core_server.py
and attendant bits, such as an XML-RPC plugin. The web interface is
straight from the POP3 proxy server.
Index: Options.py
===================================================================
RCS file: /cvsroot/spambayes/spambayes/spambayes/Options.py,v
retrieving revision 1.141
retrieving revision 1.142
diff -C2 -d -r1.141 -r1.142
*** Options.py 26 Mar 2007 07:57:13 -0000 1.141
--- Options.py 10 Jun 2007 15:27:36 -0000 1.142
***************
*** 653,656 ****
--- 653,671 ----
PATH, DO_NOT_RESTORE),
+ ("core_spam_cache", _("Spam cache directory"), "core-spam-cache",
+ _("""Directory that SpamBayes should cache spam in. If this does
+ not exist, it will be created."""),
+ PATH, DO_NOT_RESTORE),
+
+ ("core_ham_cache", _("Ham cache directory"), "core-ham-cache",
+ _("""Directory that SpamBayes should cache ham in. If this does
+ not exist, it will be created."""),
+ PATH, DO_NOT_RESTORE),
+
+ ("core_unknown_cache", _("Unknown cache directory"), "core-unknown-cache",
+ _("""Directory that SpamBayes should cache unclassified messages in.
+ If this does not exist, it will be created."""),
+ PATH, DO_NOT_RESTORE),
+
("cache_messages", _("Cache messages"), True,
_("""You can disable the pop3proxy caching of messages. This
***************
*** 1280,1283 ****
--- 1295,1309 ----
r"\w\w(?:_\w\w)?", RESTORE),
),
+ "Plugin": (
+ ("xmlrpc_path", _("XML-RPC path"), "/sbrpc",
+ _("""The path to respond to."""),
+ r"[\w]+", RESTORE),
+ ("xmlrpc_host", _("XML-RPC host"), "localhost",
+ _("""The host to listen on."""),
+ SERVER, RESTORE),
+ ("xmlrpc_port", _("XML-RPC port"), 8001,
+ _("""The port to listen on."""),
+ r"[\d]+", RESTORE),
+ ),
}
Index: ProxyUI.py
===================================================================
RCS file: /cvsroot/spambayes/spambayes/spambayes/ProxyUI.py,v
retrieving revision 1.64
retrieving revision 1.65
diff -C2 -d -r1.64 -r1.65
*** ProxyUI.py 28 Nov 2005 10:54:18 -0000 1.64
--- ProxyUI.py 10 Jun 2007 15:27:36 -0000 1.65
***************
*** 54,58 ****
True, False = 1, 0
- import re
import cgi
import time
--- 54,57 ----
***************
*** 72,81 ****
from spambayes.compatsets import Set
- import tokenizer
import UserInterface
from spambayes.Options import options, _
- from email.Iterators import typed_subpart_iterator
! global state
# These are the options that will be offered on the configuration page.
--- 71,78 ----
from spambayes.compatsets import Set
import UserInterface
from spambayes.Options import options, _
! state = None
# These are the options that will be offered on the configuration page.
***************
*** 111,115 ****
)
! # Like the above, but hese are the options that will be offered on the
# advanced configuration page.
adv_map = (
--- 108,112 ----
)
! # Like the above, but these are the options that will be offered on the
# advanced configuration page.
adv_map = (
***************
*** 174,178 ****
self.state_recreator = state_recreator # ugly
self.app_for_version = "SpamBayes Proxy"
- self.previous_sort = None
if not proxy_state.can_stop:
self.html._readonly = False
--- 171,174 ----
***************
*** 221,241 ****
self.write(_("<p>OK. Return <a href='home'>Home</a>.</p>"))
- def _keyToTimestamp(self, key):
- """Given a message key (as seen in a Corpus), returns the timestamp
- for that message. This is the time that the message was received,
- not the Date header."""
- return long(key[:10])
-
- def _getTimeRange(self, timestamp):
- """Given a unix timestamp, returns a 3-tuple: the start timestamp
- of the given day, the end timestamp of the given day, and the
- formatted date of the given day."""
- this = time.localtime(timestamp)
- start = (this[0], this[1], this[2], 0, 0, 0, this[6], this[7],
this[8])
- end = time.localtime(time.mktime(start) + 36*60*60)
- end = (end[0], end[1], end[2], 0, 0, 0, end[6], end[7], end[8])
- date = time.strftime("%A, %B %d, %Y", start)
- return time.mktime(start), time.mktime(end), date
-
def _buildReviewKeys(self, timestamp):
"""Builds an ordered list of untrained message keys, ready for output
--- 217,220 ----
***************
*** 278,382 ****
return keys, date, prior, start, end
- def _sortMessages(self, messages, sort_order, reverse=False):
- """Sorts the message by the appropriate attribute. If this was the
- previous sort order, then reverse it."""
- if sort_order is None or sort_order == "received":
- # Default sorting, which is in reverse order of appearance.
- # This is complicated because the 'received' info is the key.
- messages.sort()
- if self.previous_sort == sort_order:
- messages.reverse()
- self.previous_sort = None
- else:
- self.previous_sort = 'received'
- return messages
- tmplist = [(getattr(x[1], sort_order), x) for x in messages]
- tmplist.sort()
- if reverse:
- tmplist.reverse()
- return [x for (key, x) in tmplist]
-
- def _appendMessages(self, table, keyedMessageInfo, label, sort_order,
- reverse=False):
- """Appends the rows of a table of messages to 'table'."""
- stripe = 0
-
- keyedMessageInfo = self._sortMessages(keyedMessageInfo, sort_order,
- reverse)
- nrows = options["html_ui", "rows_per_section"]
- for key, messageInfo in keyedMessageInfo[:nrows]:
- unused, unused, messageInfo.received = \
- self._getTimeRange(self._keyToTimestamp(key))
- row = self.html.reviewRow.clone()
- try:
- score = messageInfo.score
- except ValueError:
- score = None
- if label == _('Spam'):
- if score is not None \
- and score > options["html_ui", "spam_discard_level"]:
- r_att = getattr(row, 'discard')
- else:
- r_att = getattr(row, options["html_ui",
- "default_spam_action"])
- elif label == _('Ham'):
- if score is not None \
- and score < options["html_ui", "ham_discard_level"]:
- r_att = getattr(row, 'discard')
- else:
- r_att = getattr(row, options["html_ui",
- "default_ham_action"])
- else:
- r_att = getattr(row, options["html_ui",
- "default_unsure_action"])
- setattr(r_att, "checked", 1)
-
- row.optionalHeadersValues = '' # make way for real list
- for header in options["html_ui", "display_headers"]:
- header = header.lower()
- text = getattr(messageInfo, "%sHeader" % (header,))
- if header == "subject":
- # Subject is special, because it links to the body.
- # If the user doesn't display the subject, then there
- # is no link to the body.
- h = self.html.reviewRow.linkedHeaderValue.clone()
- h.text.title = messageInfo.bodySummary
- h.text.href = "view?key=%s&corpus=%s" % (key, label)
- else:
- h = self.html.reviewRow.headerValue.clone()
- h.text = text
- row.optionalHeadersValues += h
-
- # Apart from any message headers, we may also wish to display
- # the message score, and the time the message was received.
- if options["html_ui", "display_score"]:
- if isinstance(messageInfo.score, types.StringTypes):
- # Presumably either "?" or "Err".
- row.score_ = messageInfo.score
- else:
- row.score_ = "%.2f%%" % (messageInfo.score,)
- else:
- del row.score_
- if options["html_ui", "display_received_time"]:
- row.received_ = messageInfo.received
- else:
- del row.received_
-
- # Many characters can't go in the URL or they cause problems
- # (&, ;, ?, etc). So we use the hex values for them all.
- subj_list = []
- for c in messageInfo.subjectHeader:
- subj_list.append("%%%s" % (hex(ord(c))[2:],))
- subj = "".join(subj_list)
- row.classify.href="showclues?key=%s&subject=%s" % (key, subj)
- row.tokens.href="showclues?key=%s&subject=%s&tokens=1" % (key,
subj)
- setattr(row, 'class', ['stripe_on', 'stripe_off'][stripe]) # Grr!
- setattr(row, 'onMouseOut',
- ["this.className='stripe_on';",
- "this.className='stripe_off';"][stripe])
- row = str(row).replace('TYPE', label).replace('KEY', key)
- table += row
- stripe = stripe ^ 1
-
def onReview(self, **params):
"""Present a list of message for (re)training."""
--- 257,260 ----
***************
*** 619,626 ****
sh.optionalHeaders = ''
h = self.html.headerHeader.clone()
! for header in options["html_ui", "display_headers"]:
h.headerLink.href = 'review?sort=%sHeader' % \
! (header.lower(),)
! h.headerName = header.title()
sh.optionalHeaders += h
if not options["html_ui", "display_score"]:
--- 497,504 ----
sh.optionalHeaders = ''
h = self.html.headerHeader.clone()
! for disp_header in options["html_ui", "display_headers"]:
h.headerLink.href = 'review?sort=%sHeader' % \
! (disp_header.lower(),)
! h.headerName = disp_header.title()
sh.optionalHeaders += h
if not options["html_ui", "display_score"]:
***************
*** 649,661 ****
self._writePostamble(help_topic="review")
- def _contains(self, a, b, ignore_case=False):
- """Return true if substring b is part of string a."""
- assert isinstance(a, types.StringTypes)
- assert isinstance(b, types.StringTypes)
- if ignore_case:
- a = a.lower()
- b = b.lower()
- return a.find(b) >= 0
-
def onView(self, key, corpus):
"""View a message - linked from the Review page."""
--- 527,530 ----
***************
*** 702,769 ****
self._writePostamble()
- def _makeMessageInfo(self, message):
- """Given an email.Message, return an object with subjectHeader,
- bodySummary and other header (as needed) attributes. These objects
- are passed into appendMessages by onReview - passing email.Message
- objects directly uses too much memory.
- """
- # Remove notations before displaying - see:
- # [ 848365 ] Remove subject annotations from message review page
- message.delNotations()
- subjectHeader = message["Subject"] or "(none)"
- headers = {"subject" : subjectHeader}
- for header in options["html_ui", "display_headers"]:
- headers[header.lower()] = (message[header] or "(none)")
- score = message[options["Headers", "score_header_name"]]
- if score:
- # the score might have the log info at the end
- op = score.find('(')
- if op >= 0:
- score = score[:op]
- try:
- score = float(score) * 100
- except ValueError:
- # Hmm. The score header should only contain a floating
- # point number. What's going on here, then?
- score = "Err" # Let the user know something is wrong.
- else:
- # If the lookup fails, this means that the "include_score"
- # option isn't activated. We have the choice here to either
- # calculate it now, which is pretty inefficient, since we have
- # already done so, or to admit that we don't know what it is.
- # We'll go with the latter.
- score = "?"
- try:
- part = typed_subpart_iterator(message, 'text', 'plain').next()
- text = part.get_payload()
- except StopIteration:
- try:
- part = typed_subpart_iterator(message, 'text', 'html').next()
- text = part.get_payload()
- text, unused = tokenizer.crack_html_style(text)
- text, unused = tokenizer.crack_html_comment(text)
- text = tokenizer.html_re.sub(' ', text)
- text = _('(this message only has an HTML body)\n') + text
- except StopIteration:
- text = _('(this message has no text body)')
- if type(text) == type([]): # gotta be a 'right' way to do this
- text = _("(this message is a digest of %s messages)") %
(len(text))
- elif text is None:
- text = _("(this message has no body)")
- else:
- text = text.replace(' ', ' ') # Else they'll be quoted
- text = re.sub(r'(\s)\s+', r'\1', text) # Eg. multiple blank lines
- text = text.strip()
-
- class _MessageInfo:
- pass
- messageInfo = _MessageInfo()
- for headerName, headerValue in headers.items():
- headerValue = self._trimHeader(headerValue, 45, True)
- setattr(messageInfo, "%sHeader" % (headerName,), headerValue)
- messageInfo.score = score
- messageInfo.bodySummary = self._trimHeader(text, 200)
- return messageInfo
-
def close_database(self):
state.close()
--- 571,574 ----
Index: UserInterface.py
===================================================================
RCS file: /cvsroot/spambayes/spambayes/spambayes/UserInterface.py,v
retrieving revision 1.61
retrieving revision 1.62
diff -C2 -d -r1.61 -r1.62
*** UserInterface.py 28 Nov 2005 10:53:12 -0000 1.61
--- UserInterface.py 10 Jun 2007 15:27:36 -0000 1.62
***************
*** 80,83 ****
--- 80,84 ----
import types
import StringIO
+ from email.Iterators import typed_subpart_iterator
import oe_mailbox
***************
*** 277,280 ****
--- 278,282 ----
self.stats = stats
self.app_for_version = None # subclasses must fill this in
+ self.previous_sort = None
def onClassify(self, file, text, which):
***************
*** 820,823 ****
--- 822,827 ----
elif parms["how"] == _("Save experimental options"):
pmap = experimental_ini_map
+ elif parms["how"] == _("Save plugin options"):
+ pmap = self.plugin_ini_map
del parms["how"]
html = self._getHTMLClone()
***************
*** 1251,1252 ****
--- 1255,1448 ----
lines.append(''.join(cur_line))
return lines
+
+ def _keyToTimestamp(self, key):
+ """Given a message key (as seen in a Corpus), returns the timestamp
+ for that message. This is the time that the message was received,
+ not the Date header."""
+ return long(key[:10])
+
+ def _getTimeRange(self, timestamp):
+ """Given a unix timestamp, returns a 3-tuple: the start timestamp
+ of the given day, the end timestamp of the given day, and the
+ formatted date of the given day."""
+ this = time.localtime(timestamp)
+ start = (this[0], this[1], this[2], 0, 0, 0, this[6], this[7],
this[8])
+ end = time.localtime(time.mktime(start) + 36*60*60)
+ end = (end[0], end[1], end[2], 0, 0, 0, end[6], end[7], end[8])
+ date = time.strftime("%A, %B %d, %Y", start)
+ return time.mktime(start), time.mktime(end), date
+
+ def _sortMessages(self, messages, sort_order, reverse=False):
+ """Sorts the message by the appropriate attribute. If this was the
+ previous sort order, then reverse it."""
+ if sort_order is None or sort_order == "received":
+ # Default sorting, which is in reverse order of appearance.
+ # This is complicated because the 'received' info is the key.
+ messages.sort()
+ if self.previous_sort == sort_order:
+ messages.reverse()
+ self.previous_sort = None
+ else:
+ self.previous_sort = 'received'
+ return messages
+ tmplist = [(getattr(x[1], sort_order), x) for x in messages]
+ tmplist.sort()
+ if reverse:
+ tmplist.reverse()
+ return [x for (key, x) in tmplist]
+
+ def _appendMessages(self, table, keyedMessageInfo, label, sort_order,
+ reverse=False):
+ """Appends the rows of a table of messages to 'table'."""
+ stripe = 0
+
+ keyedMessageInfo = self._sortMessages(keyedMessageInfo, sort_order,
+ reverse)
+ nrows = options["html_ui", "rows_per_section"]
+ for key, messageInfo in keyedMessageInfo[:nrows]:
+ unused, unused, messageInfo.received = \
+ self._getTimeRange(self._keyToTimestamp(key))
+ row = self.html.reviewRow.clone()
+ try:
+ score = messageInfo.score
+ except ValueError:
+ score = None
+ if label == _('Spam'):
+ if score is not None \
+ and score > options["html_ui", "spam_discard_level"]:
+ r_att = getattr(row, 'discard')
+ else:
+ r_att = getattr(row, options["html_ui",
+ "default_spam_action"])
+ elif label == _('Ham'):
+ if score is not None \
+ and score < options["html_ui", "ham_discard_level"]:
+ r_att = getattr(row, 'discard')
+ else:
+ r_att = getattr(row, options["html_ui",
+ "default_ham_action"])
+ else:
+ r_att = getattr(row, options["html_ui",
+ "default_unsure_action"])
+ setattr(r_att, "checked", 1)
+
+ row.optionalHeadersValues = '' # make way for real list
+ for header in options["html_ui", "display_headers"]:
+ header = header.lower()
+ text = getattr(messageInfo, "%sHeader" % (header,))
+ if header == "subject":
+ # Subject is special, because it links to the body.
+ # If the user doesn't display the subject, then there
+ # is no link to the body.
+ h = self.html.reviewRow.linkedHeaderValue.clone()
+ h.text.title = messageInfo.bodySummary
+ h.text.href = "view?key=%s&corpus=%s" % (key, label)
+ else:
+ h = self.html.reviewRow.headerValue.clone()
+ h.text = text
+ row.optionalHeadersValues += h
+
+ # Apart from any message headers, we may also wish to display
+ # the message score, and the time the message was received.
+ if options["html_ui", "display_score"]:
+ if isinstance(messageInfo.score, types.StringTypes):
+ # Presumably either "?" or "Err".
+ row.score_ = messageInfo.score
+ else:
+ row.score_ = "%.2f%%" % (messageInfo.score,)
+ else:
+ del row.score_
+ if options["html_ui", "display_received_time"]:
+ row.received_ = messageInfo.received
+ else:
+ del row.received_
+
+ # Many characters can't go in the URL or they cause problems
+ # (&, ;, ?, etc). So we use the hex values for them all.
+ subj_list = []
+ for c in messageInfo.subjectHeader:
+ subj_list.append("%%%s" % (hex(ord(c))[2:],))
+ subj = "".join(subj_list)
+ row.classify.href = "showclues?key=%s&subject=%s" % (key, subj)
+ row.tokens.href = ("showclues?key=%s&subject=%s&tokens=1" %
+ (key, subj))
+ setattr(row, 'class', ['stripe_on', 'stripe_off'][stripe]) # Grr!
+ setattr(row, 'onMouseOut',
+ ["this.className='stripe_on';",
+ "this.className='stripe_off';"][stripe])
+ row = str(row).replace('TYPE', label).replace('KEY', key)
+ table += row
+ stripe = stripe ^ 1
+
+ def _contains(self, a, b, ignore_case=False):
+ """Return true if substring b is part of string a."""
+ assert isinstance(a, types.StringTypes)
+ assert isinstance(b, types.StringTypes)
+ if ignore_case:
+ a = a.lower()
+ b = b.lower()
+ return a.find(b) >= 0
+
+ def _makeMessageInfo(self, message):
+ """Given an email.Message, return an object with subjectHeader,
+ bodySummary and other header (as needed) attributes. These objects
+ are passed into appendMessages by onReview - passing email.Message
+ objects directly uses too much memory.
+ """
+ # Remove notations before displaying - see:
+ # [ 848365 ] Remove subject annotations from message review page
+ message.delNotations()
+ subjectHeader = message["Subject"] or "(none)"
+ headers = {"subject" : subjectHeader}
+ for header in options["html_ui", "display_headers"]:
+ headers[header.lower()] = (message[header] or "(none)")
+ score = message[options["Headers", "score_header_name"]]
+ if score:
+ # the score might have the log info at the end
+ op = score.find('(')
+ if op >= 0:
+ score = score[:op]
+ try:
+ score = float(score) * 100
+ except ValueError:
+ # Hmm. The score header should only contain a floating
+ # point number. What's going on here, then?
+ score = "Err" # Let the user know something is wrong.
+ else:
+ # If the lookup fails, this means that the "include_score"
+ # option isn't activated. We have the choice here to either
+ # calculate it now, which is pretty inefficient, since we have
+ # already done so, or to admit that we don't know what it is.
+ # We'll go with the latter.
+ score = "?"
+ try:
+ part = typed_subpart_iterator(message, 'text', 'plain').next()
+ text = part.get_payload()
+ except StopIteration:
+ try:
+ part = typed_subpart_iterator(message, 'text', 'html').next()
+ text = part.get_payload()
+ text, unused = tokenizer.crack_html_style(text)
+ text, unused = tokenizer.crack_html_comment(text)
+ text = tokenizer.html_re.sub(' ', text)
+ text = _('(this message only has an HTML body)\n') + text
+ except StopIteration:
+ text = _('(this message has no text body)')
+ if type(text) == type([]): # gotta be a 'right' way to do this
+ text = _("(this message is a digest of %s messages)") %
(len(text))
+ elif text is None:
+ text = _("(this message has no body)")
+ else:
+ text = text.replace(' ', ' ') # Else they'll be quoted
+ text = re.sub(r'(\s)\s+', r'\1', text) # Eg. multiple blank lines
+ text = text.strip()
+
+ class _MessageInfo:
+ pass
+ messageInfo = _MessageInfo()
+ for headerName, headerValue in headers.items():
+ headerValue = self._trimHeader(headerValue, 45, True)
+ setattr(messageInfo, "%sHeader" % (headerName,), headerValue)
+ messageInfo.score = score
+ messageInfo.bodySummary = self._trimHeader(text, 200)
+ return messageInfo
Index: dnscache.py
===================================================================
RCS file: /cvsroot/spambayes/spambayes/spambayes/dnscache.py,v
retrieving revision 1.3
retrieving revision 1.4
diff -C2 -d -r1.3 -r1.4
*** dnscache.py 13 Aug 2006 02:05:43 -0000 1.3
--- dnscache.py 10 Jun 2007 15:27:36 -0000 1.4
***************
*** 23,29 ****
kCheckForPruneEvery=20
! kMaxTTL=60 * 60 * 24 * 7 # One week
! kPruneThreshold=1500 # May go over slightly; numbers chosen at random
! kPruneDownTo=1000
--- 23,32 ----
kCheckForPruneEvery=20
! kMaxTTL=60 * 60 * 24 * 7 # One week
! # Some servers always return a TTL of zero. We'll hold onto data a bit
! # longer.
! kMinTTL=24 * 60 * 60 * 1 # one day
! kPruneThreshold=5000 # May go over slightly; numbers chosen at random
! kPruneDownTo=2500
***************
*** 89,97 ****
self.dnsTimeout=10
- # Some servers always return a TTL of zero.
- # In those cases, turning this up a bit is
- # probably reasonable.
- self.minTTL=0
-
# end of user-settable attributes
--- 92,95 ----
***************
*** 160,164 ****
c=self.caches[answer.qType]
c[answer.question].remove(answer)
! if len(c[answer.question])==0:
del c[answer.question]
--- 158,162 ----
c=self.caches[answer.qType]
c[answer.question].remove(answer)
! if not c[answer.question]:
del c[answer.question]
***************
*** 180,184 ****
c=self.caches[answer.qType]
c[answer.question].remove(answer)
! if len(c[answer.question])==0:
del c[answer.question]
--- 178,182 ----
c=self.caches[answer.qType]
c[answer.question].remove(answer)
! if not c[answer.question]:
del c[answer.question]
***************
*** 218,233 ****
pass
else:
! assert len(answers)>0
! ind=0
! # No guarantee that expire has already been done
! while ind<len(answers):
! thisAnswer=answers[ind]
! if thisAnswer.expiresAt<now:
! del answers[ind]
! else:
! thisAnswer.lastUsed=now
! ind+=1
! if len(answers)==0:
del cacheToLookIn[question]
else:
--- 216,233 ----
pass
else:
! if answers:
! ind=0
! # No guarantee that expire has already been done
! while ind<len(answers):
! thisAnswer=answers[ind]
! if thisAnswer.expiresAt<now:
! del answers[ind]
! else:
! thisAnswer.lastUsed=now
! ind+=1
! else:
! print >> sys.stderr, "lookup failure:", question
! if not answers:
del cacheToLookIn[question]
else:
***************
*** 250,275 ****
except DNS.Base.DNSError,detail:
if detail.args[0]<>"Timeout":
! print "Error, fixme",detail
! print "Question was",queryQuestion
! print "Origianal question was",question
! print "Type was",qType
objs=[
lookupResult(qType,None,question,self.cacheErrorSecs+now,now) ]
cacheToLookIn[question]=objs # Add to format for return?
return self.formatForReturn(objs)
except socket.gaierror,detail:
! print "DNS connection failure:", self.queryObj.ns, detail
! print "Defaults:", DNS.defaults
objs=[]
for answer in reply.answers:
if answer["typename"]==qType:
! # PyDNS returns TTLs as longs but RFC 1035 says that the
! # TTL value is a signed 32-bit value and must be positive,
! # so it should be safe to coerce it to a Python integer.
! # And anyone who sets a time to live of more than 2^31-1
! # seconds (68 years and change) is drunk.
! # Arguably, I ought to impose a maximum rather than continuing
! # with longs (int(long) returns long in recent versions of
Python).
! ttl=max(min(int(answer["ttl"]),kMaxTTL),self.minTTL)
# RFC 2308 says that you should cache an NXDOMAIN for the
# minimum of the minimum field of the SOA record and the TTL
--- 250,275 ----
except DNS.Base.DNSError,detail:
if detail.args[0]<>"Timeout":
! print >> sys.stderr, "Error, fixme", detail
! print >> sys.stderr, "Question was", queryQuestion
! print >> sys.stderr, "Original question was", question
! print >> sys.stderr, "Type was", qType
objs=[
lookupResult(qType,None,question,self.cacheErrorSecs+now,now) ]
cacheToLookIn[question]=objs # Add to format for return?
return self.formatForReturn(objs)
except socket.gaierror,detail:
! print >> sys.stderr, "DNS connection failure:", self.queryObj.ns,
detail
! print >> sys.stderr, "Defaults:", DNS.defaults
objs=[]
for answer in reply.answers:
if answer["typename"]==qType:
! # PyDNS returns TTLs as longs but RFC 1035 says that the TTL
! # value is a signed 32-bit value and must be positive, so it
! # should be safe to coerce it to a Python integer. And
! # anyone who sets a time to live of more than 2^31-1 seconds
! # (68 years and change) is drunk. Arguably, I ought to
! # impose a maximum rather than continuing with longs
! # (int(long) returns long in recent versions of Python).
! ttl=max(min(int(answer["ttl"]),kMaxTTL),kMinTTL)
# RFC 2308 says that you should cache an NXDOMAIN for the
# minimum of the minimum field of the SOA record and the TTL
***************
*** 279,288 ****
objs.append(item)
! if len(objs)>0:
cacheToLookIn[question]=objs
return self.formatForReturn(objs)
# Probably SERVFAIL or the like
! if len(reply.authority)==0:
objs=[
lookupResult(qType,None,question,self.cacheErrorSecs+now,now) ]
cacheToLookIn[question]=objs
--- 279,288 ----
objs.append(item)
! if objs:
cacheToLookIn[question]=objs
return self.formatForReturn(objs)
# Probably SERVFAIL or the like
! if not reply.authority:
objs=[
lookupResult(qType,None,question,self.cacheErrorSecs+now,now) ]
cacheToLookIn[question]=objs
***************
*** 319,329 ****
"www.seeputofor.com", "www.completegarbage.tv",
"www.tradelinkllc.com"]:
! print "checking", host
now=time.time()
ips=c.lookup(host)
! print ips,time.time()-now
now=time.time()
ips=c.lookup(host)
! print ips,time.time()-now
if ips:
--- 319,329 ----
"www.seeputofor.com", "www.completegarbage.tv",
"www.tradelinkllc.com"]:
! print >> sys.stderr, "checking", host
now=time.time()
ips=c.lookup(host)
! print >> sys.stderr, ips,time.time()-now
now=time.time()
ips=c.lookup(host)
! print >> sys.stderr, ips,time.time()-now
if ips:
***************
*** 331,340 ****
now=time.time()
name=c.lookup(ip,qType="PTR")
! print name,time.time()-now
now=time.time()
name=c.lookup(ip,qType="PTR")
! print name,time.time()-now
else:
! print "unknown"
c.close()
--- 331,340 ----
now=time.time()
name=c.lookup(ip,qType="PTR")
! print >> sys.stderr, name,time.time()-now
now=time.time()
name=c.lookup(ip,qType="PTR")
! print >> sys.stderr, name,time.time()-now
else:
! print >> sys.stderr, "unknown"
c.close()
Index: storage.py
===================================================================
RCS file: /cvsroot/spambayes/spambayes/spambayes/storage.py,v
retrieving revision 1.63
retrieving revision 1.64
diff -C2 -d -r1.63 -r1.64
*** storage.py 11 May 2007 00:23:08 -0000 1.63
--- storage.py 10 Jun 2007 15:27:36 -0000 1.64
***************
*** 721,726 ****
import ZODB
from ZODB.FileStorage import FileStorage
! self.storage = FileStorage(self.db_filename,
! read_only=self.mode=='r')
def load(self):
--- 721,731 ----
import ZODB
from ZODB.FileStorage import FileStorage
! try:
! self.storage = FileStorage(self.db_filename,
! read_only=self.mode=='r')
! except IOError, msg:
! print >> sys.stderr, ("Could not create FileStorage from",
! self.db_filename)
! raise
def load(self):
***************
*** 774,778 ****
from ZODB.POSException import ReadOnlyError
! assert self.closed == False, "Can't store a closed database"
if options["globals", "verbose"]:
--- 779,783 ----
from ZODB.POSException import ReadOnlyError
! assert not self.closed, "Can't store a closed database"
if options["globals", "verbose"]:
_______________________________________________
Spambayes-checkins mailing list
[email protected]
http://mail.python.org/mailman/listinfo/spambayes-checkins