From richiehindle at users.sourceforge.net Tue Jul 1 14:19:11 2003 From: richiehindle at users.sourceforge.net (Richie Hindle) Date: Tue Jul 1 16:19:15 2003 Subject: [Spambayes-checkins] spambayes pop3proxy.py,1.81,1.82 Message-ID: Update of /cvsroot/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv23790 Modified Files: pop3proxy.py Log Message: Prevent the POP3 proxy from including the POP3 trailing dot in the text it sends to the email parser. Cope with the parser adding a boundary marker but no trailing newline when it fixes broken messages. Thanks to Scott Schlesier for these edits. When an exception is raised by the email parser or the classifier, add an exception header to the email and recover. This should prevent broken emails that aren't handled properly by the email parser, or bugs in the classifier, from preventing emails getting through. The exception header should help us track down the problem - here's an example: X-Spambayes-Exception: exceptions.TypeError(string payload expected: ) in _handle_text() at C:\PYTHON23\lib\email\Generator.py line 199: raise TypeError, 'string payload expected: %s' % type(payload) Index: pop3proxy.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/pop3proxy.py,v retrieving revision 1.81 retrieving revision 1.82 diff -C2 -d -r1.81 -r1.82 *** pop3proxy.py 12 Jun 2003 07:25:03 -0000 1.81 --- pop3proxy.py 1 Jul 2003 20:19:09 -0000 1.82 *************** *** 90,94 **** """ ! import os, sys, re, errno, getopt, time import socket from thread import start_new_thread --- 90,94 ---- """ ! import os, sys, re, errno, getopt, time, traceback import socket from thread import start_new_thread *************** *** 418,452 **** # broken emails that don't use the proper line separators. if re.search(r'\n\r?\n', response): # Break off the first line, which will be '+OK'. ok, messageText = response.split('\n', 1) ! msg = spambayes.message.SBHeaderMessage() ! msg.setPayload(messageText) ! msg.setId(state.getNewMessageName()) ! # Now find the spam disposition and add the header. ! (prob, clues) = state.bayes.spamprob(msg.asTokens(),\ ! evidence=True) ! msg.addSBHeaders(prob, clues) ! ! if command == 'RETR': ! cls = msg.GetClassification() ! if cls == options["Hammie", "header_ham_string"]: ! state.numHams += 1 ! elif cls == options["Hammie", "header_spam_string"]: ! state.numSpams += 1 ! else: ! state.numUnsure += 1 ! # Cache the message; don't pollute the cache with test messages. ! if not state.isTest \ ! and options["pop3proxy", "cache_messages"]: ! # Write the message into the Unknown cache. ! message = state.unknownCorpus.makeMessage(msg.getId()) ! message.setSubstance(msg.as_string()) ! state.unknownCorpus.addMessage(message) ! # Return the +OK and the message with the header added. ! return ok + "\n" + msg.as_string() else: --- 418,483 ---- # broken emails that don't use the proper line separators. if re.search(r'\n\r?\n', response): + # Remove the trailing .\r\n before passing to the email parser. + if response[-3:] == '.\r\n': + response = response[:-3] + # Break off the first line, which will be '+OK'. ok, messageText = response.split('\n', 1) ! try: ! msg = spambayes.message.SBHeaderMessage() ! msg.setPayload(messageText) ! msg.setId(state.getNewMessageName()) ! # Now find the spam disposition and add the header. ! (prob, clues) = state.bayes.spamprob(msg.asTokens(),\ ! evidence=True) ! msg.addSBHeaders(prob, clues) ! if command == 'RETR': ! cls = msg.GetClassification() ! if cls == options["Hammie", "header_ham_string"]: ! state.numHams += 1 ! elif cls == options["Hammie", "header_spam_string"]: ! state.numSpams += 1 ! else: ! state.numUnsure += 1 ! # Cache the message; don't pollute the cache with test messages. ! if not state.isTest \ ! and options["pop3proxy", "cache_messages"]: ! # Write the message into the Unknown cache. ! message = state.unknownCorpus.makeMessage(msg.getId()) ! message.setSubstance(msg.as_string()) ! state.unknownCorpus.addMessage(message) ! ! # We'll return the message with the header added. ! messageText = msg.as_string() ! ! except: ! # Something nasty happened while parsing or classifying - ! # report the exception in a hand-appended header and recover. ! # This is one case where an unqualified 'except' is OK, 'cos ! # anything's better than destroying people's email... ! eType, eValue, eTraceback = sys.exc_info() ! file, line, func, code = traceback.extract_tb(eTraceback)[-1] ! details = "%s(%s) in %s() at %s line %d: %s" % \ ! (eType, eValue, func, file, line, code) ! exceptionHeader = 'X-Spambayes-Exception: %s\r\n' % details ! headers, body = re.split(r'\n\r?\n', messageText, 1) ! headers = headers + "\n" + exceptionHeader + "\r\n" ! messageText = headers + body ! ! # Restore the +OK and the full POP3 \r\n.\r\n terminator. We ! # need to make sure the first \r\n is there as well as the ! # trailing .\r\n because the email parser can fix broken messages ! # by adding a trailing boundary without a \r\n. Thanks to Scott ! # Schlesier for this fix. ! retval = ok + "\n" + messageText ! if retval[-2:] == '\r\n': ! retval += '.\r\n' ! else: ! retval += '\r\n.\r\n' ! return retval else: *************** *** 713,717 **** CreateProxies(servers, proxyPorts, state) LoadServerInfo() ! if 0 <= len(args) <= 2: # Normal usage, with optional server name and port number. --- 744,748 ---- CreateProxies(servers, proxyPorts, state) LoadServerInfo() ! if 0 <= len(args) <= 2: # Normal usage, with optional server name and port number. From richie at entrian.com Wed Jul 2 00:07:35 2003 From: richie at entrian.com (Richie Hindle) Date: Tue Jul 1 18:10:04 2003 Subject: [Spambayes-checkins] spambayes pop3proxy.py,1.81,1.82 In-Reply-To: References: Message-ID: > The exception header [...] Here's a less contrived example of an exception that it's good to recover from, and one that's been bugging me for months: X-Spambayes-Exception: exceptions.IOError([Errno 28] No space left on device) in store() at D:\Projects\Python\spambayes\spambayes-july\spambayes\FileCorpus.py line 231: fp.write(self.getSubstance()) Previously, running out of disk space would screw things royally. Since I'm currently the victim of a spammer using my address as his From: address, I'm receiving about 1,500 bounce messages a day - it's easy to run out of disk space on a five-year-old Win98 box when that's happening! -- Richie Hindle richie@entrian.com From mhammond at users.sourceforge.net Tue Jul 1 19:22:56 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Tue Jul 1 21:22:59 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000/installer spambayes_addin.iss, 1.2, 1.3 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000/installer In directory sc8-pr-cvs1:/tmp/cvs-serv3103 Modified Files: spambayes_addin.iss Log Message: Binary version 3. Index: spambayes_addin.iss =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/installer/spambayes_addin.iss,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** spambayes_addin.iss 18 Mar 2003 07:37:32 -0000 1.2 --- spambayes_addin.iss 2 Jul 2003 01:22:54 -0000 1.3 *************** *** 5,10 **** [Setup] AppName=Spambayes Outlook Addin ! AppVerName=Spambayes Outlook Addin 0.0.2 ! AppVersion=0.0.2 DefaultDirName={pf}\Spambayes Outlook Addin DefaultGroupName=Spambayes Outlook Addin --- 5,10 ---- [Setup] AppName=Spambayes Outlook Addin ! AppVerName=Spambayes Outlook Addin 0.3 ! AppVersion=0.3 DefaultDirName={pf}\Spambayes Outlook Addin DefaultGroupName=Spambayes Outlook Addin From richiehindle at users.sourceforge.net Tue Jul 1 20:14:33 2003 From: richiehindle at users.sourceforge.net (Richie Hindle) Date: Tue Jul 1 22:14:37 2003 Subject: [Spambayes-checkins] spambayes pop3proxy.py,1.82,1.83 Message-ID: Update of /cvsroot/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv9597 Modified Files: pop3proxy.py Log Message: Correctly line-wrap the X-Spambayes-Exception header. Index: pop3proxy.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/pop3proxy.py,v retrieving revision 1.82 retrieving revision 1.83 diff -C2 -d -r1.82 -r1.83 *** pop3proxy.py 1 Jul 2003 20:19:09 -0000 1.82 --- pop3proxy.py 2 Jul 2003 02:14:31 -0000 1.83 *************** *** 93,96 **** --- 93,97 ---- import socket from thread import start_new_thread + from email.Header import Header import spambayes.message *************** *** 461,470 **** # anything's better than destroying people's email... eType, eValue, eTraceback = sys.exc_info() file, line, func, code = traceback.extract_tb(eTraceback)[-1] details = "%s(%s) in %s() at %s line %d: %s" % \ (eType, eValue, func, file, line, code) ! exceptionHeader = 'X-Spambayes-Exception: %s\r\n' % details headers, body = re.split(r'\n\r?\n', messageText, 1) ! headers = headers + "\n" + exceptionHeader + "\r\n" messageText = headers + body --- 462,480 ---- # anything's better than destroying people's email... eType, eValue, eTraceback = sys.exc_info() + headerName = 'X-Spambayes-Exception' file, line, func, code = traceback.extract_tb(eTraceback)[-1] + + # Build the header. details = "%s(%s) in %s() at %s line %d: %s" % \ (eType, eValue, func, file, line, code) ! header = Header(details, header_name=headerName, ! continuation_ws='\t') ! ! # Insert the header, fixing up the fact that email.Header ! # splits the lines using \n rather than \r\n (and being ! # paranoid about that possibly changing in the future). headers, body = re.split(r'\n\r?\n', messageText, 1) ! fixed = str(header).replace('\r\n', '\n').replace('\n', '\r\n') ! headers += "\n%s: %s\r\n\r\n" % (headerName, fixed) messageText = headers + body From montanaro at users.sourceforge.net Wed Jul 2 09:45:54 2003 From: montanaro at users.sourceforge.net (Skip Montanaro) Date: Wed Jul 2 11:45:57 2003 Subject: [Spambayes-checkins] website download.ht,1.7,1.8 Message-ID: Update of /cvsroot/spambayes/website In directory sc8-pr-cvs1:/tmp/cvs-serv12799 Modified Files: download.ht Log Message: update version of Mark's installer Index: download.ht =================================================================== RCS file: /cvsroot/spambayes/website/download.ht,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -d -r1.7 -r1.8 *** download.ht 22 Jun 2003 02:00:44 -0000 1.7 --- download.ht 2 Jul 2003 15:45:51 -0000 1.8 *************** *** 29,35 ****

Binary Releases

Outlook Plugin

!

Mark has packaged together an installer for the plugin. You can download it from his website. ! This is currently at version 002.

Other

--- 29,35 ----

Binary Releases

Outlook Plugin

!

Mark has packaged together an installer for the plugin. You can download it from his website. ! This is currently at version 003.

Other

From montanaro at users.sourceforge.net Wed Jul 2 09:48:04 2003 From: montanaro at users.sourceforge.net (Skip Montanaro) Date: Wed Jul 2 11:48:07 2003 Subject: [Spambayes-checkins] website applications.ht,1.10,1.11 Message-ID: Update of /cvsroot/spambayes/website In directory sc8-pr-cvs1:/tmp/cvs-serv13230 Modified Files: applications.ht Log Message: installer 002 -> 003 Index: applications.ht =================================================================== RCS file: /cvsroot/spambayes/website/applications.ht,v retrieving revision 1.10 retrieving revision 1.11 diff -C2 -d -r1.10 -r1.11 *** applications.ht 26 Jun 2003 02:20:44 -0000 1.10 --- applications.ht 2 Jul 2003 15:48:02 -0000 1.11 *************** *** 27,33 ****

Availability

!

Mark has packaged together an installer for the plugin. You can download it from his website. ! This is currently at version 002.

Note that there are some problems with installing the binary on Windows98, WindowsME, and Windows XP; you might have success, but --- 27,33 ----

Availability

!

Mark has packaged together an installer for the plugin. You can download it from his website. ! This is currently at version 003.

Note that there are some problems with installing the binary on Windows98, WindowsME, and Windows XP; you might have success, but From montanaro at users.sourceforge.net Wed Jul 2 09:48:23 2003 From: montanaro at users.sourceforge.net (Skip Montanaro) Date: Wed Jul 2 11:48:25 2003 Subject: [Spambayes-checkins] website windows.ht,1.18,1.19 Message-ID: Update of /cvsroot/spambayes/website In directory sc8-pr-cvs1:/tmp/cvs-serv13265 Modified Files: windows.ht Log Message: installer 002 -> 003 Index: windows.ht =================================================================== RCS file: /cvsroot/spambayes/website/windows.ht,v retrieving revision 1.18 retrieving revision 1.19 diff -C2 -d -r1.18 -r1.19 *** windows.ht 26 Jun 2003 02:20:44 -0000 1.18 --- windows.ht 2 Jul 2003 15:48:21 -0000 1.19 *************** *** 9,13 ****

If you are using Outlook 2000 or Outlook XP (not Outlook Express) you should be able to simply download and run the Outlook plug-in installer. A separate Python installation is not necessary.

--- 9,13 ----

If you are using Outlook 2000 or Outlook XP (not Outlook Express) you should be able to simply download and run the Outlook plug-in installer. A separate Python installation is not necessary.

From richiehindle at users.sourceforge.net Wed Jul 2 12:42:35 2003 From: richiehindle at users.sourceforge.net (Richie Hindle) Date: Wed Jul 2 14:42:39 2003 Subject: [Spambayes-checkins] spambayes pop3proxy.py,1.83,1.84 Message-ID: Update of /cvsroot/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv9471 Modified Files: pop3proxy.py Log Message: Fixed a bug whereby long attachments would be broken by the POP3 proxy. For messages that take a long time to download, the proxy starts to forward them after 30 seconds, regardless of whether it's seen the whole message. It classifies the message using however much of the message it's seen so far. It's done this since the early days, but in the intervening time someone (whose anonimiTy I MuST hONour hEre) has changed it to parse the message and then use the stringified version of the parsed message to forward to the client. The problem is that the parser will 'fix' a partial message by appending a closing boundary separator - this separator can then end up embedded in the middle of a long attachment. We still parse the message and add the Spambayes headers to the parsed message, but we now take just the headers from the parsed message and add the (possible partial) body ourselves. This edit simplifies Scott Schlesier's trailing dot fix, because we no longer need to cope with added boundary separators. Index: pop3proxy.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/pop3proxy.py,v retrieving revision 1.83 retrieving revision 1.84 diff -C2 -d -r1.83 -r1.84 *** pop3proxy.py 2 Jul 2003 02:14:31 -0000 1.83 --- pop3proxy.py 2 Jul 2003 18:42:33 -0000 1.84 *************** *** 420,424 **** if re.search(r'\n\r?\n', response): # Remove the trailing .\r\n before passing to the email parser. ! if response[-3:] == '.\r\n': response = response[:-3] --- 420,426 ---- if re.search(r'\n\r?\n', response): # Remove the trailing .\r\n before passing to the email parser. ! # Thanks to Scott Schlesier for this fix. ! terminatingDotPresent = (response[-4:] == '\n.\r\n') ! if terminatingDotPresent: response = response[:-3] *************** *** 453,458 **** state.unknownCorpus.addMessage(message) ! # We'll return the message with the header added. ! messageText = msg.as_string() except: --- 455,472 ---- state.unknownCorpus.addMessage(message) ! # We'll return the message with the headers added. We take ! # all the headers from the SBHeaderMessage, but take the body ! # directly from the POP3 conversation, because the ! # SBHeaderMessage might have "fixed" a partial message by ! # appending a closing boundary separator. Remember we can ! # be dealing with partial message here because of the timeout ! # code in onServerLine. ! headers = [] ! for name, value in msg.items(): ! enc = Header(value, header_name=name, continuation_ws='\t') ! header = "%s: %s" % (name, str(enc)) ! headers.append(re.sub(r'\r?\n', '\r\n', header)) ! body = re.split(r'\n\r?\n', messageText, 1)[1] ! messageText = "\r\n".join(headers) + "\r\n\r\n" + body except: *************** *** 471,492 **** continuation_ws='\t') ! # Insert the header, fixing up the fact that email.Header ! # splits the lines using \n rather than \r\n (and being ! # paranoid about that possibly changing in the future). headers, body = re.split(r'\n\r?\n', messageText, 1) ! fixed = str(header).replace('\r\n', '\n').replace('\n', '\r\n') ! headers += "\n%s: %s\r\n\r\n" % (headerName, fixed) messageText = headers + body ! # Restore the +OK and the full POP3 \r\n.\r\n terminator. We ! # need to make sure the first \r\n is there as well as the ! # trailing .\r\n because the email parser can fix broken messages ! # by adding a trailing boundary without a \r\n. Thanks to Scott ! # Schlesier for this fix. retval = ok + "\n" + messageText ! if retval[-2:] == '\r\n': retval += '.\r\n' - else: - retval += '\r\n.\r\n' return retval --- 485,499 ---- continuation_ws='\t') ! # Insert the header, converting email.Header's '\n' line ! # breaks to POP3's '\r\n'. headers, body = re.split(r'\n\r?\n', messageText, 1) ! header = re.sub(r'\r?\n', '\r\n', str(header)) ! headers += "\n%s: %s\r\n\r\n" % (headerName, header) messageText = headers + body ! # Restore the +OK and the POP3 .\r\n terminator if there was one. retval = ok + "\n" + messageText ! if terminatingDotPresent: retval += '.\r\n' return retval From richiehindle at users.sourceforge.net Wed Jul 2 13:28:20 2003 From: richiehindle at users.sourceforge.net (Richie Hindle) Date: Wed Jul 2 15:28:23 2003 Subject: [Spambayes-checkins] spambayes/spambayes UserInterface.py, 1.11, 1.12 Message-ID: Update of /cvsroot/spambayes/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv18027 Modified Files: UserInterface.py Log Message: Put the current date and time into the footer of the web interface, rather than always displaying "Mon Dec 30 14:04:32 2002". Index: UserInterface.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/spambayes/UserInterface.py,v retrieving revision 1.11 retrieving revision 1.12 diff -C2 -d -r1.11 -r1.12 *** UserInterface.py 15 May 2003 01:29:11 -0000 1.11 --- UserInterface.py 2 Jul 2003 19:28:17 -0000 1.12 *************** *** 96,100 **** htmlSource, self._images = self.readUIResources() self.html = PyMeldLite.Meld(htmlSource, readonly=True) ! def onIncomingConnection(self, clientSocket): """Checks the security settings.""" --- 96,100 ---- htmlSource, self._images = self.readUIResources() self.html = PyMeldLite.Meld(htmlSource, readonly=True) ! def onIncomingConnection(self, clientSocket): """Checks the security settings.""" *************** *** 140,145 **** """Writes the end of time-consuming pages - see `_writePreamble`.""" footer = self.html.footer.clone() ! footer.timestamp = time.asctime(time.localtime()) ! self.write("" + self.html.footer) self.write("") --- 140,145 ---- """Writes the end of time-consuming pages - see `_writePreamble`.""" footer = self.html.footer.clone() ! footer.timestamp = time.strftime('%H:%M on %A %B %d %Y', time.localtime()) ! self.write("" + footer) self.write("") *************** *** 425,429 **** if options.multiple_values_allowed(sect, opt): if val in options[sect, opt]: ! newOption.input_box.checked = "checked" newOption.input_box.type = "checkbox" newOption.input_box.name = html_key + '-' + str(i) --- 425,429 ---- if options.multiple_values_allowed(sect, opt): if val in options[sect, opt]: ! newOption.input_box.checked = "checked" newOption.input_box.type = "checkbox" newOption.input_box.name = html_key + '-' + str(i) *************** *** 442,449 **** newOption.val_label = str(val) newOption.input_box.value = str(val) ! if firstOpt: newConfigRow1.input = newOption firstOpt = False ! else: newConfigRow1.input += newOption # Insert the help text in a cell --- 442,449 ---- newOption.val_label = str(val) newOption.input_box.value = str(val) ! if firstOpt: newConfigRow1.input = newOption firstOpt = False ! else: newConfigRow1.input += newOption # Insert the help text in a cell *************** *** 455,459 **** newConfigRow2 = configRow2.clone() currentValue = options[sect, opt] ! if type(currentValue) in types.StringTypes: currentValue = currentValue.replace(',', ', ') --- 455,459 ---- newConfigRow2 = configRow2.clone() currentValue = options[sect, opt] ! if type(currentValue) in types.StringTypes: currentValue = currentValue.replace(',', ', ') *************** *** 462,466 **** currentValue = options.unconvert(sect, opt) newConfigRow2 = configRow2.clone() ! # Tim thinks that Yes/No makes more sense than True/False if options.is_boolean(sect, opt): --- 462,466 ---- currentValue = options.unconvert(sect, opt) newConfigRow2 = configRow2.clone() ! # Tim thinks that Yes/No makes more sense than True/False if options.is_boolean(sect, opt): From richiehindle at users.sourceforge.net Wed Jul 2 14:51:52 2003 From: richiehindle at users.sourceforge.net (Richie Hindle) Date: Wed Jul 2 16:51:55 2003 Subject: [Spambayes-checkins] spambayes pop3proxy.py,1.84,1.85 Message-ID: Update of /cvsroot/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv1245 Modified Files: pop3proxy.py Log Message: Removed this: o Lose the trailing dot from cached messages. from the To-do list, thanks to Scott Schlesier's trailing-dot patch. Index: pop3proxy.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/pop3proxy.py,v retrieving revision 1.84 retrieving revision 1.85 diff -C2 -d -r1.84 -r1.85 *** pop3proxy.py 2 Jul 2003 18:42:33 -0000 1.84 --- pop3proxy.py 2 Jul 2003 20:51:49 -0000 1.85 *************** *** 70,74 **** o Cope with the email client timing out and closing the connection. - o Lose the trailing dot from cached messages. --- 70,73 ---- From richiehindle at users.sourceforge.net Wed Jul 2 15:10:44 2003 From: richiehindle at users.sourceforge.net (Richie Hindle) Date: Wed Jul 2 17:10:47 2003 Subject: [Spambayes-checkins] spambayes/spambayes UserInterface.py, 1.12, 1.13 Message-ID: Update of /cvsroot/spambayes/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv5653 Modified Files: UserInterface.py Log Message: Put the current date and time into the footer of the web interface, but this time for *all* the pages. Index: UserInterface.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/spambayes/UserInterface.py,v retrieving revision 1.12 retrieving revision 1.13 diff -C2 -d -r1.12 -r1.13 *** UserInterface.py 2 Jul 2003 19:28:17 -0000 1.12 --- UserInterface.py 2 Jul 2003 21:10:41 -0000 1.13 *************** *** 102,105 **** --- 102,113 ---- clientSocket.getpeername()[0] == clientSocket.getsockname()[0] + def _getHTMLClone(self): + """Gets a clone of the HTML, with the footer timestamped, ready to be + modified and sent to the browser.""" + clone = self.html.clone() + timestamp = time.strftime('%H:%M on %A %B %d %Y', time.localtime()) + clone.footer.timestamp = timestamp + return clone + def _writePreamble(self, name, parent=None, showImage=True): """Writes the HTML for the beginning of a page - time-consuming *************** *** 110,114 **** # Take the whole palette and remove the content and the footer, # leaving the header and an empty body. ! html = self.html.clone() html.mainContent = " " del html.footer --- 118,122 ---- # Take the whole palette and remove the content and the footer, # leaving the header and an empty body. ! html = self._getHTMLClone() html.mainContent = " " del html.footer *************** *** 139,145 **** def _writePostamble(self): """Writes the end of time-consuming pages - see `_writePreamble`.""" ! footer = self.html.footer.clone() ! footer.timestamp = time.strftime('%H:%M on %A %B %d %Y', time.localtime()) ! self.write("" + footer) self.write("") --- 147,151 ---- def _writePostamble(self): """Writes the end of time-consuming pages - see `_writePreamble`.""" ! self.write("" + self._getHTMLClone().footer) self.write("") *************** *** 364,368 **** def onConfig(self): # Start with an empty config form then add the sections. ! html = self.html.clone() # "Save and Shutdown" is confusing here - it means "Save database" # but that's not clear. --- 370,374 ---- def onConfig(self): # Start with an empty config form then add the sections. ! html = self._getHTMLClone() # "Save and Shutdown" is confusing here - it means "Save database" # but that's not clear. *************** *** 491,495 **** if parms.has_key("how"): del parms["how"] ! html = self.html.clone() html.shutdownTableCell = " " html.mainContent = self.html.headedBox.clone() --- 497,501 ---- if parms.has_key("how"): del parms["how"] ! html = self._getHTMLClone() html.shutdownTableCell = " " html.mainContent = self.html.headedBox.clone() *************** *** 531,535 **** self.reReadOptions() ! html = self.html.clone() html.shutdownTableCell = " " html.mainContent = self.html.headedBox.clone() --- 537,541 ---- self.reReadOptions() ! html = self._getHTMLClone() html.shutdownTableCell = " " html.mainContent = self.html.headedBox.clone() From anadelonbrin at users.sourceforge.net Wed Jul 2 19:54:55 2003 From: anadelonbrin at users.sourceforge.net (Tony Meyer) Date: Wed Jul 2 21:54:58 2003 Subject: [Spambayes-checkins] website applications.ht, 1.11, 1.12 download.ht, 1.8, 1.9 faq.txt, 1.7, 1.8 windows.ht, 1.19, 1.20 Message-ID: Update of /cvsroot/spambayes/website In directory sc8-pr-cvs1:/tmp/cvs-serv15778 Modified Files: applications.ht download.ht faq.txt windows.ht Log Message: Remove/update notes about the 002 binary installer not working correctly on various Windows/Outlook combinations. For the moment, I think we believe that all combinations work with the 003 binary, so until we hear otherwise, let's say this. If this changes, we can put the nice tables (etc) back. Add a FAQ about backing up the Outlook plugin data. Update the FAQ about which versions of Outlook the plugin will work with. Add a FAQ about Outlook training, because the FAQ previously read like you had to use one of the other methods even if you used the plugin. Added a FAQ about donating money, based on Tim's comments to the list. Feel free to correct any mistakes! Index: applications.ht =================================================================== RCS file: /cvsroot/spambayes/website/applications.ht,v retrieving revision 1.11 retrieving revision 1.12 diff -C2 -d -r1.11 -r1.12 *** applications.ht 2 Jul 2003 15:48:02 -0000 1.11 --- applications.ht 3 Jul 2003 01:54:52 -0000 1.12 *************** *** 30,38 **** You can download it from his website. This is currently at version 003.

-

Note that there are some problems with installing the binary on - Windows98, WindowsME, and Windows XP; you might have success, but - you might not. A new binary that solves this problem will be released soon - (it should be before the end of May), or alternatively you can use the CVS - version, or alpha3 release.

Download the alpha3 release.

Alternatively, you can use CVS to get the code - go to the CVS page on the project's sourceforge site for more.

--- 30,33 ---- *************** *** 59,63 ****

Requirements

    !
  • Python2.2 or later (2.2.3 recommended)
  • Should work on windows/unix/whatever...
--- 54,58 ----

Requirements

    !
  • Python 2.2 or later (2.2.3 recommended)
  • Should work on windows/unix/whatever...
*************** *** 76,80 ****

Requirements

    !
  • Python2.2 or later (2.2.3 recommended)
  • Should work on windows/unix/whatever... ?
--- 71,75 ----

Requirements

    !
  • Python 2.2 or later (2.2.3 recommended)
  • Should work on windows/unix/whatever... ?
*************** *** 93,97 ****

Requirements

    !
  • Python2.2 or later (2.2.3 recommended)
  • The code is currently Unix-specific.
--- 88,92 ----

Requirements

    !
  • Python 2.2 or later (2.2.3 recommended)
  • The code is currently Unix-specific.
Index: download.ht =================================================================== RCS file: /cvsroot/spambayes/website/download.ht,v retrieving revision 1.8 retrieving revision 1.9 diff -C2 -d -r1.8 -r1.9 *** download.ht 2 Jul 2003 15:45:51 -0000 1.8 --- download.ht 3 Jul 2003 01:54:52 -0000 1.9 *************** *** 3,12 **** Author: SpamBayes -

Note: If you run the Outlook plugin, whether you used the binary - installer or downloaded source, please have a look at the Outlook/Windows compatibility matrix and let us know if you can fill in any - holes.

-

Source Releases

The third pre-release of version 1.0 of the SpamBayes project is available. --- 3,6 ---- Index: faq.txt =================================================================== RCS file: /cvsroot/spambayes/website/faq.txt,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -d -r1.7 -r1.8 *** faq.txt 1 Jul 2003 00:50:11 -0000 1.7 --- faq.txt 3 Jul 2003 01:54:52 -0000 1.8 *************** *** 316,323 **** ----------------------------------------------------- ! The most up to date list of known compatible versions of Outlook may be ! found on the `Windows page`_. ! ! .. _Windows page: http://spambayes.sf.net/windows.html --- 316,323 ---- ----------------------------------------------------- ! The 002 installer for the binary has a number of problems with various ! versions of Outlook/Windows. However, to our knowledge, the 003 installer ! should work with any combination of Windows/Outlook versions. Please ! let us know if this is not the case. *************** *** 360,363 **** --- 360,388 ---- + Can I back up the Outlook database? Should I do this? + ------------------------------------------------------ + + Yes you can do this, and it is a good idea if you don't keep copies of the + mail that you have trained. This way, if your database becomes corrupted, + you will be able to recoved without losing all your data (if you do keep + copies of mail that you train, you can simply recreate the database via + the SpamBayes manager dialog). + + To backup the databases, all you need to do is make a copy of the directory + that SpamBayes keeps its data in. If you need to, you can drop the files + back in to recover from a corrupted database, or for any other reason. + + This directory is located in the "Application Data" directory. On Windows + NT/2000/XP, this will probably be: + + C:\\Documents and Settings\\[username]\\Application Data\\Spambayes + + On other versions of Windows, this will probably be: + + C:\\Windows\\Application Data\\Spambayes + + Note that this folder may be hidden. + + Using Spambayes =============== *************** *** 461,464 **** --- 486,502 ---- + How do I train Spambayes (Outlook plugin)? + ----------------------------------------------- + + Instructions about training the Outlook plugin can be found in the documentation + for the plugin. However, basically what you need to do is move as much spam + as you have into your spam folder, tell the plugin which folder that is and + which folders contain examples of ham, and it will do the rest. + + The plugin does *not* train on all incoming mail. However, if you use the + "Delete as spam" and "Recover from spam" buttons, those messages will be + (re)trained as necessary. + + Do I need to keep spam after it has been trained? If so, for how long? ---------------------------------------------------------------------- *************** *** 623,626 **** --- 661,691 ---- 4. Changed the action to "copy" or "move", rather than "untouched" + + + Do I have to pay for SpamBayes? Can I pay you money if I really want to? + ------------------------------------------------------------------------- + + SpamBayes is free and open-source - there is no charge, and we really + aren't interested in your money (on the other hand, if you want to donate + time towards testing, documenting or development - please sign up!). + + If you really feel that your life would be incomplete without giving some + money towards the project, you have a couple of options. There are some + commercial programs that are based on the SpamBayes code, so you could + purchase one of those; this should give you some additional benefits like + support or greater ease-of-use as well. + + The employer of one of the project's + founders (Tim Peters) paid for the initial research and coding on the + SpamBayes project. Open source does very well at the latter but not so + well at the former (research on statistical algorithms is time-consuming + and tedious, and there's no a priori guarantee of success). One thing the + `Python Software Foundation (PSF)`_ hopes to do in coming years is fund + core research -- but last time they worked out the details, it seemed to + require some funds first . Therefore, if you'd rather contribute + closer to the SpamBayes source, the PSF would be the most appropriate place + to invest your life's savings. + + .. _Python Software Foundation (PSF): http://www.python.org/psf/donations.html Index: windows.ht =================================================================== RCS file: /cvsroot/spambayes/website/windows.ht,v retrieving revision 1.19 retrieving revision 1.20 diff -C2 -d -r1.19 -r1.20 *** windows.ht 2 Jul 2003 15:48:21 -0000 1.19 --- windows.ht 3 Jul 2003 01:54:52 -0000 1.20 *************** *** 12,15 **** --- 12,17 ---- plug-in installer. A separate Python installation is not necessary.

+

Note that all users who installed version 002 of the plugin are recommended to upgrade to the 003 release.

+

The Outlook add-in was developed mostly using Outlook 2000 on Windows 2000 and Win98SE, in Outlook's Internet Mail Only configuration. Those *************** *** 28,88 ****

Compatibility

!

This table lists combinations of Windows and Outlook versions and how the ! Outlook plugin fares with them.

! !

! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
 Win95Win98/98se/MeWin2kWinXP
Outlook 2000unknown3 1.0a2 source ! or CVS works, installer ! 002 fails1 works works
Outlook 2002 (XP)2unknown3
Outlook 2003currently does not work
!

! !

! Notes: !

    !
  1. One very common install problem generates a traceback ! in the logfile with an error message like "no codec search functions ! registered: can't find encoding". At the moment, the only workaround is ! to install Python, download the Spambayes distribution and install the ! plugin from source (see below).
  2. ! !
  3. Outlook XP SP2 is known to work. Earlier versions are ! known to have some issues. If you're having problems and are behind on ! installing service packs from Microsoft (for the OS or for Outlook), ! catch up on that first -- Outlook and OS bugs affect the add-in too! !
  4. ! !
  5. We can use some people to help check out the ! highlighted configurations in the table. If you can help, please send ! your results to spambayes@python.org. Please be ! explicit about the service pack or revision level of the various software ! bits you are using, and how you installed the plugin (using the binary ! installer, from the 1.0a2 distribution, or from CVS).
  6. ! !
!

Installing the Outlook Client From Source

--- 30,38 ----

Compatibility

!

As far as we know, the latest release of the plugin works with all ! versions of Windows and Outlook (Outlook 2003 should have the latest ! Technical Release installed). If you have a problem, please follow ! the bug reporting steps above; we will endeavour to keep this page ! up to date.

Installing the Outlook Client From Source

*************** *** 106,110 **** file or via CVS. The zip file will probably be easier to handle, but there are ! several significant improvements to the code which make the CVS version a viable option (though you will have to have a CVS client for Windows installed). --- 56,60 ---- file or via CVS. The zip file will probably be easier to handle, but there are ! several improvements to the code which make the CVS version a viable option (though you will have to have a CVS client for Windows installed). From anadelonbrin at users.sourceforge.net Thu Jul 3 20:57:07 2003 From: anadelonbrin at users.sourceforge.net (Tony Meyer) Date: Thu Jul 3 22:57:11 2003 Subject: [Spambayes-checkins] website faq.txt,1.8,1.9 Message-ID: Update of /cvsroot/spambayes/website In directory sc8-pr-cvs1:/tmp/cvs-serv14398 Modified Files: faq.txt Log Message: Typo. Index: faq.txt =================================================================== RCS file: /cvsroot/spambayes/website/faq.txt,v retrieving revision 1.8 retrieving revision 1.9 diff -C2 -d -r1.8 -r1.9 *** faq.txt 3 Jul 2003 01:54:52 -0000 1.8 --- faq.txt 4 Jul 2003 02:57:04 -0000 1.9 *************** *** 365,369 **** Yes you can do this, and it is a good idea if you don't keep copies of the mail that you have trained. This way, if your database becomes corrupted, ! you will be able to recoved without losing all your data (if you do keep copies of mail that you train, you can simply recreate the database via the SpamBayes manager dialog). --- 365,369 ---- Yes you can do this, and it is a good idea if you don't keep copies of the mail that you have trained. This way, if your database becomes corrupted, ! you will be able to recover without losing all your data (if you do keep copies of mail that you train, you can simply recreate the database via the SpamBayes manager dialog). From anadelonbrin at users.sourceforge.net Thu Jul 3 22:43:32 2003 From: anadelonbrin at users.sourceforge.net (Tony Meyer) Date: Fri Jul 4 00:43:36 2003 Subject: [Spambayes-checkins] spambayes mboxtrain.py,1.7,1.8 Message-ID: Update of /cvsroot/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv24739 Modified Files: mboxtrain.py Log Message: The order of the elif statements meant that one would never execute (should be most specific to most general and it was not). Fixes [spambayes-dev] [ spambayes-Bugs-761677 ] mboxtrain.py's -n optionhas no effect Index: mboxtrain.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/mboxtrain.py,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -d -r1.7 -r1.8 *** mboxtrain.py 13 Apr 2003 22:24:24 -0000 1.7 --- mboxtrain.py 4 Jul 2003 04:43:30 -0000 1.8 *************** *** 213,220 **** elif os.path.isfile(path): mbox_train(h, path, is_spam, force) - elif os.path.isdir(os.path.join(path, "cur")): - maildir_train(h, os.path.join(path, "cur"), is_spam, force) elif trainnew and os.path.isdir(os.path.join(path, "new")): maildir_train(h, os.path.join(path, "new"), is_spam, force) elif os.path.isdir(path): mhdir_train(h, path, is_spam, force) --- 213,220 ---- elif os.path.isfile(path): mbox_train(h, path, is_spam, force) elif trainnew and os.path.isdir(os.path.join(path, "new")): maildir_train(h, os.path.join(path, "new"), is_spam, force) + elif os.path.isdir(os.path.join(path, "cur")): + maildir_train(h, os.path.join(path, "cur"), is_spam, force) elif os.path.isdir(path): mhdir_train(h, path, is_spam, force) From anadelonbrin at users.sourceforge.net Thu Jul 3 23:02:39 2003 From: anadelonbrin at users.sourceforge.net (Tony Meyer) Date: Fri Jul 4 01:02:41 2003 Subject: [Spambayes-checkins] spambayes mboxtrain.py,1.8,1.9 Message-ID: Update of /cvsroot/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv26910 Modified Files: mboxtrain.py Log Message: *Correctly* fixes [spambayes-dev] [ spambayes-Bugs-761677 ] mboxtrain.py's -n optionhas no effect (I changed it from never to instead, when it should be as well as). Index: mboxtrain.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/mboxtrain.py,v retrieving revision 1.8 retrieving revision 1.9 diff -C2 -d -r1.8 -r1.9 *** mboxtrain.py 4 Jul 2003 04:43:30 -0000 1.8 --- mboxtrain.py 4 Jul 2003 05:02:36 -0000 1.9 *************** *** 213,220 **** elif os.path.isfile(path): mbox_train(h, path, is_spam, force) - elif trainnew and os.path.isdir(os.path.join(path, "new")): - maildir_train(h, os.path.join(path, "new"), is_spam, force) elif os.path.isdir(os.path.join(path, "cur")): maildir_train(h, os.path.join(path, "cur"), is_spam, force) elif os.path.isdir(path): mhdir_train(h, path, is_spam, force) --- 213,220 ---- elif os.path.isfile(path): mbox_train(h, path, is_spam, force) elif os.path.isdir(os.path.join(path, "cur")): maildir_train(h, os.path.join(path, "cur"), is_spam, force) + if trainnew: + maildir_train(h, os.path.join(path, "new"), is_spam, force) elif os.path.isdir(path): mhdir_train(h, path, is_spam, force) From montanaro at users.sourceforge.net Sat Jul 5 19:49:41 2003 From: montanaro at users.sourceforge.net (Skip Montanaro) Date: Sat Jul 5 21:49:45 2003 Subject: [Spambayes-checkins] website reply.txt,1.3,1.4 Message-ID: Update of /cvsroot/spambayes/website In directory sc8-pr-cvs1:/tmp/cvs-serv3307 Modified Files: reply.txt Log Message: tweak this, tweak that. Index: reply.txt =================================================================== RCS file: /cvsroot/spambayes/website/reply.txt,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** reply.txt 23 May 2003 14:23:20 -0000 1.3 --- reply.txt 6 Jul 2003 01:49:39 -0000 1.4 *************** *** 5,8 **** --- 5,9 ---- see if it answers your question(s). + What is Spambayes? ------------------ *************** *** 16,19 **** --- 17,21 ---- http://spambayes.sf.net/ + Will Spambayes run on my system/in my environment? -------------------------------------------------- *************** *** 23,44 **** you get mail from a mail server. I'm having trouble installing Spambayes. Help! ----------------------------------------------- ! There are known problems installing the Outlook plug-in on some combinations ! of Windows and Outlook. Consult ! ! http://spambayes.sf.net/windows.html ! ! for information about these problems. ! ! People who are not using the binary installer for the Outlook plugin should ! consult ! http://spambayes.sf.net/download.html ! to see what versions of Python will work with Spambayes. - For other installation issues, please file a bug report (see below). I found a bug. --- 25,41 ---- you get mail from a mail server. + I'm having trouble installing Spambayes. Help! ----------------------------------------------- ! There were problems installing the Outlook plug-in on some combinations of ! Windows and Outlook for early versions of the plug-in. Version 003 seems to ! install properly with all combinations of Windows and Outlook which have ! been tried so far. ! More information about Spambayes and Windows can be found at ! http://spambayes.sf.net/windows.html I found a bug. *************** *** 54,57 **** --- 51,55 ---- pieces together which are necessary to fix the underlying problem. + Subscribing to the Spambayes mailing list. ------------------------------------------ *************** *** 63,65 **** --- 61,68 ---- http://mail.python.org/mailman/listinfo/spambayes + + Before asking a question on the list, please take a moment and check the + frequently asked questions page: + + http://spambayes.sourceforge.net/faq.html From tim_one at users.sourceforge.net Sat Jul 5 20:36:36 2003 From: tim_one at users.sourceforge.net (Tim Peters) Date: Sat Jul 5 22:37:09 2003 Subject: [Spambayes-checkins] website reply.txt,1.4,1.5 Message-ID: Update of /cvsroot/spambayes/website In directory sc8-pr-cvs1:/tmp/cvs-serv7104/website Modified Files: reply.txt Log Message: Just some word-wrap. Index: reply.txt =================================================================== RCS file: /cvsroot/spambayes/website/reply.txt,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** reply.txt 6 Jul 2003 01:49:39 -0000 1.4 --- reply.txt 6 Jul 2003 02:36:34 -0000 1.5 *************** *** 1,6 **** READ THIS! (If you want help.) ! This is an automated response to an email message you sent to the ! spambayes@python.org mailing list. Please read this message carefully to see if it answers your question(s). --- 1,6 ---- READ THIS! (If you want help.) ! This is an automated response to an email message you sent to the ! spambayes@python.org mailing list. Please read this message carefully to see if it answers your question(s). *************** *** 9,17 **** ------------------ ! The Spambayes project was formed to develop a Bayesian anti-spam filter, ! initially based on the work of Paul Graham. The major difference between ! this and other, similar projects is the emphasis on testing newer approaches ! to scoring messages. You can read all about Spambayes on the project's ! website: http://spambayes.sf.net/ --- 9,17 ---- ------------------ ! The Spambayes project was formed to develop a Bayesian anti-spam filter, ! initially based on the work of Paul Graham. The major difference between ! this and other, similar projects is the emphasis on testing newer ! approaches to scoring messages. You can read all about Spambayes on the ! project's website: http://spambayes.sf.net/ *************** *** 21,27 **** -------------------------------------------------- ! Yes, though which tools you use and the amount of work necessary to get ! started will vary depending on your computing platform, email client and how ! you get mail from a mail server. --- 21,27 ---- -------------------------------------------------- ! Yes, though which tools you use and the amount of work necessary to get ! started will vary depending on your computing platform, email client and ! how you get mail from a mail server. *************** *** 30,35 **** There were problems installing the Outlook plug-in on some combinations of ! Windows and Outlook for early versions of the plug-in. Version 003 seems to ! install properly with all combinations of Windows and Outlook which have been tried so far. --- 30,35 ---- There were problems installing the Outlook plug-in on some combinations of ! Windows and Outlook for early versions of the plug-in. Version 003 seems ! to install properly with all combinations of Windows and Outlook which have been tried so far. *************** *** 47,52 **** If you post your bug report to the mailing list, there's always the chance ! it will get missed. Filing a bug report also provides a single place to ! collect all the data related to the bug, making it easier to put all the pieces together which are necessary to fix the underlying problem. --- 47,52 ---- If you post your bug report to the mailing list, there's always the chance ! it will get missed. Filing a bug report also provides a single place to ! collect all the data related to the bug, making it easier to put all the pieces together which are necessary to fix the underlying problem. *************** *** 55,60 **** ------------------------------------------ ! The spambayes@python.org mailing list formed in September 2002 to support ! development of the Spambayes spam filtering system as an outgrowth of earlier threads on the Python developers' mailing list. You can subscribe to the Spambayes mailing list using the form at --- 55,60 ---- ------------------------------------------ ! The spambayes@python.org mailing list formed in September 2002 to support ! development of the Spambayes spam filtering system as an outgrowth of earlier threads on the Python developers' mailing list. You can subscribe to the Spambayes mailing list using the form at *************** *** 66,68 **** http://spambayes.sourceforge.net/faq.html - --- 66,67 ---- From anadelonbrin at users.sourceforge.net Sun Jul 6 18:09:30 2003 From: anadelonbrin at users.sourceforge.net (Tony Meyer) Date: Sun Jul 6 20:09:32 2003 Subject: [Spambayes-checkins] spambayes/spambayes Version.py,1.4,1.5 Message-ID: Update of /cvsroot/spambayes/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv25114/spambayes Modified Files: Version.py Log Message: Update changelog and what's new in preparation for a4 release. (Note that I've reversed the order of the changelog so that the newest information is at the top. This will play havoc with this cvs diff, but is for the better, I think). The what's new file only has a3->a4 info, not a2->a3 as well. Add the windows directory to the manifest, and notesfilter to setup.py Update the __version__, and version information in version.py (I've increased the 'core' version because the incorrect token count bug could be 'significant', I think. Feel free to disagree with this!) Index: Version.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/spambayes/Version.py,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** Version.py 1 Jul 2003 00:58:28 -0000 1.4 --- Version.py 7 Jul 2003 00:09:27 -0000 1.5 *************** *** 6,12 **** versions = { # Non app specific - changed when "spambayes\*" changes significantly ! "Version": 0.1, ! "Description": "SpamBayes Beta1", ! "Date": "May 2003", "Full Description": "%(Description)s, version %(Version)s (%(Date)s)", # Sub-dict for application specific version strings. --- 6,12 ---- versions = { # Non app specific - changed when "spambayes\*" changes significantly ! "Version": 0.2, ! "Description": "SpamBayes Beta2", ! "Date": "July 2003", "Full Description": "%(Description)s, version %(Version)s (%(Date)s)", # Sub-dict for application specific version strings. From anadelonbrin at users.sourceforge.net Sun Jul 6 18:09:30 2003 From: anadelonbrin at users.sourceforge.net (Tony Meyer) Date: Sun Jul 6 20:09:35 2003 Subject: [Spambayes-checkins] spambayes CHANGELOG.txt, 1.6, 1.7 MANIFEST.in, 1.4, 1.5 WHAT_IS_NEW.txt, 1.5, 1.6 setup.py, 1.18, 1.19 Message-ID: Update of /cvsroot/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv25114 Modified Files: CHANGELOG.txt MANIFEST.in WHAT_IS_NEW.txt setup.py Log Message: Update changelog and what's new in preparation for a4 release. (Note that I've reversed the order of the changelog so that the newest information is at the top. This will play havoc with this cvs diff, but is for the better, I think). The what's new file only has a3->a4 info, not a2->a3 as well. Add the windows directory to the manifest, and notesfilter to setup.py Update the __version__, and version information in version.py (I've increased the 'core' version because the incorrect token count bug could be 'significant', I think. Feel free to disagree with this!) Index: CHANGELOG.txt =================================================================== RCS file: /cvsroot/spambayes/spambayes/CHANGELOG.txt,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -d -r1.6 -r1.7 *** CHANGELOG.txt 22 Jun 2003 01:44:53 -0000 1.6 --- CHANGELOG.txt 7 Jul 2003 00:09:27 -0000 1.7 *************** *** 1,270 **** Alpha Release 3 =============== ! Mark Hammond 03/02/03 Change train.py to be able to work with a bsddb database. ! Mark Hammond 03/02/03 If a new bsddb or bsddb3 module is available use this instead of a pickle in the Outlook plugin. ! Mark Hammond 03/02/03 Add tick-marks to the filter dialog. ! Mark Hammond 03/02/03 Fix SF#677804 ('Untouched fitler command error'). ! Mark Hammond 04/02/03 Fix SF#642740 ('"Recover from Spam" wrong folder'). ! Mark Hammond 07/02/03 Fix some errors using bsddb3 in Outlook plugin. ! Tim Stone 08/02/03 Ensure that nham and nspam are instances of integer in dbExpImp.py ! Tim Stone 08/02/03 Ensure that nham and nspam becoming strings doesn't break classification. ! Tim Stone 08/02/03 Added ability to put classification in subject or to headers (for OE). ! Tim Stone 10/02/03 Changed BAYESCUSTOMIZE environment varaible parsing from a split to a regex to fix filenames with embedded spaces. ! Mark Hammond 12/02/03 Check for correct exception when removing file in Outlook addin. ! Mark Hammond 12/02/03 Check for bsddb3 before bsddb (previously bsddb3 would never be found). ! Mark Hammond 13/02/03 Add SF#685746 ('Outlook plugin folder list sorted alphabetically'). ! Mark Hammond 13/02/03 Handle exceptions when opening folders in Outlook plugin better. ! Skip Montanaro 13/02/03 Split BAYESCUSTOMIZE environment variable using os.pathsep. ! Neil Schemenauer 16/02/03 Add -c and -d options to mailsort.py. ! Neil Schemenauer 16/02/03 First check-in of dump_cdb.py ! Mark Hammond 18/02/03 Store Outlook plugin files in the "correct" Windows directory. ! Tim Stone 25/02/03 First check in of Lotus Notes filter. ! Tim Stone 25/02/03 Add option for pop3proxy to notate Subject: header. ! Tony Meyer 25/02/03 Fix bug in Corpus.get() which would never return the default value. ! Mark Hammond 26/02/03 Fix bug in dbmstorage.py for Python 2.2, which tried bsddb3 twice if it failed. ! Tony Meyer 27/02/03 Add options to add an id (as a header or in the body), strip such ids from incoming mail, find a message via the id, train messages by forwarding/bouncing to smtpproxy. ! Tony Meyer 27/02/03 First check in of smtpproxy. ! T. Alexander Popiel 27/02/03 Added various files relating to incremental training (or "self training") regimes. ! Tim Stone 27/02/03 Fix SF#693423 ('email message generates error in pop3proxy.py'). ! T. Alexander Popiel 28/02/03 Put all regimes into regmies.py. Define fpfnunsure and fnunsure regimes. ! T. Alexander Popiel 28/02/03 Fix name conflict between regimes list and regimes source file in incremental.py ! T. Alexander Popiel 28/02/03 Reduce the amount of progress output in incremental.py ! T. Alexander Popiel 01/03/03 Add option to mkgraph to spit out counts *or* error rates, and n-day averages *or* cumulative. ! Tony Meyer 01/03/03 Small modifications to smtpproxy related pop3proxy options. ! Tony Meyer 01/03/03 Expose options for adding an id to incoming mail in pop3proxy. ! Tony Meyer 01/03/03 Expose options for using smtpproxy. ! Tony Meyer 02/03/03 Added support to smtpproxy for extracting an id in a Mozilla style forwarded message (HTML table). ! Mark Hammond 03/03/03 Fix manager.py calling shutil.move (does not exist pre Python 2.3). ! Mark Hammond 03/03/03 Fix SF#696995 ('Invalid HTML comments are not ignored'). ! Skip Montanaro 03/03/03 Note when subject charset is invalid (rather than raising an exception). ! Mark Hammond 04/03/03 Fix a Outlook plugin bug that could cause incorrect word scores to be used/saved when a bsddb database is used. ! Mark Hammond 04/03/03 Remove unused 'wordcache' instance variable in storage.py. ! Mark Hammond 04/03/03 Show all tokens in message when showing clues in Outlook plugin. ! Mark Hammond 04/03/03 Fix a bug in the Outlook plugin test code that used *all* ham/spam words, not just top 50. ! Mark Hammond 04/03/03 Only remember source folder when filtering, not just scoring in Outlook plugin. ! Mark Hammond 04/03/03 Only attempt to create "Spam" field on a mail item in Outlook plugin. ! Mark Hammond 04/03/03 If no items are found in Outlook plugin don't attempt to recurse folders. ! Mark Hammond 04/03/03 Fix SF#696476 ('Manual filtering in outlook fails'). ! Mark Hammond 04/03/03 Fix SF#697120 ('Manual filtering in Outlook (still) fails'). ! Jeremy Hylton 04/03/03 Band-aid decode_header() in pop3proxy.py ! Tim Stone 06/03/03 Added SF#690928 ('turn off saving messages in popproxy'). ! Skip Montanaro 06/03/03 Catch extra exception in header parse errors. ! Tim Stone 06/03/03 Fix SF#698852 ("can't classify messages"). ! Mark Hammond 07/03/03 Handle MAPI exceptions better in Outlook plugin. ! Mark Hammond 07/03/03 Centralise detection of "not found" exceptions in Outlook plugin. ! Mark Hammond 07/03/03 Supress errors in outlook plugin when hotmail connector can't save the message. ! T. Alexander Popiel 07/03/03 Added another regime to regimes.py. ! Tim Stone 08/03/03 Fix SF#700165 ('MoveFileEx doesn't exist on Win98'). ! Tim Peters 08/03/03 List unique tokens one per line in Outlook plugin's ShowClues. ! Mark Hammond 09/03/03 Correct "data" directory location in export.py. ! Tony Meyer 09/03/03 Added pop3proxy include_prob option to (optionally) note the score/prob in the classification header. ! Tim Stone 09/03/03 Added configuration for pop3proxy include_prob option, add_mailid_to and strip_incoming mailIds options. ! Tony Meyer 10/03/03 Added level & evidence headers in pop3proxy. ! Tony Meyer 11/03/03 Fixes a bug in pop3proxy/smtpproxy where headers will appear in the message body. ! Mark Hammond 12/03/03 Added pop3proxy_service.py ! Tony Meyer 12/03/03 Update web ui so that boolean options are radio buttons rather than text boxes, and multiple choice options are checkboxes. ! Tony Meyer 12/03/03 Separated out pop3proxy options and header options in pop3proxy web ui. ! Tony Meyer 12/03/03 Adds UpdatableConfigParser. ! Tony Meyer 12/03/03 Changes Options.py to use UpdatableConfigParser rather than ConfigParser. ! Tony Meyer 13/03/03 Revert Options.py to ConfigParser from UpdatableConfigParser. ! Mark Hammond 16/03/03 Allow messages to be scored after training in Outlook plugin. ! Mark Hammond 16/03/03 Fix bug in Outlook plugin where filter operation report was reporting incorrect total. ! Mark Hammond 17/03/03 Warn, but ignore errors walking the folder tree in Outlook plugin. ! Mark Hammond 17/03/03 Fix SF#704921 ('"Train now" (outlook) fails '). ! Mark Hammond 17/03/03 Prevent a single error filtering a message from stopping the whole filter process in Outlook plugin. ! Mark Hammond 18/03/03 Ensure all buttons are greyed during filter process in Outlook plugin. ! Mark Hammond 18/03/03 When running Outlook plugin from a binary redirect output to a log. ! Mark Hammond 18/03/03 Version 002 of the binary. ! Mark Hammond 20/03/03 Ensure database is saved before testing outlook plugin. ! Mark Hammond 20/03/03 Fix error in testing outlook plugin (getting wrong end of sorted list). ! Tim Stone 20/03/03 Added SF#703283 ('mboxtrain only trains on cur in maildir'). ! Mark Hammond 23/03/03 Fix SF#707491 ('Pop3 proxy service code for Windows doesn't work...'). ! Tim Stone 28/03/03 Unicode print error fix in notesfilter. ! Tony Meyer 03/04/03 Expire messages from the unknown pop3proxy cache as well as ham/spam caches. ! Tony Meyer 03/04/03 Kick off expiry check each time a client connects to the proxy rather than on startup, for those who have the proxy stable! ! Tony Meyer 03/04/03 Add "show clues" button to the review message page in pop3proxy ui. ! Tony Meyer 07/04/03 First check-in of IMAP filter. ! Tim Stone 07/04/03 First check-in of message.py ! Tim Stone 07/04/03 Changed imapfilter to use the message class. ! Tony Meyer 08/04/03 Introduce a IMAPMessage class based on the spambayes Message class. ! Tony Meyer 08/04/03 Introduce an iterable IMAPFolder class. ! Tony Meyer 08/04/03 Allow filtering of multiple folders in IMAP filter. ! Tim Stone 08/04/03 Added methods to message.py to support copying one message to another. ! Tim Stone 08/04/03 Added logic to imapfilter to ensure that classification and training memory is preserved. ! Tony Meyer 09/04/03 Update imapfilter to reflect message class changes. ! Tim Stone 10/04/03 Made base message class more abstract and added a SBHeaderMessage class. ! Tim Stone 10/04/03 Made imapfilter use the new message class. ! Tim Stone 12/04/03 Functional version of the imapfilter. ! Tim Stone 13/04/03 Raise an error if message.py is asked to remember an unknown classification. ! Tim Stone 13/04/03 General cleanup of imapfilter. ! Tim Stone 13/04/03 Remove old message ids from the message info db when using imapfilter. ! Skip Montanaro 13/04/03 Fix train() in mboxtrain. ! Tony Meyer 13/04/03 Fix for user interface showing incorrect server strings when using pop3proxy_service. ! Tony Meyer 13/04/03 Various speed improvements to imapfilter. ! Tim Stone 14/04/03 Fixed the imapfilter docstring not printing. ! Tim Stone 14/04/03 Changed imapfilter -e argument to y/n. ! Tim Stone 14/04/03 Added -l argument to imapfilter allowing looping. ! Tim Stone 14/04/03 Correctly extract timestamp for new messages in imapfilter. ! Tony Meyer 16/04/03 Fix an imapfilter invalid date problem. ! Tim Stone 17/04/03 Corrected newline mangling in imapfilter. ! Tim Stone 17/04/03 Corrected folder comparison operator in imapfilter. ! Tim Stone 17/04/03 Refactored functionality into an IMAPSession class. ! Tim Stone 17/04/03 Added -p option for password prompt in imapfilter. ! Tim Stone 17/04/03 Corrected imapfilter training error which would result in no training being done. ! Tim Stone 17/04/03 Corrected an error in the timed loop that unnecessarily kept imap sessions open. ! Tim Stone 17/04/03 Moved the header repaid regex into the message class. ! Tony Meyer 17/04/03 Added ConfigParser from Python 2.3 which solves many problems in the 2.2 version. ! Tony Meyer 17/04/03 Updated UpdatableConfigParser to use new 2.3 ConfigParser. ! Tony Meyer 18/04/03 Remove support for pop3proxy_port, pop3proxy_server_name and pop3proxy_server_port otpions (long deprecated). ! Tony Meyer 18/04/03 Remove option to launch smtpproxy and always do this from pop3proxy (if servers are specified). ! Tony Meyer 18/04/03 Fix smtpproxy bug that would prevent mail sent in the same session as training mail being delivered. ! Tony Meyer 18/04/03 Major rework of configuration file reading/options. Section names no longer ignored. ! Tony Meyer 18/04/03 Moved interface code out of pop3proxy into ImapUI, ProxyUI and UserInterface.py ! Tim Stone 18/04/03 Added web interface support to imapfilter. ! Tim Stone 18/04/03 Only start browser if required in imapfilter. ! Tony Meyer 18/04/03 Fix for time retrieval in imapfilter when the date header is missing. ! Tony Meyer 18/04/03 Change the line endings fix (pop3proxy/imapfilter) to a more robust one (from smtplib). ! Tim Stone 18/04/03 Converted pop3proxy to use message.py. (notate-body is no longer working) ! Mark Hammond 18/04/03 Fixed Outlook plugin to work in non-English locales. ! Tony Meyer 19/04/03 Fixed updating of configuration files. ! Tim Stone 19/04/03 Correction to regex for smtpproxy servers validation. ! Tony Meyer 19/04/03 Stop IMAP filter filtering messages marked as deleted. ! Tony Meyer 19/04/03 Copy IMAP flags along with message. ! Tony Meyer 19/04/03 Use IMAP date instead of the local one. ! Tony Meyer 19/04/03 Added utility functions to Options.py to assist people to figure out what is available. ! Tony Meyer 20/04/03 Moved pop3proxy test code into separate module. ! Tony Meyer 20/04/03 Allow "" as a valid option if the valid values are defined by a regex and multiple values are allowed. ! Tony Meyer 20/04/03 Change imapfilter server option to pop3proxy style (i.e. server[:port]) ! Tony Meyer 20/04/03 Set web interface pages to not cache. ! Tony Meyer 20/04/03 Fixed imapfilter and pop3proxy web configuration. ! Tony Meyer 20/04/03 Change the select folder config for imapfilter to two pages. ! Tony Meyer 20/04/03 Added check for parsedate failing in imapfilter. ! Tony Meyer 20/04/03 Fix the regex for the date in imapfilter. ! Tim Stone 20/04/03 Removed unnecessary imports/comments in pop3proxy. ! Tim Stone 20/04/03 Changed pop3proxy's STAT handling to return a guess at new message size. ! Tim Stone 21/04/03 Cosmetic changes to the web configuration page. ! Skip Montanaro 21/04/03 Fix crlf regex in message.py ! Tony Meyer 21/04/03 Fix SF#725307 ('Outlook plugin won't load (anymore)'). ! Tim Stone 21/04/03 Rewrote is_valid method in Options.py ! Tony Meyer 22/04/03 Fixed is_valid method for sets. ! Tim Stone 22/04/03 Added extra verbose output in IMAP Filter. ! Tim Stone 22/04/03 Corrected counting error in IMAP Filter. ! Tony Meyer 22/04/03 Fix SF#725616 ('Options.py mergefiles crashes (+ fix)'). ! Tony Meyer 22/04/03 Improved processing of fetch response in IMAP filter. ! Tony Meyer 24/04/03 Fix SF#725307 ("Outlook plugin won't load (anymore)"). ! Tony Meyer 24/04/03 Fix SF#725466 ('Include a proper locale fix in Options.py'). ! Tony Meyer 24/04/03 Fix SF#726255 ('Problem if bayescustomize.ini not there'). ! Tony Meyer 24/04/03 Moved the crlf fixing from generic message class to IMAP filter. ! Tony Meyer 24/04/03 Major rewrite of Options.py ! Tony Meyer 24/04/03 Changed options with muliple values to tuples. ! Tony Meyer 24/04/03 Fixed bug where the IMAP user interface would try to display a folder before logging in. ! Tony Meyer 24/04/03 Added convert_config_file script. ! Tim Stone 24/04/03 Fix message.py incorrectly persisting/restoring state. ! Tony Meyer 24/04/03 Fix Options.py convert and unconvert functions. ! Tony Meyer 24/04/03 Fix valid characters for IMAP username and password. ! Tony Meyer 24/04/03 Improve behaviour of convert_config_file script. ! Tony Meyer 24/04/03 Check that spam/unsure/filter folders exist in IMAP before filtering/training. ! Tony Meyer 24/04/03 Removed CompatConfigParser.py ! Tony Meyer 24/04/03 Removed UpdatableConfigParser.py ! Tony Meyer 25/04/03 Added message_from_string functions to message.py and imapfilter.py ! Tony Meyer 25/04/03 Extra error checking in IMAP Filter. ! Tony Meyer 27/04/03 Minor bug fixes to Options.py ! Tony Meyer 27/04/03 Fixed configuration file reading bug forcing single space separators instead of any whitespace. ! Tony Meyer 27/04/03 Fixed Options.py bug reported by Tim Stone. ! Tony Meyer 27/04/03 Fix hammiefilter calling mergefiles instead of merge_files. ! Tony Meyer 28/04/03 Stop using IMAP uids as our ids. ! Tony Meyer 28/04/03 Fix SelectFolder bug in IMAP Filter. ! Tim Stone 28/04/03 Create IMAP session object for each login. ! Tony Meyer 28/04/03 Fix for SF#728886 ('In the pop3 UI not able to pass more than 1 server'). ! Tony Meyer 28/04/03 Fix for incorrect is_boolean code in Options.py ! Tony Meyer 28/04/03 IMAP Filter now only retrieves RFC822 headers when iterating, not whole message. ! Tim Stone 28/04/03 Moved crlf replacement from IMAP to generic message class. ! Tony Meyer 30/05/03 Added url slurper. ! Mark Hammond 01/05/03 Ignore the pywin.dialogs package in the Outlook plugin install. ! Mark Hammond 01/05/03 Save the database after an explicit train. ! Mark Hammond 01/05/03 Fix globals statements in url slurper. ! Mark Hammond 01/05/03 Fix testtools import in url slurper. ! Mark Hammond 01/05/03 Print url slurper status to stderr. ! Mark Hammond 01/05/03 Added socket.error catching in url slurper. ! Mark Hammond 01/05/03 Avoid slurping non html content. ! Tony Meyer 01/05/03 Fix bug where url cache would not be in the current working directory by default. ! Tony Meyer 02/05/03 Fix temp file problem with web interface on linux. ! Tony Meyer 02/05/03 Update configuration file reading so that writing uses same delimiters. ! Tony Meyer 02/05/03 Fix temp file problem with web interface on linux. ! Tony Meyer 03/05/03 Removed OptionConfig.py ! Mark Hammond 03/05/03 Correct usage doc with respect to default directory. ! Mark Hammond 03/05/03 Fix SF#715248 ('Pickle classifier should save to a temp file first'). ! Mark Hammond 03/05/03 Formalised error reporting in Outlook plugin. ! Mark Hammond 03/05/03 Created special handling for "startup errors" in Outlook plugin ! Mark Hammond 03/05/03 Allow test suite to work with bsddb3 or bsddb. ! Tony Meyer 03/05/03 Fix invalid options names in IMAP and POP3 user interface. ! Tony Meyer 03/05/03 Fix incorrect state information displaying after configuration. ! Tim Stone 04/05/03 Catch exception when a file in the pop3proxy cache mysteriously disappears. ! Tony Meyer 04/05/03 Fix bug stopping some messages loading into pop3proxy cache. ! Tony Meyer 06/05/03 Added getattr backwards compatibility for renamed options. ! Tony Meyer 06/05/03 IMAP Filter now deletes existing spambayes headers before training. ! Tony Meyer 06/05/03 Added "Storage":"messageinfo_storage_file" option. ! Tony Meyer 06/05/03 Fix for SF#733247 ('crash when using merged-in options'). ! Tony Meyer 11/05/03 Fixed KeyError bug in message.py. ! Tony Meyer 11/05/03 Added SSL support to imapfilter (untested). ! Tony Meyer 13/05/03 Added refresh button to review messages page in pop3proxy ui. ! Tony Meyer 13/05/03 Added "check again" link on 'no more untrained messages page' in pop3proxy ui. ! Tony Meyer 13/05/03 Added "html_ui":"display_to" option. ! Mark Hammond 14/05/03 Various changes to urlslurper.py ! Mark Hammond 14/05/03 Fix SF#737956 ('No hourglass when building folder lists'). ! Mark Hammond 14/05/03 Fix SF#737955 ('Transient connection error disables plugin'). ! Tony Meyer 14/05/03 Added missing import to UserInterface.py ! Tony Meyer 14/05/03 Increased efforts to stop browsers caching the interface pages. ! Mark Hammond 15/05/03 The training dialog now shows a correct progress bar for the *complete* operation - training *and* scoring ! Mark Hammond 15/05/03 Fix SF#706170 ('Execute test suite fails in Outlook'). ! Mark Hammond 15/05/03 Save bsddb databases after a training operation (should prevent Outlook ever saving at shutdown). ! Mark Hammond 15/05/03 Print how long each save takes (so people can complain). ! Mark Hammond 15/05/03 Keep and print some stats about how many items SpamBayes saw. ! Tim Peters 19/05/03 Catch BoundaryError when parsing messages. ! Tim Peters 19/05/03 Improve tokenisation for messages that have text that looks like Wrinkle Reduction ! Tim Peters 19/05/03 Decode numeric character entities in html. ! Tim Peters 19/05/03 Replace

and
tages with single blanks. ! Tony Meyer 21/05/03 Cosmetic changes to pop3proxy and imapfilter interface. ! Tony Meyer 21/05/03 Remove the "account for string nham/nspam" code in classifier. ! Tony Meyer 25/05/03 Expose experimental ham/spam imbalance option to pop3proxy/imapfilter users ! Tim Peters 25/05/03 Restore __slots__ declaration to WordInfo object in classifier.py ! Tim Peters 25/05/03 PickledClassifier.load(): use getstate/setstate to copy the state. ! Tony Meyer 26/05/03 Fix SF#737986 ('Message.as_string() fails.'). ! Tony Meyer 26/05/03 Restore notate_to and notate_subject functionality to pop3proxy. ! Mark Hammond 29/05/03 DB classifier keeps a list of "changed words" to prevent saves from updating *all* words. ! Mark Hammond 29/05/03 DB classifier doesn't cache hapaxes. ! Mark Hammond 03/06/03 Handle malformed messages better in the Outlook plugin. ! Mark Hammond 03/06/03 In Outlook plugin, create our own toolbar, rather than using the standard one. ! Mark Hammond 03/06/03 Fix an Outlook plugin error that would try to save the database when classifying. ! Mark Hammond 03/06/03 Make Outlook plugin log refer to "Spambayes" rather than "SpamAddin" ! Mark Hammond 03/06/03 Use 'wait' cursor when incremental training in Outlook plugin. ! Mark Hammond 03/06/03 In Outlook plugin, save config when dialog closes and not at shutdown. ! Mark Hammond 03/06/03 Clean up toolbar images. ! Mark Hammond 04/06/03 In Outlook plugin, no longer default to the "Inbox" (see also SF#741797 ('Does not filter incoming mail')). ! Mark Hammond 04/06/03 In Outlook plugin, when filtering, saving the spam score is no longer fatal. ! Tony Meyer 04/06/03 In muttrc, fix incorrect Spambayes header name. ! Mark Hammond 05/06/03 Add a version information repository. ! Mark Hammond 05/06/03 Change Outlook plugin to use new version information repository. ! Neale Pickett 06/06/03 Integrated code for the VM mailer into spambayes.el ! Tony Meyer 08/06/03 Add pop3proxy, hammie, smtpproxy & imapfilter version information. ! Skip Montanaro 10/06/03 Correction to VM mailer addition to spambayes.el ! Tony Meyer 12/06/03 Update pop3proxy and imapfilter to print out version information. ! Mark Hammond 16/06/03 Split OptionsClass into a separate file. ! Mark Hammond 16/06/03 Allow lists to be used for multi-valued options. ! Mark Hammond 16/06/03 Allow the first entry in the "defaults" table to be a sub-class of Option. ! Mark Hammond 16/06/03 In Outlook plugin, when training, instead of suggesting the inbox, suggest folders we watch. ! Mark Hammond 16/06/03 In Outlook plugin, change "Anti-Spam" on the dropdown to "SpamBayes" ! Mark Hammond 16/06/03 In Outlook plugin, huge changes to configuration. No longer use a pickle, but instead a series of .INI files. ! Mark Hammond 17/06/03 2 new [General] options for Outlook plugin - delete_as_spam_message_state and recover_from_spam_message_state. ! Mark Hammond 17/06/03 In Outlook plugin, prevent "Deleted items", Outbox and Sent Items from appearing in the folder list. Fixes: [ 749277 ] Should prevent "Deleted Items" being target folder. ! Mark Hammond 17/06/03 In Outlook plugin, catch the assertion error in the classifier, and warn the user their database is corrupt. ! Mark Hammond 17/06/03 In Outlook plugin, introduce ReportErrorOnce, useful for errors on event handlers that you don't want to bombard the user with. ! Mark Hammond 17/06/03 In Outlook plugin, an error on a single sub-folder need not be fatal. Hopefully fixes [ 743515 ] Unable to expand folders in folder selection dialog. ! Mark Hammond 17/06/03 In Outlook plugin, DeleteAsSpam didn't detect "no folder" correctly. ! Anthony Baxter 17/06/03 In IMAPFilter interface, fix parm_map code. ! Mark Hammond 18/06/03 In Outlook plugin, allow either spam or unsure messages to be marked as read as they are filtered. ! Mark Hammond 18/06/03 In Outlook plugin, more work on the toolbar. ! Mark Hammond 19/06/03 In Outlook plugin, change "Anti-Spam Manager" -> "SpamBayes Manager" ! Mark Hammond 20/06/03 In Outlook plugin, add a 'verbose' option to the options. ! Neale Pickett 21/06/03 In hammiefilter, make untrain mode work. ! Tony Meyer 22/06/03 Fix RFC822.PEEK error in imapfilter. --- 1,295 ---- + Alpha Release 4 + =============== + Tony Meyer 04/07/2003 Fix SF#761677 ("mboxtrain.py's -n optionhas no effect") + Richie Hindle 03/07/2003 Put the current date and time into the footer of the web interface, rather than always displaying "Mon Dec 30 14:04:32 2002". + Richie Hindle 03/07/2003 Fix a bug in pop3proxy where long attachments would be broken. + Richie Hindle 02/07/2003 If an exception occurs parsing a message in pop3proxy, append an 'exception' header to the message and recover. + Richie Hindle 02/07/2003 Stop the pop3proxy including the trailing . when passing messages to the email package. + Mark Hammond 01/07/2003 Version 003 of the binary. + Mark Hammond 01/07/2003 In outlook plugin, display a message for "Delete as Spam" or "Recover from Spam" when SpamBayes is not enabled. + Skip Montanaro 01/07/2003 Encode unicode objects as utf-8 before using as a key for DBDictClassifier instances. (Fixes [ spambayes-Bugs-761670 ] Unexpected unicode key inbsd db) + Mark Hammond 01/07/2003 In Outlook plugin, toolbar was not initialized when "Outlook Today" was the default view. + Mark Hammond 30/06/2003 In Outlook plugin, don't (try to) do OnStartupComplete work if OnConnection failed. + Mark Hammond 30/06/2003 In Outlook plugin, log the repr() of messages displayed in a dialog, as they often have embedded \r\n chars - repr() keeps the whole thing to a single line. + Tim Peters 28/06/2003 A new stripper to squash yet another way of hiding content in HTML spam, like Ereywl55ctions to hide Erections. + Tim Peters 27/06/2003 In storage.py store(): If a Shelf db doesn't have a key, then "del db[key]" should raise KeyError. + Tim Peters 27/06/2003 In storage.py store(): Use iteritems() instead of items() to materialize the changed_words guts. + Tim Peters 27/06/2003 In storage.py, check WORD_CHANGED and WORD_DELETED with is not ==. + Tim Peters 27/06/2003 Remove a superstituous check for None in storage.py (_wordinfoset()). + Tim Peters 27/06/2003 Fix a bug in storage.py (_wordinfoget()) which could cause incorrect token counts. + Tony Meyer 23/06/2003 In imapfilter, try to append without flags if appending fails. + Tony Meyer 23/06/2003 Implement SF#755098 - "Progress Indicator in imapfilter" + Tony Meyer 23/06/2003 Fix the -i switch in imapfilter. + Barry Warsaw 22/06/2003 Don't try and get password from options if -p is specified in imapfilter. + Barry Warsaw 22/06/2003 Fix an import error in imapfilter. + Alpha Release 3 =============== ! Tony Meyer 22/06/2003 Fix RFC822.PEEK error in imapfilter. ! Neale Pickett 21/06/2003 "In hammiefilter, make untrain mode work." ! Mark Hammond 20/06/2003 "In Outlook plugin, add a 'verbose' option to the options." ! Mark Hammond 19/06/2003 "In Outlook plugin, change ""Anti-Spam Manager"" -> ""SpamBayes Manager""" ! Mark Hammond 18/06/2003 "In Outlook plugin, allow either spam or unsure messages to be marked as read as they are filtered." ! Mark Hammond 18/06/2003 "In Outlook plugin, more work on the toolbar." ! Mark Hammond 17/06/2003 2 new [General] options for Outlook plugin - delete_as_spam_message_state and recover_from_spam_message_state. ! Mark Hammond 17/06/2003 "In Outlook plugin, prevent ""Deleted items"", Outbox and Sent Items from appearing in the folder list. Fixes: [ 749277 ] Should prevent ""Deleted Items"" being target folder." ! Mark Hammond 17/06/2003 "In Outlook plugin, catch the assertion error in the classifier, and warn the user their database is corrupt." ! Mark Hammond 17/06/2003 "In Outlook plugin, introduce ReportErrorOnce, useful for errors on event handlers that you don't want to bombard the user with." ! Mark Hammond 17/06/2003 "In Outlook plugin, an error on a single sub-folder need not be fatal. Hopefully fixes [ 743515 ] Unable to expand folders in folder selection dialog." ! Mark Hammond 17/06/2003 "In Outlook plugin, DeleteAsSpam didn't detect ""no folder"" correctly." ! Anthony Baxter 17/06/2003 "In IMAPFilter interface, fix parm_map code." ! Mark Hammond 16/06/2003 Split OptionsClass into a separate file. ! Mark Hammond 16/06/2003 Allow lists to be used for multi-valued options. ! Mark Hammond 16/06/2003 "Allow the first entry in the ""defaults"" table to be a sub-class of Option." ! Mark Hammond 16/06/2003 "In Outlook plugin, when training, instead of suggesting the inbox, suggest folders we watch." ! Mark Hammond 16/06/2003 "In Outlook plugin, change ""Anti-Spam"" on the dropdown to ""SpamBayes""" ! Mark Hammond 16/06/2003 "In Outlook plugin, huge changes to configuration. No longer use a pickle, but instead a series of .INI files." ! Tony Meyer 12/06/2003 Update pop3proxy and imapfilter to print out version information. ! Skip Montanaro 10/06/2003 Correction to VM mailer addition to spambayes.el ! Tony Meyer 8/06/2003 "Add pop3proxy, hammie, smtpproxy & imapfilter version information." ! Neale Pickett 6/06/2003 Integrated code for the VM mailer into spambayes.el ! Mark Hammond 5/06/2003 Add a version information repository. ! Mark Hammond 5/06/2003 Change Outlook plugin to use new version information repository. ! Mark Hammond 4/06/2003 "In Outlook plugin, no longer default to the ""Inbox"" (see also SF#741797 ('Does not filter incoming mail'))." ! Mark Hammond 4/06/2003 "In Outlook plugin, when filtering, saving the spam score is no longer fatal." ! Tony Meyer 4/06/2003 "In muttrc, fix incorrect Spambayes header name." ! Mark Hammond 3/06/2003 Handle malformed messages better in the Outlook plugin. ! Mark Hammond 3/06/2003 "In Outlook plugin, create our own toolbar, rather than using the standard one." ! Mark Hammond 3/06/2003 Fix an Outlook plugin error that would try to save the database when classifying. ! Mark Hammond 3/06/2003 "Make Outlook plugin log refer to ""Spambayes"" rather than ""SpamAddin""" ! Mark Hammond 3/06/2003 Use 'wait' cursor when incremental training in Outlook plugin. ! Mark Hammond 3/06/2003 "In Outlook plugin, save config when dialog closes and not at shutdown." ! Mark Hammond 3/06/2003 Clean up toolbar images. ! Tony Meyer 30/05/2003 Added url slurper. ! Mark Hammond 29/05/2003 "DB classifier keeps a list of ""changed words"" to prevent saves from updating *all* words." ! Mark Hammond 29/05/2003 DB classifier doesn't cache hapaxes. ! Tony Meyer 26/05/2003 Fix SF#737986 ('Message.as_string() fails.'). ! Tony Meyer 26/05/2003 Restore notate_to and notate_subject functionality to pop3proxy. ! Tony Meyer 25/05/2003 Expose experimental ham/spam imbalance option to pop3proxy/imapfilter users ! Tim Peters 25/05/2003 Restore __slots__ declaration to WordInfo object in classifier.py ! Tim Peters 25/05/2003 PickledClassifier.load(): use getstate/setstate to copy the state. ! Tony Meyer 21/05/2003 Cosmetic changes to pop3proxy and imapfilter interface. ! Tony Meyer 21/05/2003 "Remove the ""account for string nham/nspam"" code in classifier." ! Tim Peters 19/05/2003 Catch BoundaryError when parsing messages. ! Tim Peters 19/05/2003 Improve tokenisation for messages that have text that looks like Wrinkle Reduction ! Tim Peters 19/05/2003 Decode numeric character entities in html. ! Tim Peters 19/05/2003 Replace

and
tages with single blanks. ! Mark Hammond 15/05/2003 The training dialog now shows a correct progress bar for the *complete* operation - training *and* scoring ! Mark Hammond 15/05/2003 Fix SF#706170 ('Execute test suite fails in Outlook'). ! Mark Hammond 15/05/2003 Save bsddb databases after a training operation (should prevent Outlook ever saving at shutdown). ! Mark Hammond 15/05/2003 Print how long each save takes (so people can complain). ! Mark Hammond 15/05/2003 Keep and print some stats about how many items SpamBayes saw. ! Mark Hammond 14/05/2003 Various changes to urlslurper.py ! Mark Hammond 14/05/2003 Fix SF#737956 ('No hourglass when building folder lists'). ! Mark Hammond 14/05/2003 Fix SF#737955 ('Transient connection error disables plugin'). ! Tony Meyer 14/05/2003 Added missing import to UserInterface.py ! Tony Meyer 14/05/2003 Increased efforts to stop browsers caching the interface pages. ! Tony Meyer 13/05/2003 Added refresh button to review messages page in pop3proxy ui. ! Tony Meyer 13/05/2003 "Added ""check again"" link on 'no more untrained messages page' in pop3proxy ui." ! Tony Meyer 13/05/2003 "Added ""html_ui"":""display_to"" option." ! Tony Meyer 11/05/2003 Fixed KeyError bug in message.py. ! Tony Meyer 11/05/2003 Added SSL support to imapfilter (untested). ! Tony Meyer 6/05/2003 Added getattr backwards compatibility for renamed options. ! Tony Meyer 6/05/2003 IMAP Filter now deletes existing spambayes headers before training. ! Tony Meyer 6/05/2003 "Added ""Storage"":""messageinfo_storage_file"" option." ! Tony Meyer 6/05/2003 Fix for SF#733247 ('crash when using merged-in options'). ! Tim Stone 4/05/2003 Catch exception when a file in the pop3proxy cache mysteriously disappears. ! Tony Meyer 4/05/2003 Fix bug stopping some messages loading into pop3proxy cache. ! Tony Meyer 3/05/2003 Removed OptionConfig.py ! Mark Hammond 3/05/2003 Correct usage doc with respect to default directory. ! Mark Hammond 3/05/2003 Fix SF#715248 ('Pickle classifier should save to a temp file first'). ! Mark Hammond 3/05/2003 Formalised error reporting in Outlook plugin. ! Mark Hammond 3/05/2003 "Created special handling for ""startup errors"" in Outlook plugin" ! Mark Hammond 3/05/2003 Allow test suite to work with bsddb3 or bsddb. ! Tony Meyer 3/05/2003 Fix invalid options names in IMAP and POP3 user interface. ! Tony Meyer 3/05/2003 Fix incorrect state information displaying after configuration. ! Tony Meyer 2/05/2003 Fix temp file problem with web interface on linux. ! Tony Meyer 2/05/2003 Update configuration file reading so that writing uses same delimiters. ! Tony Meyer 2/05/2003 Fix temp file problem with web interface on linux. ! Mark Hammond 1/05/2003 Ignore the pywin.dialogs package in the Outlook plugin install. ! Mark Hammond 1/05/2003 Save the database after an explicit train. ! Mark Hammond 1/05/2003 Fix globals statements in url slurper. ! Mark Hammond 1/05/2003 Fix testtools import in url slurper. ! Mark Hammond 1/05/2003 Print url slurper status to stderr. ! Mark Hammond 1/05/2003 Added socket.error catching in url slurper. ! Mark Hammond 1/05/2003 Avoid slurping non html content. ! Tony Meyer 1/05/2003 Fix bug where url cache would not be in the current working directory by default. ! Tony Meyer 28/04/2003 Stop using IMAP uids as our ids. ! Tony Meyer 28/04/2003 Fix SelectFolder bug in IMAP Filter. ! Tim Stone 28/04/2003 Create IMAP session object for each login. ! Tony Meyer 28/04/2003 Fix for SF#728886 ('In the pop3 UI not able to pass more than 1 server'). ! Tony Meyer 28/04/2003 Fix for incorrect is_boolean code in Options.py ! Tony Meyer 28/04/2003 "IMAP Filter now only retrieves RFC822 headers when iterating, not whole message." ! Tim Stone 28/04/2003 Moved crlf replacement from IMAP to generic message class. ! Tony Meyer 27/04/2003 Minor bug fixes to Options.py ! Tony Meyer 27/04/2003 Fixed configuration file reading bug forcing single space separators instead of any whitespace. ! Tony Meyer 27/04/2003 Fixed Options.py bug reported by Tim Stone. ! Tony Meyer 27/04/2003 Fix hammiefilter calling mergefiles instead of merge_files. ! Tony Meyer 25/04/2003 Added message_from_string functions to message.py and imapfilter.py ! Tony Meyer 25/04/2003 Extra error checking in IMAP Filter. ! Tony Meyer 24/04/2003 "Fix SF#725307 (""Outlook plugin won't load (anymore)"")." ! Tony Meyer 24/04/2003 Fix SF#725466 ('Include a proper locale fix in Options.py'). ! Tony Meyer 24/04/2003 Fix SF#726255 ('Problem if bayescustomize.ini not there'). ! Tony Meyer 24/04/2003 Moved the crlf fixing from generic message class to IMAP filter. ! Tony Meyer 24/04/2003 Major rewrite of Options.py ! Tony Meyer 24/04/2003 Changed options with muliple values to tuples. ! Tony Meyer 24/04/2003 Fixed bug where the IMAP user interface would try to display a folder before logging in. ! Tony Meyer 24/04/2003 Added convert_config_file script. ! Tim Stone 24/04/2003 Fix message.py incorrectly persisting/restoring state. ! Tony Meyer 24/04/2003 Fix Options.py convert and unconvert functions. ! Tony Meyer 24/04/2003 Fix valid characters for IMAP username and password. ! Tony Meyer 24/04/2003 Improve behaviour of convert_config_file script. ! Tony Meyer 24/04/2003 Check that spam/unsure/filter folders exist in IMAP before filtering/training. ! Tony Meyer 24/04/2003 Removed CompatConfigParser.py ! Tony Meyer 24/04/2003 Removed UpdatableConfigParser.py ! Tony Meyer 22/04/2003 Fixed is_valid method for sets. ! Tim Stone 22/04/2003 Added extra verbose output in IMAP Filter. ! Tim Stone 22/04/2003 Corrected counting error in IMAP Filter. ! Tony Meyer 22/04/2003 Fix SF#725616 ('Options.py mergefiles crashes (+ fix)'). ! Tony Meyer 22/04/2003 Improved processing of fetch response in IMAP filter. ! Tim Stone 21/04/2003 Cosmetic changes to the web configuration page. ! Skip Montanaro 21/04/2003 Fix crlf regex in message.py ! Tony Meyer 21/04/2003 Fix SF#725307 ('Outlook plugin won't load (anymore)'). ! Tim Stone 21/04/2003 Rewrote is_valid method in Options.py ! Tony Meyer 20/04/2003 Moved pop3proxy test code into separate module. ! Tony Meyer 20/04/2003 "Allow """" as a valid option if the valid values are defined by a regex and multiple values are allowed." ! Tony Meyer 20/04/2003 Change imapfilter server option to pop3proxy style (i.e. server[:port]) ! Tony Meyer 20/04/2003 Set web interface pages to not cache. ! Tony Meyer 20/04/2003 Fixed imapfilter and pop3proxy web configuration. ! Tony Meyer 20/04/2003 Change the select folder config for imapfilter to two pages. ! Tony Meyer 20/04/2003 Added check for parsedate failing in imapfilter. ! Tony Meyer 20/04/2003 Fix the regex for the date in imapfilter. ! Tim Stone 20/04/2003 Removed unnecessary imports/comments in pop3proxy. ! Tim Stone 20/04/2003 Changed pop3proxy's STAT handling to return a guess at new message size. ! Tony Meyer 19/04/2003 Fixed updating of configuration files. ! Tim Stone 19/04/2003 Correction to regex for smtpproxy servers validation. ! Tony Meyer 19/04/2003 Stop IMAP filter filtering messages marked as deleted. ! Tony Meyer 19/04/2003 Copy IMAP flags along with message. ! Tony Meyer 19/04/2003 Use IMAP date instead of the local one. ! Tony Meyer 19/04/2003 Added utility functions to Options.py to assist people to figure out what is available. ! Tony Meyer 18/04/2003 "Remove support for pop3proxy_port, pop3proxy_server_name and pop3proxy_server_port otpions (long deprecated)." ! Tony Meyer 18/04/2003 Remove option to launch smtpproxy and always do this from pop3proxy (if servers are specified). ! Tony Meyer 18/04/2003 Fix smtpproxy bug that would prevent mail sent in the same session as training mail being delivered. ! Tony Meyer 18/04/2003 Major rework of configuration file reading/options. Section names no longer ignored. ! Tony Meyer 18/04/2003 "Moved interface code out of pop3proxy into ImapUI, ProxyUI and UserInterface.py" ! Tim Stone 18/04/2003 Added web interface support to imapfilter. ! Tim Stone 18/04/2003 Only start browser if required in imapfilter. ! Tony Meyer 18/04/2003 Fix for time retrieval in imapfilter when the date header is missing. ! Tony Meyer 18/04/2003 Change the line endings fix (pop3proxy/imapfilter) to a more robust one (from smtplib). ! Tim Stone 18/04/2003 Converted pop3proxy to use message.py. (notate-body is no longer working) ! Mark Hammond 18/04/2003 Fixed Outlook plugin to work in non-English locales. ! Tim Stone 17/04/2003 Corrected newline mangling in imapfilter. ! Tim Stone 17/04/2003 Corrected folder comparison operator in imapfilter. ! Tim Stone 17/04/2003 Refactored functionality into an IMAPSession class. ! Tim Stone 17/04/2003 Added -p option for password prompt in imapfilter. ! Tim Stone 17/04/2003 Corrected imapfilter training error which would result in no training being done. ! Tim Stone 17/04/2003 Corrected an error in the timed loop that unnecessarily kept imap sessions open. ! Tim Stone 17/04/2003 Moved the header repaid regex into the message class. ! Tony Meyer 17/04/2003 Added ConfigParser from Python 2.3 which solves many problems in the 2.2 version. ! Tony Meyer 17/04/2003 Updated UpdatableConfigParser to use new 2.3 ConfigParser. ! Tony Meyer 16/04/2003 Fix an imapfilter invalid date problem. ! Tim Stone 14/04/2003 Fixed the imapfilter docstring not printing. ! Tim Stone 14/04/2003 Changed imapfilter -e argument to y/n. ! Tim Stone 14/04/2003 Added -l argument to imapfilter allowing looping. ! Tim Stone 14/04/2003 Correctly extract timestamp for new messages in imapfilter. ! Tim Stone 13/04/2003 Raise an error if message.py is asked to remember an unknown classification. ! Tim Stone 13/04/2003 General cleanup of imapfilter. ! Tim Stone 13/04/2003 Remove old message ids from the message info db when using imapfilter. ! Skip Montanaro 13/04/2003 Fix train() in mboxtrain. ! Tony Meyer 13/04/2003 Fix for user interface showing incorrect server strings when using pop3proxy_service. ! Tony Meyer 13/04/2003 Various speed improvements to imapfilter. ! Tim Stone 12/04/2003 Functional version of the imapfilter. ! Tim Stone 10/04/2003 Made base message class more abstract and added a SBHeaderMessage class. ! Tim Stone 10/04/2003 Made imapfilter use the new message class. ! Tony Meyer 9/04/2003 Update imapfilter to reflect message class changes. ! Tony Meyer 8/04/2003 Introduce a IMAPMessage class based on the spambayes Message class. ! Tony Meyer 8/04/2003 Introduce an iterable IMAPFolder class. ! Tony Meyer 8/04/2003 Allow filtering of multiple folders in IMAP filter. ! Tim Stone 8/04/2003 Added methods to message.py to support copying one message to another. ! Tim Stone 8/04/2003 Added logic to imapfilter to ensure that classification and training memory is preserved. ! Tony Meyer 7/04/2003 First check-in of IMAP filter. ! Tim Stone 7/04/2003 First check-in of message.py ! Tim Stone 7/04/2003 Changed imapfilter to use the message class. ! Tony Meyer 3/04/2003 Expire messages from the unknown pop3proxy cache as well as ham/spam caches. ! Tony Meyer 3/04/2003 "Kick off expiry check each time a client connects to the proxy rather than on startup, for those who have the proxy stable!" ! Tony Meyer 3/04/2003 "Add ""show clues"" button to the review message page in pop3proxy ui." ! Tim Stone 28/03/2003 Unicode print error fix in notesfilter. ! Mark Hammond 23/03/2003 Fix SF#707491 ('Pop3 proxy service code for Windows doesn't work...'). ! Mark Hammond 20/03/2003 Ensure database is saved before testing outlook plugin. ! Mark Hammond 20/03/2003 Fix error in testing outlook plugin (getting wrong end of sorted list). ! Tim Stone 20/03/2003 Added SF#703283 ('mboxtrain only trains on cur in maildir'). ! Mark Hammond 18/03/2003 Ensure all buttons are greyed during filter process in Outlook plugin. ! Mark Hammond 18/03/2003 When running Outlook plugin from a binary redirect output to a log. ! Mark Hammond 18/03/2003 Version 002 of the binary. ! Mark Hammond 17/03/2003 "Warn, but ignore errors walking the folder tree in Outlook plugin." ! Mark Hammond 17/03/2003 "Fix SF#704921 ('""Train now"" (outlook) fails ')." ! Mark Hammond 17/03/2003 Prevent a single error filtering a message from stopping the whole filter process in Outlook plugin. ! Mark Hammond 16/03/2003 Allow messages to be scored after training in Outlook plugin. ! Mark Hammond 16/03/2003 Fix bug in Outlook plugin where filter operation report was reporting incorrect total. ! Tony Meyer 13/03/2003 Revert Options.py to ConfigParser from UpdatableConfigParser. ! Mark Hammond 12/03/2003 Added pop3proxy_service.py ! Tony Meyer 12/03/2003 "Update web ui so that boolean options are radio buttons rather than text boxes, and multiple choice options are checkboxes." ! Tony Meyer 12/03/2003 Separated out pop3proxy options and header options in pop3proxy web ui. ! Tony Meyer 12/03/2003 Adds UpdatableConfigParser. ! Tony Meyer 12/03/2003 Changes Options.py to use UpdatableConfigParser rather than ConfigParser. ! Tony Meyer 11/03/2003 Fixes a bug in pop3proxy/smtpproxy where headers will appear in the message body. ! Tony Meyer 10/03/2003 Added level & evidence headers in pop3proxy. ! Mark Hammond 9/03/2003 "Correct ""data"" directory location in export.py." ! Tony Meyer 9/03/2003 Added pop3proxy include_prob option to (optionally) note the score/prob in the classification header. ! Tim Stone 9/03/2003 "Added configuration for pop3proxy include_prob option, add_mailid_to and strip_incoming mailIds options." ! Tim Stone 8/03/2003 Fix SF#700165 ('MoveFileEx doesn't exist on Win98'). ! Tim Peters 8/03/2003 List unique tokens one per line in Outlook plugin's ShowClues. ! Mark Hammond 7/03/2003 Handle MAPI exceptions better in Outlook plugin. ! Mark Hammond 7/03/2003 "Centralise detection of ""not found"" exceptions in Outlook plugin." ! Mark Hammond 7/03/2003 Supress errors in outlook plugin when hotmail connector can't save the message. ! T. Alexander Popiel 7/03/2003 Added another regime to regimes.py. ! Tim Stone 6/03/2003 Added SF#690928 ('turn off saving messages in popproxy'). ! Skip Montanaro 6/03/2003 Catch extra exception in header parse errors. ! Tim Stone 6/03/2003 "Fix SF#698852 (""can't classify messages"")." ! Mark Hammond 4/03/2003 Fix a Outlook plugin bug that could cause incorrect word scores to be used/saved when a bsddb database is used. ! Mark Hammond 4/03/2003 Remove unused 'wordcache' instance variable in storage.py. ! Mark Hammond 4/03/2003 Show all tokens in message when showing clues in Outlook plugin. ! Mark Hammond 4/03/2003 "Fix a bug in the Outlook plugin test code that used *all* ham/spam words, not just top 50." ! Mark Hammond 4/03/2003 "Only remember source folder when filtering, not just scoring in Outlook plugin." ! Mark Hammond 4/03/2003 "Only attempt to create ""Spam"" field on a mail item in Outlook plugin." ! Mark Hammond 4/03/2003 If no items are found in Outlook plugin don't attempt to recurse folders. ! Mark Hammond 4/03/2003 Fix SF#696476 ('Manual filtering in outlook fails'). ! Mark Hammond 4/03/2003 Fix SF#697120 ('Manual filtering in Outlook (still) fails'). ! Jeremy Hylton 4/03/2003 Band-aid decode_header() in pop3proxy.py ! Mark Hammond 3/03/2003 Fix manager.py calling shutil.move (does not exist pre Python 2.3). ! Mark Hammond 3/03/2003 Fix SF#696995 ('Invalid HTML comments are not ignored'). ! Skip Montanaro 3/03/2003 Note when subject charset is invalid (rather than raising an exception). ! Tony Meyer 2/03/2003 Added support to smtpproxy for extracting an id in a Mozilla style forwarded message (HTML table). ! T. Alexander Popiel 1/03/2003 "Add option to mkgraph to spit out counts *or* error rates, and n-day averages *or* cumulative." ! Tony Meyer 1/03/2003 Small modifications to smtpproxy related pop3proxy options. ! Tony Meyer 1/03/2003 Expose options for adding an id to incoming mail in pop3proxy. ! Tony Meyer 1/03/2003 Expose options for using smtpproxy. ! T. Alexander Popiel 28/02/2003 Put all regimes into regmies.py. Define fpfnunsure and fnunsure regimes. ! T. Alexander Popiel 28/02/2003 Fix name conflict between regimes list and regimes source file in incremental.py ! T. Alexander Popiel 28/02/2003 Reduce the amount of progress output in incremental.py ! Tony Meyer 27/02/2003 "Add options to add an id (as a header or in the body), strip such ids from incoming mail, find a message via the id, train messages by forwarding/bouncing to smtpproxy." ! Tony Meyer 27/02/2003 First check in of smtpproxy. ! T. Alexander Popiel 27/02/2003 "Added various files relating to incremental training (or ""self training"") regimes." ! Tim Stone 27/02/2003 Fix SF#693423 ('email message generates error in pop3proxy.py'). ! Mark Hammond 26/02/2003 "Fix bug in dbmstorage.py for Python 2.2, which tried bsddb3 twice if it failed." ! Tim Stone 25/02/2003 First check in of Lotus Notes filter. ! Tim Stone 25/02/2003 Add option for pop3proxy to notate Subject: header. ! Tony Meyer 25/02/2003 Fix bug in Corpus.get() which would never return the default value. ! Mark Hammond 18/02/2003 "Store Outlook plugin files in the ""correct"" Windows directory." ! Neil Schemenauer 16/02/2003 Add -c and -d options to mailsort.py. ! Neil Schemenauer 16/02/2003 First check-in of dump_cdb.py ! Mark Hammond 13/02/2003 Add SF#685746 ('Outlook plugin folder list sorted alphabetically'). ! Mark Hammond 13/02/2003 Handle exceptions when opening folders in Outlook plugin better. ! Skip Montanaro 13/02/2003 Split BAYESCUSTOMIZE environment variable using os.pathsep. ! Mark Hammond 12/02/2003 Check for correct exception when removing file in Outlook addin. ! Mark Hammond 12/02/2003 Check for bsddb3 before bsddb (previously bsddb3 would never be found). ! Tim Stone 10/02/2003 Changed BAYESCUSTOMIZE environment varaible parsing from a split to a regex to fix filenames with embedded spaces. ! Tim Stone 8/02/2003 Ensure that nham and nspam are instances of integer in dbExpImp.py ! Tim Stone 8/02/2003 Ensure that nham and nspam becoming strings doesn't break classification. ! Tim Stone 8/02/2003 Added ability to put classification in subject or to headers (for OE). ! Mark Hammond 7/02/2003 Fix some errors using bsddb3 in Outlook plugin. ! Mark Hammond 4/02/2003 "Fix SF#642740 ('""Recover from Spam"" wrong folder')." ! Mark Hammond 3/02/2003 Change train.py to be able to work with a bsddb database. ! Mark Hammond 3/02/2003 If a new bsddb or bsddb3 module is available use this instead of a pickle in the Outlook plugin. ! Mark Hammond 3/02/2003 Add tick-marks to the filter dialog. ! Mark Hammond 3/02/2003 Fix SF#677804 ('Untouched fitler command error'). Index: MANIFEST.in =================================================================== RCS file: /cvsroot/spambayes/spambayes/MANIFEST.in,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** MANIFEST.in 25 Jan 2003 19:48:55 -0000 1.4 --- MANIFEST.in 7 Jul 2003 00:09:27 -0000 1.5 *************** *** 6,9 **** --- 6,10 ---- recursive-include utilities *.py *.txt recursive-include testtools *.py *.txt + recursive-include windows *.py *.txt include *.txt *.py Index: WHAT_IS_NEW.txt =================================================================== RCS file: /cvsroot/spambayes/spambayes/WHAT_IS_NEW.txt,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** WHAT_IS_NEW.txt 22 Jun 2003 01:44:53 -0000 1.5 --- WHAT_IS_NEW.txt 7 Jul 2003 00:09:27 -0000 1.6 *************** *** 9,141 **** noted in the "Transition" section. ! New in Alpha Release 3 ====================== Outlook Plugin -------------- ! o The Outlook Plugin now works with bsddb[3] databases, and uses them ! rather than pickles, if available. ! o The Outlook Plugin now stores files in the "correct" windows directory. ! These will be automatically migrated. ! o Show all tokens in message when showing clues in Outlook plugin. ! o Fix a bug in the Outlook plugin test code. ! o Only create "Spam" field on mail items in Outlook plugin. ! o MAPI exceptions are better handled. ! o Errors when hotmail connector cannot save the message are suppressed. ! o Tokens are listed one per line in Show Clues. ! o Messages can be scored after training. ! o Plugin *may* now work correctly in non-English locales. ! o Databases are saved after any training operation. ! o Handle malformed messages better in the Outlook plugin. ! o In Outlook plugin, create our own toolbar, rather than using the ! standard one. ! o Use 'wait' cursor when incremental training in Outlook plugin. ! o In Outlook plugin, save config when dialog closes and not at shutdown. ! o Clean up toolbar images. ! o In Outlook plugin, no longer default to the "Inbox". ! o In Outlook plugin, when filtering, saving the spam score is no longer ! fatal. ! o 2 new [General] options - delete_as_spam_message_state and ! recover_from_spam_message_state. ! o Prevent "Deleted items", Outbox and Sent Items from appearing ! in the folder list. ! o Allow either spam or unsure messages to be marked as read as they are filtered. ! o Significant improvements to the toolbar. ! o Standardised name from "Anti-Spam" to "Spambayes" ! o Significant changes to configuration (moving from a pickle to .ini files). POP3 Proxy ---------- ! o The POP3 Proxy can now include the classification in the "To" or ! "Subject" headers, which allows Outlook Express users to perform ! filtering on the classification. ! o The POP3 Proxy can add an id (as a header or in the body) to track ! emails. This can be used with the SMTP Proxy, or to find a particular ! message from the web interface. ! o Added include_score option to (optionally) note the score of the message ! in a header. ! o Added level (thermostat) and evidence headers for pop3proxy. ! o Added pop3proxy_server to allow pop3proxy to run as a Windows service. ! o Improved configuration page for the user interface. ! o A "Show Clues" button next to each message in the "Review" page of the ! web interface. ! o Messages in the "unknown" cache are expired, just like those in the ! "ham" and "spam" caches. ! o Messages are expired (if old enough) each time a client connects to the ! proxy, rather than on the proxy startup. ! o pop3proxy_port, pop3proxy_server_name and pop3proxy_server_port options ! were removed (these were deprecated in Alpha 2). ! o If a file is removed from the cache (not by the proxy) this no longer ! causes an exception. ! o Messages received in quick succession (within the same second) may not ! have been visible in the "review" page; fixed this. ! o Added "Refresh" button to "Review" page. ! o Improved proxying of "STAT" POP3 command so that a guess at the message ! size is returned. ! o Web interface encourage browsers not to cache the pages. ! o Added an option to display who a message is to in the "Review" page. ! o A new option to correct for a much higher ratio of spam to ham (or ! vice-versa) is available via the interface page. Developer --------- ! o Added base message classes for use by all Spambayes applications - ! currently used by the IMAP filter and POP3 proxy. ! o Major rework of the configuration file loading and format of Options.py. ! o Test code moved out of pop3proxy.py. ! o Web interface code abstracted out of pop3proxy.py. ! o A version information repository for all applications. General ------- ! o A utility to dump the contents of a CDB database. ! o -c and -d options to mailsort.py ! o A basic filter for Lotus Notes. ! o A SMTP Proxy to allow training via forwarding/bouncing messages. ! o Various files to test "incremental training" (or "self training"). ! o Option to mkgraph to spit out counts *or* error rates, and n-day ! averages *or* cumulative. ! o Note when the subject charset is invalid (rather than raising an ! exception). ! o A filter for IMAP. ! o A script to test the effectiveness of following URLs in messages when ! insufficient clues are otherwise present. ! o 'Nonsense' HTML tags are stripped rather than replaced with a space ! (e.g. Wrinkle Reduction becomes ! "Wrinkle" and "Reduction" rather than "Wr", "inkle", "Reduc" and ! "tion"). ! o Decode numeric character entities so that ! your septic system becomes "your septic system". ! o

and
tags are replaced with single blanks. ! o DB classifier keeps a list of "changed words" to prevent saves from ! updating *all* words. ! o DB classifier no longer caches hapaxes. ! o In muttrc, fix incorrect Spambayes header name. ! o Integrated code for the VM mailer into spambayes.el ! o In hammiefilter, make untrain mode work. Transition ========== ! o If you are using the Outlook Plugin and a recent bsddb or bsddb3 is ! available, you will need to do a full retrain. ! o If you had set the environment variable BAYESCUSTOMIZE to point to more ! than one configuration file, you will need to change the separator ! character from a space to the path separator for your platform (a ! semi-colon on windows, a colon on *nix and a newline on Mac OS9) ! o If your old configuration file used the pop3proxy_port, ! pop3proxy_server_name or pop3proxy_server_port options, these will no ! longer work. Copy the values in them and use the web interface to ! update your configuration file. ! o Your old configuration file more than likely includes deprecated ! settings. The old settings will still work for the moment, but you ! should take the time to update them. The "convert_config_file.py" ! script will convert the file for you, without loss of comments, and ! avoiding whitespace changes where possible. ! o If you are using POP3 proxy, you should use the web interface to set the ! location of the "message info" database (a full pathname is ! recommended). ! o If you are using POP3 proxy, it is recommended (but not required) that ! you do a full retrain to take advantage of the "message info" database. --- 9,55 ---- noted in the "Transition" section. ! New in Alpha Release 4 ====================== Outlook Plugin -------------- ! o Display a message for "Delete as Spam" or "Recover from Spam" when ! SpamBayes is not enabled. ! o The toolbar is now initialized when "Outlook Today" is the default view. POP3 Proxy ---------- ! o Fix a bug where long attachments would be broken. ! o If an exception occurs parsing a message, recover and append a new ! 'exception' header. ! (This will be added to other SpamBayes applications by the next ! release). ! o Stop including the trailing dot in messages. ! ! IMAP Filter ! ----------- ! o In imapfilter, try to append without flags if appending fails. ! o Fix the -i switch in imapfilter and an import error. ! o Don't try and get password from options if -p is specified in imapfilter. Developer --------- ! o Various changes/improvements to storage.py. ! Note that this includes a fix for a potentially serious bug introduced ! in a3 which could result in incorrect token counts. General ------- ! o The web interface (used by pop3proxy and imapfilter) now shows the ! correct date and time in the footer. ! o A new stripper to squash yet another way of hiding content in HTML spam, ! like Ereywl55ctions to hide ! Erections. Transition ========== ! Transition between release a3 and a4 should be seemless. Refer to the a3 ! release for information about transitioning between a2 and a4. *************** *** 143,149 **** =================== The following bugs tracked via the Sourceforge system were fixed: ! 677804, 642740, 685746, 693423, 696995, 696476, 697120, 698852, 700165, ! 704921, 707491, 725307, 725616, 725307, 725466, 726255, 728886, 715248, ! 733247, 737956, 737955, 706170, 737986, 743515, 749277 A url containing the details of these bugs can be made by appending the --- 57,61 ---- =================== The following bugs tracked via the Sourceforge system were fixed: ! 761677, 761670 A url containing the details of these bugs can be made by appending the *************** *** 154,160 **** Feature Requests Added ====================== ! The following feature requests tracked via the Sourceforge system were ! fixed: ! 690928, 703283 A url containing the details of these feature requests can be made by --- 66,72 ---- Feature Requests Added ====================== ! The following feature request tracked via the Sourceforge system was ! added: ! 755098 A url containing the details of these feature requests can be made by Index: setup.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/setup.py,v retrieving revision 1.18 retrieving revision 1.19 diff -C2 -d -r1.18 -r1.19 *** setup.py 28 Apr 2003 00:36:03 -0000 1.18 --- setup.py 7 Jul 2003 00:09:27 -0000 1.19 *************** *** 43,46 **** --- 43,47 ---- 'mboxtrain.py', 'imapfilter.py', + 'notesfilter.py', ], packages = [ From anadelonbrin at users.sourceforge.net Sun Jul 6 18:19:33 2003 From: anadelonbrin at users.sourceforge.net (Tony Meyer) Date: Sun Jul 6 20:19:36 2003 Subject: [Spambayes-checkins] spambayes/spambayes __init__.py,1.4,1.5 Message-ID: Update of /cvsroot/spambayes/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv26151/spambayes Modified Files: __init__.py Log Message: Opps. Forgot to tick this box last time. Update __version__ information (which wasn't done for a3). Index: __init__.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/spambayes/__init__.py,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** __init__.py 31 Jan 2003 19:59:52 -0000 1.4 --- __init__.py 7 Jul 2003 00:19:31 -0000 1.5 *************** *** 1,3 **** # package marker. ! __version__ = '1.0a2' --- 1,3 ---- # package marker. ! __version__ = '1.0a4' From anadelonbrin at users.sourceforge.net Sun Jul 6 18:46:31 2003 From: anadelonbrin at users.sourceforge.net (Tony Meyer) Date: Sun Jul 6 20:46:35 2003 Subject: [Spambayes-checkins] spambayes WHAT_IS_NEW.txt,1.6,1.7 Message-ID: Update of /cvsroot/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv29220 Modified Files: WHAT_IS_NEW.txt Log Message: Typo Index: WHAT_IS_NEW.txt =================================================================== RCS file: /cvsroot/spambayes/spambayes/WHAT_IS_NEW.txt,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -d -r1.6 -r1.7 *** WHAT_IS_NEW.txt 7 Jul 2003 00:09:27 -0000 1.6 --- WHAT_IS_NEW.txt 7 Jul 2003 00:46:29 -0000 1.7 *************** *** 50,54 **** Transition ========== ! Transition between release a3 and a4 should be seemless. Refer to the a3 release for information about transitioning between a2 and a4. --- 50,54 ---- Transition ========== ! Transition between release a3 and a4 should be seamless. Refer to the a3 release for information about transitioning between a2 and a4. From anadelonbrin at users.sourceforge.net Sun Jul 6 22:16:43 2003 From: anadelonbrin at users.sourceforge.net (Tony Meyer) Date: Mon Jul 7 00:16:47 2003 Subject: [Spambayes-checkins] website applications.ht, 1.12, 1.13 developer.ht, 1.10, 1.11 download.ht, 1.9, 1.10 index.ht, 1.15, 1.16 Message-ID: Update of /cvsroot/spambayes/website In directory sc8-pr-cvs1:/tmp/cvs-serv17589 Modified Files: applications.ht developer.ht download.ht index.ht Log Message: Add info about -bugs mailing list. Update references to a3 to a4. Index: applications.ht =================================================================== RCS file: /cvsroot/spambayes/website/applications.ht,v retrieving revision 1.12 retrieving revision 1.13 diff -C2 -d -r1.12 -r1.13 *** applications.ht 3 Jul 2003 01:54:52 -0000 1.12 --- applications.ht 7 Jul 2003 04:16:41 -0000 1.13 *************** *** 30,34 **** You can download it from his website. This is currently at version 003.

!

Download the alpha3 release.

Alternatively, you can use CVS to get the code - go to the CVS page on the project's sourceforge site for more.

--- 30,34 ---- You can download it from his website. This is currently at version 003.

!

Download the alpha4 release.

Alternatively, you can use CVS to get the code - go to the CVS page on the project's sourceforge site for more.

*************** *** 45,49 ****

Availability

!

Download the alpha3 release.

Alternatively, use CVS to get the code - go to the CVS page on the project's sourceforge site for more.

--- 45,49 ----

Availability

!

Download the alpha4 release.

Alternatively, use CVS to get the code - go to the CVS page on the project's sourceforge site for more.

*************** *** 60,64 ****

Availability

!

Download the alpha3 release.

Alternatively, use CVS to get the code - go to the CVS page on the project's sourceforge site for more.

--- 60,64 ----

Availability

!

Download the alpha4 release.

Alternatively, use CVS to get the code - go to the CVS page on the project's sourceforge site for more.

*************** *** 77,81 ****

Availability

!

Download the alpha3 release.

Alternatively, use CVS to get the code - go to the CVS page on the project's sourceforge site for more.

--- 77,81 ----

Availability

!

Download the alpha4 release.

Alternatively, use CVS to get the code - go to the CVS page on the project's sourceforge site for more.

*************** *** 93,96 ****

Availability

!

Download the alpha3 release.

Alternatively, use CVS to get the code - go to the CVS page on the project's sourceforge site for more.

--- 93,96 ----

Availability

!

Download the alpha4 release.

Alternatively, use CVS to get the code - go to the CVS page on the project's sourceforge site for more.

Index: developer.ht =================================================================== RCS file: /cvsroot/spambayes/website/developer.ht,v retrieving revision 1.10 retrieving revision 1.11 diff -C2 -d -r1.10 -r1.11 *** developer.ht 22 Jun 2003 02:00:44 -0000 1.10 --- developer.ht 7 Jul 2003 04:16:41 -0000 1.11 *************** *** 30,34 ****

So what needs to be done

!

Currently (May) work is now being focused on improving deployment of the system (actually building the applications and the code so that Tim's sister <wink> can use the system), with the aim of eventually --- 30,34 ----

So what needs to be done

!

Currently (July) work is now being focused on improving deployment of the system (actually building the applications and the code so that Tim's sister <wink> can use the system), with the aim of eventually Index: download.ht =================================================================== RCS file: /cvsroot/spambayes/website/download.ht,v retrieving revision 1.9 retrieving revision 1.10 diff -C2 -d -r1.9 -r1.10 *** download.ht 3 Jul 2003 01:54:52 -0000 1.9 --- download.ht 7 Jul 2003 04:16:41 -0000 1.10 *************** *** 4,9 ****

Source Releases

!

The third pre-release of version 1.0 of the SpamBayes project is available. ! Download version 1.0a3 from the sourceforge Files page as either a gzipped tarball or a zip file of the source files.

--- 4,9 ----

Source Releases

!

The fourth pre-release of version 1.0 of the SpamBayes project is available. ! Download version 1.0a4 from the sourceforge Files page as either a gzipped tarball or a zip file of the source files.

Index: index.ht =================================================================== RCS file: /cvsroot/spambayes/website/index.ht,v retrieving revision 1.15 retrieving revision 1.16 diff -C2 -d -r1.15 -r1.16 *** index.ht 22 Jun 2003 02:00:44 -0000 1.15 --- index.ht 7 Jul 2003 04:16:41 -0000 1.16 *************** *** 5,9 ****

News

!

Third pre-release available. See the download page for more.

Spambayes (in particular the Outlook plugin) was recently featured in an --- 5,9 ----

News

!

Fourth pre-release available. See the download page for more.

Spambayes (in particular the Outlook plugin) was recently featured in an *************** *** 96,100 ****

The code is currently available from a variety of methods from the downloads page. The current release is ! 1.0 alpha 2.

--- 96,100 ----

The code is currently available from a variety of methods from the downloads page. The current release is ! 1.0 alpha 4.

*************** *** 107,111 ****

Mailing lists

!

There are currently four mailing lists of interest:

  • --- 107,111 ----

    Mailing lists

    !

    There are currently five mailing lists of interest:

    From richiehindle at users.sourceforge.net Mon Jul 7 14:58:40 2003 From: richiehindle at users.sourceforge.net (Richie Hindle) Date: Mon Jul 7 16:58:44 2003 Subject: [Spambayes-checkins] spambayes/spambayes/resources ui.html, 1.14, 1.15 ui_html.py, 1.14, 1.15 Message-ID: Update of /cvsroot/spambayes/spambayes/spambayes/resources In directory sc8-pr-cvs1:/tmp/cvs-serv5072 Modified Files: ui.html ui_html.py Log Message: Prevent the "Show clues" links from word-wrapping and making all the table rows two lines high. Index: ui.html =================================================================== RCS file: /cvsroot/spambayes/spambayes/spambayes/resources/ui.html,v retrieving revision 1.14 retrieving revision 1.15 diff -C2 -d -r1.14 -r1.15 *** ui.html 15 May 2003 01:29:12 -0000 1.14 --- ui.html 7 Jul 2003 20:58:37 -0000 1.15 *************** *** 235,239 **** id="spam" value='spam'/> ! Show clues     --- 235,239 ---- id="spam" value='spam'/> ! Show clues     Index: ui_html.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/spambayes/resources/ui_html.py,v retrieving revision 1.14 retrieving revision 1.15 diff -C2 -d -r1.14 -r1.15 *** ui_html.py 15 May 2003 01:29:12 -0000 1.14 --- ui_html.py 7 Jul 2003 20:58:37 -0000 1.15 *************** *** 5,84 **** import zlib ! data = zlib.decompress("xÚÝ;msÛÆÑß3“ÿpAdž4•HJ²Ý„\"1µe%ÎS;V%¦L&£9\002G\022\025€Cƒ$>žþ÷îîÝ\001‡\027I\ ! tÓ´3•=\"»ÛÛÝÛ÷=;zûñlñÓÅ9{·øðž]üøæý÷gÌ;\034ÿzr6\036¿]¼Õ\003/F“#¶(xVÆ\ ! *–\031OÆãó\037¼àË/f\033•&ô)x„Ÿ*V‰`q4÷è›\027\\å<]ò­(Ù¥(Ø÷™\022ÅŠ‡b6¦\011¸&\025Š³R\ ! ù¡ø{\025ßν‹‚¯Sî±PÂìLͽL\036†<Ü\010\007\027œéÁçŸßçq!JgÅbS\0350 òÿxÆŽ¾ùÄM&S\ ! úϾû°xtÛÃ3€QÈd`û\003–V¥:,Ä-Oâˆ+x\001C¥’…ŬT[âÁRF[ö‰­\000”}3yÆx\021ó䀕w\ ! qY\036°Hn…ŠC~ÊR^¬ãlÊ&ì\037_~¡ø\022¸½Ã:œ¼’E\012s[\000¾ü‚O“8»÷¡Ld1e¿›ÀOHƒ|z\ ! \033ËèѼ…\023mÆ^M^LV+\034\033\031V0n;¼\023ñz\0038.e\022ÑŒÛXÜÑν)\031àÉ\023ÝhɳŒ6Yòðf\ ! ]È*‹`§p\"`§S–ó(Š³õüeýõ0\021+€qôòôË/Xý³”E$ŠC%s\030ÊïY)á<Ø2\001˜Có–R)™ö¦\ ! \022Þ(è„\020á\\Æÿ/`ÞÉɳ\026Ù\015—^Ò@*Ê’¯…>/…\014íà+î\033\022\012Í\007xGkK\021¢ÒÙ³Ö8ºÈýîë\011þ\ ! ;ewq¤6 \007/Ÿ¹\013\021c\000Ûáájµâbr:€‡Ë'\031c÷\036Z4|ð\006+#ñf{\0009ÉïÍ™ƒ¾€phF—lP@'\ ! $‚½™Ãòj&7\022÷\010DgÒcÀ\016UŸ–™>Ï–|Š\020ÿ™‰Uü\016Œä»!¹9ž<;­¡MÐO‡Ù6\033[S1\033\ ! \033[\013_‰‰hlñ‹Gïñ³(¾eaÂËrîk\005ò\0033Ræ`àp\005˜\006°g^0‹Ó5+‹pîë7£u¼ò\031Ø«u6÷ù\ ! ²Lã(J„?\016žgË2?\005<\000B\013šÙHŸ‚ݨ½Y^Ȩ\012Õ\017ý\015\022•\031A <ãÈ\"¬øú€ø½\024@ nÊ.¶j\003FÄ`\007p\015×G³qî\012Ôk„\012\ ! §ÆÓ²5š\037ˆ*Aó\017˜,ô\0068Jð\033\013ª¡­\012™²2,¸\002{\026k´À¶¾Î¢¾\017B;\022ê¼&\001\034@Ñ\004\030\ ! þåÖZU\030\006Ðz\037²æ‡,D>áæ\010Œô¯Ü\010¡\016˜Â¼\021´\035Ç€\\iü\033b\015F8[WH8XERE0ˆ™¸kÌm‡I‡\ ! d¥µ\027,E\015r\002}\032x›-\023¼Üvç\033‘€µÄ)ÚÊ÷\034kÃ,˜!\001\017481.\006-yY@AÉ\\n\003\0057âó\ ! \002\012Œ¢7h]\035œœ@Ì\014{Všt¤oÂ*7ú÷Y(’\004V†˜ôøÍRE0ƒ(Ô‚ƒQ¯³Þ¼öQ{pë¹\0141\024mÍ\ ! Èð«\010´\010àô ú1\010Â\031ìë£FPX\010y”ß\001¨¯\023\020\000=qÃ@­~\020eZ`¾Ž7KÅUUêxÓ,|1ñÁaä\ ! KßmÐéÄxˆ§óhˆ\006\012:ÁZ\013/g\005…eè$™ÃxЂ\017²TÃ1Wi#)ž\006\016(\011Û\001÷@“P\025¬LšP¬Y\003\ ! Úܞ툮N­îa¢vÞÙ`¬ˆ&€ßJpuQ•'à\037‘0\033‹Œ¬\011²\007\010¿PV\014Í&j_\026ãnໃäê\023j‰­–M\ ! ä¹\036\\à³gòù\007&Ô\025Qûlótxn\013Ø`ø®!{\017e\022÷Û·HÇIkÆÅÇ‹\023Fƒ\030?ehI€G³eÐYz\001¾\ ! »¼\"ãé\005GGG\023ÃÙx\031\034¸Ç\013sɘÉ6\020Še‹\032‚ñ\"ø§\016 ‘ƒyÃyüy\015By+4¶ \011\010ŠN³œvôÅ\ ! Ý“Ó¢+\001Q)Ìô\002\027çQgƒ>dm­K½ú±m”T<Ùm—VöD1rŠ\007¢¥(^Åè¶vÜ5«RÌ\032:\0332ø–\036<¾\ ! ì]ÕæÉE?feUˆÎ²Š^v‰\\ ?˜Ð”\023Ãô©C\011b>í옷á·×¼ë/ÙtW<ÆnÇ\004¢ù3‘®)ý¼\ ! \022÷¾1šîïÎ\032׎»ÛÔ¥\000\020 U¼~Ì4Û\012\001–üñ ªj UAbø\036\023xgZ\037ÇþïŸ W\010±À`\000\011Ì\036Š&\ ! Éìpi\027å¶T\"\005\013o\002•Ž°pSbÐ;úÁ™K\002EhXr\030õNÆå¯ãDkKü¤¥Õ…¬\005ÄíÀ…\030Ù\014Z\016.Z\ ! 5\000mö¨¬\\Öñ©8‚³S †¢4H[ž’<ÓÄZg!~ä%h.V´6²l@è•5Ï\0326iÄüà’>ëùÈ#bVí›\ ! vŒ”\014¡È´áXIO ®ÖŽ\004K-àPuMÃ(+¦ç[C)xs´â5Á¦¼PS\015\016ûl#Â\033\"çÀLÈ\"07]VJ\001\ ! /V\020X\013,\001\020ðƒº®€…¯\030–ù\013„ìCF\017!&\000óߊ•(|Hwù­)ï\030Æè¥èé\017LÙÀX\025d9¦Ã„\013\001m\"\ ! \012½èm\\†¼ˆØ˜\021tø\0043\002¿Q\010˜­\002Ì(ibd½ZSRêàƒ£c \001„\002\002¸\ ! ïÎ\027ŽÍ0%\002J›üM\034E\020î0,½Í}à¢\0046`Ðg¾ê„ÊŸ¸öâ\021\000\031\010¼^¯¿\015.×ñˆ\011?`¬\025nØç~Äì\ ! D -\014Êj™ÆÊb°–\016þoˆ‰þP¡\033\014v\027È/YA\"Ç!\036Žâ\022ñ\003\020GN\005µ\025öh“¼\013\026 r à›§0¸4Ó\ ! ~õ~Èõ݈þ\001f~.Á\017Yèn„ß\017i1Ù/ÒV|ÛXŠ°ˆsK\026¦ñã¿ñ[®ßúÁx<ûêç³·¯\027¯6)q•\ ! iM™¶A{¸’Úg$/¤)¥|jð‰Wl/’a•B8?B\005\024tâ\004\006¿´{ZZ$—Á`\005¤]¯qÄåRÞ5u\020Û¦ô‡\017Ë6<ýþÉP\ ! ¾[Q_ÂôÞ<œí\005}M»\024S' Å\006‡.O³B†7_1öõá~§Y7\\ÈÁ\032åµ\027\\Æá&\026ì]œE QX¸-èÍ\037\ ! ÁPBp–a¾­Ë±ƒP@tÝ6ãû¸T\004¤´¯þ˜Sev$‹õ\003`Lz\023bÕ¦ð{u¨^èRð(–Öƒ\032MÜNI\011ÿt\ ! þÓ°\003ET#-ͶÚì›çÚyöÿ\026H \032x?§çÿ,\012˜\002»!\005<ÿg\021 ´ÝA\000ŸÛ‰í€\035Õ:bw±JR?\007\ ! WØ£\013\001\036åD«î2áÙ\015jnЄGÚÔ>þ؇DYÅ\016vøNŠÝãv;r4™á ~\032?m»\036Žî>§XYå‰\ ! äQ?‘AŽè1¯vãÄ¡–,´\034:\023\020\026\022}i•¨8ç…\"¬\016#®¸5”ç1u04hÆm’çxPY\\§Ø_\012 „K©È\ ! NÔPäÝbÕ›á{ËJýÝp\022˜è\034ÄÇ‚º@‚r·»Lê\004\023\002Å\014¤ú(ÆýîS¾9u\013À\030\026C²ÌÍNŠ’«\ ! BÞ38Ñý¹íT8\0273ÓÝÝi\012ëÿ֚3$\017w\033°ÚmyÀÐäÊU­>¼Íg‚{÷(´F9Ÿ\006yfæ6à¬0\ ! Öµ†=,½˜3'ñZcW»Âº\011FêK‰]#ÄŒzYYd£2*&\037:%§8sk\015M»€\025\"•·t\011£¾\011°¿s\005å\016\022\ ! á?W¢Ø\016ëA=ܨ\002¾ú;¾òû,Ä1Ïr\012¾7\002édX¾nŸú'“î)´\031n\015Â]WÓδ÷\027¢!–?Ií\012â\ ! \003\023þ\016ÓëLðv‹á\033âq­Wkcö8ñG»\021Ž¶•JBqd»MVw±Ï‹Ûü+Œ@\016^)®Êá²Y=lC·\037ªt\011\ ! ˆ\000\006¨¼uá®S—ƱPVxãéèøäv@\003jó0¤M\015èÅËW\017\000º(ä’/cH,·ºJÕ˜ÔPßoÐõG#0ØÄ\ ! C\004­!í\"\016ºµô‚Éè\017_óÀ†Ÿã\\¬\026_Š\022<Â\003lîLr*”T¦Ë\033\002‘=¶'eß!²ÄfÌ°ò \017\034¢\010§\ ! KŒ?dŒtÖ\011ü§\031l-M7ñ€%ñÐ\014[¢Lƒ±duÏsß½g×4õ\010Æ­¯6“Šf\006\005\027ýPÊÆß8dz‰î\ ! ­Vð,çæ\022\023žc¿:Ô\0025Ä Þ\002'˜\030\012(ÜæI\036\\\012U\025YSÄn_'Äk\024ö\034Á~Ó-…éðyèI¯õ\034O{\006ë\ ! AŒo°g±?|÷p\027Á£\016Ä·\000í\001™«Çkqûöãå\007kì<º•!d\016âh\015ž‡\006ÏsZ\003.vn4zú\016#\026ò±¢\ ! \014\001\002ÕÔ©ÊŒ@Éz\001dÓdäÊÞ\030Á›iæ\002 Û£\000\007WŠR÷p¨–>²\001\021v%Š\032\024§û[² ny_»}3ï‚«\015\ ! Zg?\030›.ì87¯Z\012ÿ\004ÛΚK4eñúÍûsgÎpƒ{ ¡½¸tWo\000%9jÕk\026oMí‘.xne¤#Ð5¢\ ! \011_ŠÄ\013Þㇽ!Û¿\024±xÛÞç‘Ý\\nÒWžŽ_yæØaÜ8;ƒCÌ›^ƒÉ½Nyîµcøîft(\033‘äpÚa\ ! “:<\\à}\020ÀÀ-\023ŒKíu•\016Q\020Œ½ƒE\014\011jTÍ\006K\003øÂ×ËÁÓ:[~ÎY=Ô>ýw\034œí¶\036™ÜuK{eY\ ! \037â-uŸŠ¦të­^sMæº\033}ì&\012}¢añµ!ü/TíuÉ\037LÝÍ͹ÿeé\002Ù:îÊ–s´\006\037\022³ÎAŸU\ ! ENB¼œ\016fÁLê6ýÑËI\007ˆáKcú4P‚\011^‹Î{¿¶˜O“cLÛoEÒo„»S]iŽ¬\014Ì]É\004l}'\ ! Æi”Ó;~ùÌ{̶ULC{ó ŠÑ°þˈ‡l‰;ç[úÎ\0347×Õ(Be7zL%Ž&“É¿W+Æä[ûA¾^I\ ! u§\032ˆ“ˆi±»Ö©”½¢kŸ4\0237Xð6ܽâ·Âkbü\032®}áQóØ\012–\012¡ã\016±â\024À÷\"¦G0}\012­K\015\033û\ ! ÷\032ø\000Š-\004?û²Þ¦R‘¼Ë†\022b}¤3ÃÃvÌ•yG±\022ûNÊh¹mþôÀl‰tdo8Ã÷&½–RaáØfÖ%\ ! °¾ŸW›ôÂ\032¨ÉäÙPÓkæ”1£á?^jÚ\022¾Þ\031ƒv¿\025Æ?ø·EܽÝç4¹bÈ1\025D^ðAfp8!;™°£\ ! \027ÓÉ‹éÉ1;žLŽÍ\031ŒZ8˜=•Ê§ãñÝÝݨn-`Oaì ‚ÏÝâoSm5&²Mnë°(þD=m\031£¡\032\003òÅ\ ! ®2}{S¾\0009ì\027¾MI\002Õ…=\007\016œ2»\030Ë\032[“X5\011•S”\000‰‘ÑVÿAšþ#à\002زÏ}") ### end --- 5,185 ---- import zlib ! data = zlib.decompress('x\xda\xdd;ms\xdb\xc6\xd1\xdf3\x93\xffpA\xc7\x864\x95HJ\xb2\xdd\x84"1\xb5e%\ ! \xceS;V%\xa6\x9dL&\xa39\x02G\x12\x15\x80C\x81\x83$>\x9e\xfe\xf7\xee\xee\xdd\ ! \x01\x87\x17It\xd3\xb43\x95="\x81\xbb\xdb\xdb\xdd\xdb\xf7=\xcd\xbez\xfb\xf1l\ ! \xf1\xd3\xc59{\xb7\xf8\xf0\x9e]\xfc\xf8\xe6\xfd\xf7g\xcc;\x1c\x8f\xffzr6\x1e\ ! \xbf]\xbc\xd5\x03/F\x93#\xb6(xV\xc6*\x96\x19O\xc6\xe3\xf3\x1f\xbc\xe0\xcb/f\ ! \x1b\x95&\xf4)x\x84\x9f*V\x89`q4\xf7\xe8\x9b\x17\\\xe5<]\xf2\xad(\xd9\x8f\ ! \xa5(\xd8\xf7\x99\x12\xc5\x8a\x87b6\xa6\t\xb8&\x15\x8a\xb3\x8dR\xf9\xa1\xf8{\ ! \x15\xdf\xce\xbd\x8b\x82\xafS\xee\xb1P\xc2\xecL\xcd\xbdL\x1e\x86<\xdc\x08\ ! \x8f\x8d\x07\x17\x9c\xe9\xc1\x9d\xe7\x9f\xdf\xe7q!Jg\xc5bS\x1d0 \xf2\xffx\ ! \xc6\x8e\xbe\xf9\xc3\x84M&S\xfa\xcf\xbe\xfb\xb0xt\xdb\xc33\x80Q\xc8d`\xfb\ ! \x03\x96V\xa5:,\xc4-O\xe2\x88+x\x01C\xa5\x92\x85\xc5\xacT[\xe2\xc1RF[\xf6\ ! \x89\xad\x00\xc2\x94}3y\xc6x\x11\xf3\xe4\x80\x95wqY\x1e\xb0\x8dHn\x85\x8aC~\ ! \xcaR^\xac\xe3l\xca&\xec\x1f_~\xa1\xf8\x12\xb8\xbd\xc3:\x9c\xbc\x92E\ns[\x00\ ! \xbe\xfc\x82O\x938\xbb\x81\xf7\xa1Ld1e\xbf\x9b\xc0OH\x83|z\x1b\xc3\x81\x8b\ ! \xe8\x81\xd1\x8d\xbc\x85\x13m\xc6^M^LV+\x1c\x1b\x19V0n\x90;\xbc\x13\xf1z\x03\ ! 8.e\x12\xd1\x8c\xdbX\xdc\xd1\xce\xbd)\x19\xe0\xc9\x13\x8d\xddh\xc9\xb3\x8c6Y\ ! \xf2\xf0f]\xc8*\x8b`\xa7p"`\xa7S\x96\xf3(\x8a\xb3\xf5\xfce\xfd\xf50\x11+\x80\ ! q\xf4\xf2\xf4\xcb/X\xfd\xb3\x94E$\x8aC%s\x18\xca\xefY)\xe1<\xd82\x01\x98C\ ! \xf3\x96R)\x99\xf6\xa6\x12\xde(\xe8\x84\x10\xe1\\\xc6\xff/`\xde\xc9\xc9\xb3\ ! \x16\xd9\r\x97\x8f^\xd2@*\xca\x92\xaf\x85>/\x85\x0c\xed\xe0+\xee\x1b\x12\n\ ! \xcd\x07xGkK\x11\xa2\xd2\xd9\xb3\xd68\xba\xc8\xfd\xee\xeb\t\xfe;ewq\xa46 \ ! \x07/\x9f\xb9\x0b\x11c\x00\xdb\xe1\xe1j\xb5\xe2br:\x80\x87\xcb\x90\'\x19c\ ! \xf7\x1eZ4|\xf0\x06+#\xf1f{\x009\xc9\xef\xcd\x99\x83\xbe\x80phF\x97lP@\'$\ ! \x82\xbd\x99\xc3\xf2j&7\x12\xf7\x08Dg\xd2c\xc0\x90\x0eU\xc4\xb9\xb8\x96\x99>\ ! \xcf\x96|\x8a\x10\xff\x99\x89U\xfc\x0e\x8c\xe4\xbb!\xb99\x9e<;\xad\xa1\x7fM\ ! \xd0O\x87\xd96\x1b[S1\x1b\x1b[\x0b_\x89\x89hl\xf1\x8bG\xef\x90\xf1\xb3(\xbee\ ! a\xc2\xcbr\xeek\x05\xf2\x033R\xe6`\xe0p\x05\x98\x06\xb0g^0\x8b\xd35+\x8bp\ ! \xee\xeb7\xa3u\xbc\xf2\x19\xd8\xabu6\xf7\xf9\xb2L\xe3(J\x84?\x0e\x9eg\xcb2?\ ! \x05<\x00B\x0b\x9a\xd9H\x9f\x82\xdd\xa8\xbdY^\xc8\xa8\n\xd5\x0f\xc3\xbd\r\x12\x95\x19A <\xe3\xc8"\xac\xf8\xfa\x80\xf8\ ! \xbd\x14@ n\xca.\xb6j\x03F\xc4`\x07p\r\xd7G\xb3q\xee\n\xd4k\x84\n\xa7\xc6\ ! \xd3\xb25\x9a\ ! \x1f\x88*A\xf3\x0f\x98,\xf4\x068J\xf0\x1b\x0b\xaa\xa1\xad\n\x99\xb22,\xb8\ ! \x02{\x16k\xb4\xc0\xb6\xbe\xce\xa2\xbe\x0fB;\x12\xea\xbc&\x01\x1c@\xd1\x04\ ! \x18\xfe\xe5\xd6ZU\x18\x06\xd0z\x1f\xb2\xe6\x87,D>\xe1\xe6\x08\x8c\xf4\xaf\ ! \xdc\x08\xa1\x0e\x98\xc2\xbc\x11\xb4\x1d\xc7\x80\\i\xfc\x1bb\rF8[WH8XERE0\ ! \x88\x99\xb8k\xccm\x87I\x87d\xa5\xb5\x17,E\x8d\rr\x02}\x1ax\x9b-\x13\xbc\xdc\ ! v\x8d\xe7\x1b\x91\x80\xb5\xc4)\xda\xca\xf7\x1ck\xc3,\x98!\x01\x0f4\x9d81.\ ! \x06-yY\xef\x80\xa1@A\xc9\\n\x03\x057\xe2\xf3\x02\n\x8c\xa27h]\x1d\x9c\x9c@\ ! \xcc\x0c{V\x9at\xa4o\xc2*7\xfa\xf7Y(\x92\x04V\x86\x98\xf4\xf8\x8d\xcdRE0\x83\ ! (\xd4\x82\x83Q\xaf\xb3\xde\xbc\xf6Q{p\xeb\xb9\x7f\x0c1\x14m\xcd\xc8\xf0\xab\ ! \x08\xb4\x08\xe0\xf4 \xfa1\x08\xc2\x19\xec\xeb\xa3FPX\x08y\x94\xdf\x81\x8f\ ! \x01\xa8\xaf\x13\x10\x00=q\xc3@\xad~\x10eZ`\xbe\x8e7K\xc5UU\xeax\xd3,|1\xf1\ ! \xc1\x8da\xe4K\xdfm\xd0\xe9\xc4x\x88\xa7\xf3h\x88\x06\n:\xc1Z\x0b/g\x05\x85e\ ! \xe8$\x99\xc3x\xd0\x82\x0f\xb2T\xc31Wi#)\x90\x9e\x06\x0e(\x7f\t\xdb\x01\xf7@\ ! \x93P\x15\xacL\x9aP\xacY\x03\xda\xdc\x9e\xed\x88\xaeN\xad\xeea\xa2v\xde\xd9`\ ! \xac\x88&\x80\xdfJpuQ\x95\'\xe0\x1f\x910\x1b\x8b\x8c\xac\t\xb2\x07\x08\xbfPV\ ! \x0c\xcd&j_\x16\xe3n\xe0\xbb\x83\xe4\xea\x13j\x89\xad\x96M\xe4\xb9\x1e\\\xe0\ ! \xb3g\xf2\xc3\xb9\x07&\xd4\x15Q\xfbl\xf3txn\x0b\xd8`\xf8\xae!{\x0fe\x12\xf7\ ! \xdb\xb7\x90H\xc7Ik\xc6\xc5\xc7\x8b\x13F\x83\x18?ehI\x80G\xb3e\xd0Yz\x01\xbe\ ! \xbb\xbc"\xe3\xe9\x05GGG\x13\xc3\x8f\xd9x\x19\x1c\xb8\xc7\x0bs\xc9\x98\xc96\ ! \x10\x8ae\x8b\x1a\x82\xf1"\x90\xf8\xa7\x0e\xa0\x91\x83y\xc3y\xfcy\rBy+4\xb6\ ! \xa0\t\x08\x8aN\xb3\x9cv\xf4\xc5\xdd\x93\xd3\xa2+\x01Q)\xcc\xf4\x02\x17\xe7Q\ ! g\x83>dm\xadK\xbd\xfa\xb1m\x94T<\xd9m\x97V\xf6D1r\x8a\x07\xa2\xa5(^\xc5\xe8\ ! \xb6v\xdc5\xabR\xcc\x1a:\x1b2\xf8\x96\x1e<\xbe\xec]\x7f\xd5\xe6\xc9E?feU\x88\ ! \xce\xb2\x8a^v\x89\\ ?\x98\xd0\x94\x81\x13\xc3\xf4\xa9C\tb>\xed\xec\x81\x98\ ! \xb7\xe1\xb7\xd7\xbc\xeb/\xd9tW<\xc6n\xc7\x04\xa2\xf93\x91\xae)\xfd\xbc\x12\ ! \xf7\xbe1\x9a\xee\xef\xce\x1a\xd7\x8e\xbb\xdb\xd4\xa5\x00\x10\xa0U\xbc~\xcc4\ ! \xdb\n\x01\x96\x8d\xfc\xf1\xa0\xaaj UAb\xf8\x1e\x13xgZ\x1f\xc7\xfe\xef\x9f W\ ! \x08\xb1\xc0`\x00\t\xcc\x1e\x8a&\xc9\xecpi\x17\x90\xe5\xb6T"\x05\x0bo\x02\ ! \x95\x8e\xb0pSb\xd0;\xfa\xc1\x99K\x02EhXr\x18\xf5N\xc6\xe5\xaf\xe3DkK\xfc\ ! \xa4\xa5\xd5\x85\xac\x05\xc4\x9d\xed\xc0\x85\x18\xd9\x0cZ\x0e.Z5\x00m\xf6\ ! \xa8\xac\\\xd6\xf1\x8d\xa98\x82\xb3S\xa0\x86\xa24H[\x9e\x92<\xd3\xc4Zg!~\xe4\ ! %h.V\xb46\xb2l@\xe8\x955\xcf\x1a6i\xc4\xfc\xe0\x92>\xeb\xf9\xc8#bV\xed\x9bv\ ! \x8c\x94\x0c\xa1\xc8\xb4\xe1XIO \xae\xd6\x8e\x04K-\xe0PuM\xc3(+\xa6\xe7[C)xs\ ! \xb4\xe25\xc1\xa6\xbcPS\r\x0e\xfbl#\xc2\x1b"\x8d\xe7\xc0L\xc8"07]VJ\x01/V\ ! \x10X\x0b,\x01\x10\xf0\x83\xba\xae\x80\x85\xaf\x18\x96\xf9\x0b\x84\xecCF\x0f\ ! !&\x00\xf3\xdf\x8a\x95(|Hw\xf9\xad)\xef\x18\xc6\xe8\xa5\xe8\xe9\x0fL\xd9\xc0\ ! X\x15d9\xa6\xc3\x84\x0b\x01m"\n\xbd\xe8m\\\x86\xbc\x88\xd8\x98\x11t\xf8\x043\ ! \x02\xbfQ\x08\x98\xad\x7f\x02\xcc\x90(ibd\xbdZSR\xea\xe0\x83\xa3c\xa0\x01\x84\x02\x02\xb8\xef\xce\x17\x8e\xcd0%\ ! \x02J\x9b\xfcM\x1cE\x10\xee0,\xbd\xcd}\xe0\xa2\x046`\xd0g\xbe\xea\x84\xca\ ! \x9f\xb8\xf6\xe2\x11\x00\x19\x08\xbc^\xaf\xbf\r.\xd7\xf1\x88\t?`\xac\x15n\ ! \xd8\xe7~\xc4\xecD -\x0c\xcaj\x99\xc6\xcab\xb0\x96\x0e\xfeo\x88\x89\xfeP\xa1\ ! \x1b\x7f\x0cv\x17\xc8/YA"\xc7!\x1e\x8e\xe2\x12\xf1\x03\x10GN\x05\xb5\x15\xf6\ ! h\x93\xbc\x0b\x16\xa0r\xa0\xe0\x9b\xa70\xb84\xd3~\xf5~\xc8\xf5\xdd\x88\xfe\ ! \x01f~.\xc1\x0fY\xe8n\x84\xdf\x0fi1\xd9/\xd2V|\xdbX\x8a\xb0\x88sK\x16\xa6\ ! \xf1\xe3\xbf\xf1[\xae\xdf\xfa\xc1x<\xfb\xea\xe7\xb3\xb7\xaf\x17\xaf\x7f6)q\ ! \x95iM\x90\x99\xb6A{\xb8\x92\xdag\x90$/\xa4)\xa5|j\xf0\x89Wl/\x92a\x95B8?B\x7f\x05\x14t\xe2\x04\x06\xbf\ ! \xb4{ZZ$\x97\xc1`\x05\xa4]\xafq\xc4\xe5R\xde5u\x10\xdb\xa6\xf4\x87\x0f\xcb6<\ ! \xfd\xfe\xc9P\xbe[Q_\xc2\xf4\xde<\x9c\xed\x05}M\xbb\x14S\' \xc5\x06\x87.O\ ! \xb3B\x867_1\xf6\xf5\xe1~\xa7Y7\\\xc8\xc1\x1a\xe5\xb5\x17\\\xc6\xe1&\x16\xec\ ! ]\x9cE\xa0QX\xb8-\xe8\xcd\x1f\xc1PBp\x96a\xbe\xad\xcb\xb1\x83P@t\xdd6\xe3\ ! \xfb\xb8T\x04\xa4\xb4\xaf\xfe\x98Sev$\x8b\xf5\x03`Lz\x13b\xd5\xa6\xf0{u\xa8^\ ! \xe8R\xf0(\x96\xd6\x83\x1aM\xdcNI\t\xfft\xfe\xd3\xb0\x03ET#-\xcd\xb6\xda\xec\ ! \x9b\xe7\xday\xf6\x7f\xff\x16H\xa0\x1ax\x8d?\xa7\xe7\xff,\n\x98\x02\xbb!\x05\ ! <\xffg\x11\xa0\xb4\xddA\x00\x9f\xdb\x89m_H\x8ce\xf3\xf4\'\xd8I\xad3vW\xab4\ ! \xf5sp\x85=\xbb\x10\xe0S\x8e\xf4\xb8*/\x13\x9e\xdd\xa0&\x07M\xb8\xa4M\xef\ ! \xe3\x8f}H\x94e\xec\x00i\x07\r\xe8\xa4\xdc=\xee\xb7#I\x93\x19\x19\x8e\xea\ ! \xa7\xf1\xd3\xb6\xec\xe1h\xefs\x8a\x97U\x9eH\x1e\xf5\x13\x1b\xe4\x88\x1e\xf3\ ! j\xb7N\x1cj\xc9F\xcb\xc13\x01a"\xd1\x97V\x89\x8as^(\xc2\xea0\xe2\x8a[\xc3y\ ! \x1eSGC\x83f\xdc&}\x8eG\x95\xc5u\x8a\xfd\xa6\x00B\xba\x94\x8a\xeeD\r5P\xda-W\ ! \xbd\x19\xbe\xb7\xac\xd4\xdf\r\'\x81\x89\xceA|,\xa8+$(\x97\xbb\xdb\xc8\xa4N8\ ! !p\xcc@\xda\xa8\xafb\xdc\xf1>\xe5\x9fS\xb7 \x8ca2$\xcf\xdc\xec\xa4(\xd9*\xe4\ ! \x1d8\x87\x13\xdd/\x98\xfb\xd8^\x85s13\xdd\xdd\x9d&\xb1>\xfck\xadIC\xf2p\xb7\ ! \x01+\xde\x96\x07\x0cU\xae\\U\xeb\xc3\xdb|&\xb8w\x8fBk\x94\xf3i\x90gfn\x03\ ! \xce\nc]{\xd8\xc3R\x8c9s\x12\xaf5v\xb9+\xac\xa3`\xe4\xbe\x94\xd8EB\xcc\xa8\ ! \xb7\x95E6J\xa3\xe2\xf2\xa1S\x82\x8a3\xb7\xf6\xd0\xb4\x0fX!RyK\x972\xea\x9b\ ! \x01\xfb;WT\xee 1\xfes%\x8a\xed\xb0\x1e\xd4\xc3\x8d*\xe0\xab\xbf\xe3+\xbf\ ! \xcfB\x1c\xf3,\xa7\xe0{#\x90N\xc6\xe5\xebv\xaa\x7f2\xe9\x9eB\x9b\xe1\xf6\xd8\ ! \xfc\x05y5\xedM{\x9f!\x1ab\xf9\x93\xd4\xae ^0\xe1\xf00\xbd\xce\x04o\xb7\x98\ ! \xbe!\x1e\xd7z\xb56f\x8f\x13\x7f\xb4\x1b\xf1\xe7h[\xa9D\x14G\xb6\xfbdu\x17\ ! \xfb\xbe\xb8\xcd\xbf\xc2\x08\xe4\xe0\x95\xe2\xaa\x1c.\xa3\xd5\xc36\x94\xfb\ ! \xa1J\x97\x80\x08`\x80\xca[\x17\xf2:uj\x1c\x0be\x857\xa0\x8e\x8eO\x1eh\x0f4\ ! \xa06\x0fC\xda\xd4\x80^\xbc|\xf5\x00\xa0\x8bB.\xf92\x86Ds\xab\xabV\x8dI\r\ ! \xf5}\x07]\x8f4\x02\x83M=D\xd0\x1a\xd2.\xe2\xa0[K/\x98\x8c\xfe\xf0\xf57\x0fl\ ! \xf89\xce\xc5j\xf1\xa5(\xc1#<\xc0\xe6\xce$\xa7bIe\xbb\xbc!\x10\xd9c{T\xf6\ ! \x1d"Kl\xc6\x8c+\x0f\xfa\xc0!\x8ap\xba\xc6\xf8C\xc6Hg\xa1\xc0\x7f\x9a\xc1\ ! \xd6\xd2t\x17\x0fX\x12\xdf\x08\xcd\xb0%\xca4\x18KV\xf7@\xf7\xdd{wM\x93\x8f`,\ ! \xdczk3\xa9hfPp\xd1\x0f\xadl<\x8es<\xdb\xa9\xe8\xder\x05\xcfrn.5\xe19\xf6\ ! \xabE-PC\x0c\xea-p\x82\x89\xa1\x80\xc2m\xa6\xe4\xc1\xa5PU\x915E\xed\xf6\xf5B\ ! \xbcVa\xcf\x11\xec7\xddZ\x98\x0e\x9f\x87\x9e\xf4Z\xcf\xf1\xb4g\xb0\x1e\xc4\ ! \xf8\x06{\x16\xfb\xc3w\x11w\x11<\xeaH|\x0b\xd0\x1e\x90\xb9z\xbc\x16\xb7o?^~\ ! \xb0\xc6\xce\xa3[\x1aB\xe6 \x8e\xd6\xe0yh\xf0<\xd7\xa95\xe0b\xe7\x86\xa3\xa7\ ! \xef4ba\x1f+\xcc\x10 P\x8d\x9d\xaa\xce\x08\x94\xac\x17@6MG\xae\xec\r\x12\xbc\ ! \xa9f.\x04\xba=\x0bpp\xa5(uO\x87j\xeb#\x1b\x10a\x97\xa2\xa8Aq\xba\xcf%\x0b\ ! \xea\x9e\xf7\xb5\xdb7\xf3.\xb8\xda\xa0u\xf6\x83\xb1\xe9\xca\x8es\xf3\xaa\xa5\ ! \xf0O\xb0\xed\xac\xb9\xe4IS\x16\xaf\xdf\xbc?w\xe6\x0c7\xbc\x07\x1a\xdc\x8bKw\ ! \x15\xf8\x06P\x92\xa3V\xfdf\xf1\xd6\x04\xd9\x1e\xe9\x82\xe7VJ:\x02]#\x9a\xf0\ ! \xa5H\xbc\xe0=~\xd8\x1b\xb3\xfdK\x12\x8b\xb7\xed}\x1e\t\xd9\xcde\'}\x05\xea\ ! \xf8\x95g\x8e\x1d\xc6\x8d\xb3\xd399\xc4\xbc\xe95\x98\xdc\xeb\x14\x12\x9dv\ ! \x0c\xdf\xdd\x8c\x0ee#\x92\x1cN;lR\x87\x87\x0b\xbe\x0f\x02\x18\xb8u\x82q\xa9\ ! \xbd\xbe\xd2!\n\x82\xb1w\xb0\x88!A\x8d\xaa\xd9`i\x00_\xf8z9xZg\xcb\xcf9\xab\ ! \x87\xda\xa9\xff\x8e\x83\xb3\xdd\xd7#0\x93\xbbni\xaf0\xebC\x1c\xb2\xa5\xee\ ! \xf1S\x11\x95n\xc1\xd5k\xae\xe9\xd1\\\x7f\xa3\x8f\xddD\xa1O4,\xbe6\x84\xff\ ! \x85\xaa\xbf.\xf9\x83\xa9\xbc\xb9I\xf7\xbf,] [\xc7]\xd9r\x8e\xd6\xe0Cb\xd69\ ! \xe8\xb3\xaa(\xf0\xcfK\x88\x97\xd3\x01\xd2,\x98I\xdd\xb6?z9\xe9\x001|iL\x9f\ ! \x06J0\xc1k\xd1y\xef\xd7\x16\xf3ir\x8ci\xfb\xadH\xfa\x8dpw\xaa+0\xcd\x91\x95\ ! \x81\xb9+\x99\x80\xad\xef\xc48\x8drz\xc7/\x9fy\x8fY\xd8\xb6\x8aiho\x1eT1\x1a\ ! \xd6\x7f)\xf1\x90-q\xe7|K\xdf\x99\xe3\xe6\xba\x1aE\xa8\xec\xa6S\x8f\xa9\xc4\ ! \xd1d2\xf9\xf7j\xc5\x98|k?\x08\xd2\xd7-\xa9\xeeT\x03q\x121-v\xd7:\x95\xb2Wv\ ! \xed\x93f\xe2\x06\x0b\xe0\x86\xbbW\xfcVxM\x8c_\xc3\xb5/0\xc8\x0c\x0e\ ! \'d\'\x13v\xf4b:y1=9f\xc7\x93\xc9\xb19\x83Q\x0b\x07\xb3\xa7R\xf9t<\xbe\xbb\ ! \xbb\x1b\xd5\xad\x06\xec1\x8c\x1dD\xf0\xb9[\xfcm\xaa\xad\xc6D\xb6\xc9m\x1d\ ! \x16\xc5\x9f\xa8\xa7-c4Tc@\xbe\xd8U\xa6\x8fo\xca\x17 \x87\xfdB\xb8)I\xa0\xba\ ! \xb0\xe7\xc0\x81Sf\x17c\xb9Qck\x12\xab&\xa1r\x8a\x12 12\xda\xea?P\xd3\x7f\ ! \x14\xfcO\x14\x8d\xd5L' ) ### end From richiehindle at users.sourceforge.net Mon Jul 7 15:00:05 2003 From: richiehindle at users.sourceforge.net (Richie Hindle) Date: Mon Jul 7 17:00:08 2003 Subject: [Spambayes-checkins] spambayes/spambayes Options.py, 1.56, 1.57 ProxyUI.py, 1.11, 1.12 Message-ID: Update of /cvsroot/spambayes/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv5271 Modified Files: Options.py ProxyUI.py Log Message: Added a new option, no_cache_bulk_ham: Where message caching is enabled, this option suppresses caching of messages which are classified as ham and marked as 'Precedence: bulk' or 'Precedence: list'. If you subscribe to a high-volume mailing list then your 'Review messages' page can be overwhelmed with list messages, making training a pain. Once you've trained Spambayes on enough list traffic, you can use this option to prevent that traffic showing up in 'Review messages'. Index: Options.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/spambayes/Options.py,v retrieving revision 1.56 retrieving revision 1.57 diff -C2 -d -r1.56 -r1.57 *** Options.py 24 Jun 2003 06:16:27 -0000 1.56 --- Options.py 7 Jul 2003 21:00:01 -0000 1.57 *************** *** 218,222 **** BOOLEAN, RESTORE), ), ! # These options control how a message is categorized "Categorization" : ( --- 218,222 ---- BOOLEAN, RESTORE), ), ! # These options control how a message is categorized "Categorization" : ( *************** *** 258,262 **** REAL, RESTORE), ), ! # These control various displays in class TestDriver.Driver, and # Tester.Test. --- 258,262 ---- REAL, RESTORE), ), ! # These control various displays in class TestDriver.Driver, and # Tester.Test. *************** *** 389,393 **** BOOLEAN, RESTORE), ), ! "Classifier": ( ("max_discriminators", "Maximum number of extreme words", 150, --- 389,393 ---- BOOLEAN, RESTORE), ), ! "Classifier": ( ("max_discriminators", "Maximum number of extreme words", 150, *************** *** 416,420 **** worked best, so this does not seem to be corpus-dependent.""", REAL, RESTORE), ! ("minimum_prob_strength", "Minimum probability strength", 0.1, """When scoring a message, ignore all words with --- 416,420 ---- worked best, so this does not seem to be corpus-dependent.""", REAL, RESTORE), ! ("minimum_prob_strength", "Minimum probability strength", 0.1, """When scoring a message, ignore all words with *************** *** 423,427 **** tests. 0.1 appeared to work well across all corpora.""", REAL, RESTORE), ! ("use_gary_combining", "Use gary-combining", False, """The combining scheme currently detailed on the Robinson web page. --- 423,427 ---- tests. 0.1 appeared to work well across all corpora.""", REAL, RESTORE), ! ("use_gary_combining", "Use gary-combining", False, """The combining scheme currently detailed on the Robinson web page. *************** *** 431,435 **** spam distributions overlap.""", BOOLEAN, RESTORE), ! ("use_chi_squared_combining", "Use chi-squared combining", True, """For vectors of random, uniformly distributed probabilities, --- 431,435 ---- spam distributions overlap.""", BOOLEAN, RESTORE), ! ("use_chi_squared_combining", "Use chi-squared combining", True, """For vectors of random, uniformly distributed probabilities, *************** *** 465,469 **** # this option will go away (and become the default), but people *with* # strong imbalance need to test it first. ! ("experimental_ham_spam_imbalance_adjustment", "Compensate for unequal numbers of spam and ham", False, """If your training database has significantly (3 times) more ham than --- 465,469 ---- # this option will go away (and become the default), but people *with* # strong imbalance need to test it first. ! ("experimental_ham_spam_imbalance_adjustment", "Compensate for unequal numbers of spam and ham", False, """If your training database has significantly (3 times) more ham than *************** *** 478,487 **** BOOLEAN, RESTORE), ), ! "Hammie": ( ("debug_header", "Add debug header", False, """Enable debugging information in the header.""", BOOLEAN, RESTORE), ! ("debug_header_name", "Debug header name", "X-Spambayes-Debug", """Name of a debugging header for spambayes hackers, showing the --- 478,487 ---- BOOLEAN, RESTORE), ), ! "Hammie": ( ("debug_header", "Add debug header", False, """Enable debugging information in the header.""", BOOLEAN, RESTORE), ! ("debug_header_name", "Debug header name", "X-Spambayes-Debug", """Name of a debugging header for spambayes hackers, showing the *************** *** 489,493 **** standard header.""", HEADER_NAME, RESTORE), ! ("train_on_filter", "Train when filtering", False, """Train when filtering? After filtering a message, hammie can then --- 489,493 ---- standard header.""", HEADER_NAME, RESTORE), ! ("train_on_filter", "Train when filtering", False, """Train when filtering? After filtering a message, hammie can then *************** *** 561,565 **** that you wish.""", HEADER_VALUE, RESTORE), ! ("header_ham_string", "Ham disposition name", "ham", """As for Spam Designation, but for emails classified as --- 561,565 ---- that you wish.""", HEADER_VALUE, RESTORE), ! ("header_ham_string", "Ham disposition name", "ham", """As for Spam Designation, but for emails classified as *************** *** 573,581 **** should always be the subject of training.""", HEADER_VALUE, RESTORE), ! ("header_score_digits", "Accuracy of reported score", 2, """Accuracy of the score in the header in decimal digits""", INTEGER, RESTORE), ! ("header_score_logarithm", "Augment score with logarithm", False, """Set this to "True", to augment scores of 1.00 or 0.00 by a --- 573,581 ---- should always be the subject of training.""", HEADER_VALUE, RESTORE), ! ("header_score_digits", "Accuracy of reported score", 2, """Accuracy of the score in the header in decimal digits""", INTEGER, RESTORE), ! ("header_score_logarithm", "Augment score with logarithm", False, """Set this to "True", to augment scores of 1.00 or 0.00 by a *************** *** 671,675 **** """""", BOOLEAN, RESTORE), ! ("cache_expiry_days", "Days before cached messages expire", 7, """""", --- 671,675 ---- """""", BOOLEAN, RESTORE), ! ("cache_expiry_days", "Days before cached messages expire", 7, """""", *************** *** 679,687 **** """""", PATH, DO_NOT_RESTORE), ! ("ham_cache", "Ham cache directory", "pop3proxy-ham-cache", """""", PATH, DO_NOT_RESTORE), ! ("unknown_cache", "Unknown cache directory", "pop3proxy-unknown-cache", """""", --- 679,687 ---- """""", PATH, DO_NOT_RESTORE), ! ("ham_cache", "Ham cache directory", "pop3proxy-ham-cache", """""", PATH, DO_NOT_RESTORE), ! ("unknown_cache", "Unknown cache directory", "pop3proxy-unknown-cache", """""", *************** *** 717,720 **** --- 717,730 ---- BOOLEAN, RESTORE), + ("no_cache_bulk_ham", "Suppress caching of bulk ham", False, + """Where message caching is enabled, this option suppresses caching + of messages which are classified as ham and marked as + 'Precedence: bulk' or 'Precedence: list'. If you subscribe to a + high-volume mailing list then your 'Review messages' page can be + overwhelmed with list messages, making training a pain. Once you've + trained Spambayes on enough list traffic, you can use this option + to prevent that traffic showing up in 'Review messages'.""", + BOOLEAN, RESTORE), + ("add_mailid_to", "Add unique spambayes id", (), """If you wish to be able to find a specific message (via the 'find' *************** *** 858,862 **** """""", IMAP_FOLDER, DO_NOT_RESTORE), ! ("spam_folder", "Folder for suspected spam", "", """""", --- 868,872 ---- """""", IMAP_FOLDER, DO_NOT_RESTORE), ! ("spam_folder", "Folder for suspected spam", "", """""", *************** *** 899,903 **** IMAP_FOLDER, DO_NOT_RESTORE), ), ! "globals" : ( ("verbose", "Verbose", False, --- 909,913 ---- IMAP_FOLDER, DO_NOT_RESTORE), ), ! "globals" : ( ("verbose", "Verbose", False, Index: ProxyUI.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/spambayes/ProxyUI.py,v retrieving revision 1.11 retrieving revision 1.12 diff -C2 -d -r1.11 -r1.12 *** ProxyUI.py 26 May 2003 00:00:53 -0000 1.11 --- ProxyUI.py 7 Jul 2003 21:00:02 -0000 1.12 *************** *** 84,87 **** --- 84,88 ---- ('pop3proxy', 'listen_ports'), ('pop3proxy', 'cache_messages'), + ('pop3proxy', 'no_cache_bulk_ham'), ('html_ui', 'display_to'), ('Header Options', None), *************** *** 489,493 **** # we have a few extra checks errmsg = UserInterface.UserInterface.verifyInput(self, parms) ! # check for equal number of pop3servers and ports slist = list(parms['pop3proxy_remote_servers']) --- 490,494 ---- # we have a few extra checks errmsg = UserInterface.UserInterface.verifyInput(self, parms) ! # check for equal number of pop3servers and ports slist = list(parms['pop3proxy_remote_servers']) From richiehindle at users.sourceforge.net Mon Jul 7 15:01:23 2003 From: richiehindle at users.sourceforge.net (Richie Hindle) Date: Mon Jul 7 17:01:25 2003 Subject: [Spambayes-checkins] spambayes pop3proxy.py,1.85,1.86 Message-ID: Update of /cvsroot/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv5726 Modified Files: pop3proxy.py Log Message: Added a new option, no_cache_bulk_ham: Where message caching is enabled, this option suppresses caching of messages which are classified as ham and marked as 'Precedence: bulk' or 'Precedence: list'. If you subscribe to a high-volume mailing list then your 'Review messages' page can be overwhelmed with list messages, making training a pain. Once you've trained Spambayes on enough list traffic, you can use this option to prevent that traffic showing up in 'Review messages'. Index: pop3proxy.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/pop3proxy.py,v retrieving revision 1.85 retrieving revision 1.86 diff -C2 -d -r1.85 -r1.86 *** pop3proxy.py 2 Jul 2003 20:51:49 -0000 1.85 --- pop3proxy.py 7 Jul 2003 21:01:20 -0000 1.86 *************** *** 446,452 **** state.numUnsure += 1 ! # Cache the message; don't pollute the cache with test messages. ! if not state.isTest \ ! and options["pop3proxy", "cache_messages"]: # Write the message into the Unknown cache. message = state.unknownCorpus.makeMessage(msg.getId()) --- 446,461 ---- state.numUnsure += 1 ! # Suppress caching of "Precedence: bulk" or ! # "Precedence: list" ham if the options say so. ! isSuppressedBulkHam = \ ! (cls == options["Hammie", "header_ham_string"] and ! options["pop3proxy", "no_cache_bulk_ham"] and ! msg.get('precedence') in ['bulk', 'list']) ! ! # Cache the message. Don't pollute the cache with test ! # messages or suppressed bulk ham. ! if (not state.isTest and ! options["pop3proxy", "cache_messages"] and ! not isSuppressedBulkHam): # Write the message into the Unknown cache. message = state.unknownCorpus.makeMessage(msg.getId()) From anadelonbrin at users.sourceforge.net Mon Jul 7 18:08:56 2003 From: anadelonbrin at users.sourceforge.net (Tony Meyer) Date: Mon Jul 7 20:08:58 2003 Subject: [Spambayes-checkins] spambayes/spambayes hammiebulk.py,1.6,1.7 Message-ID: Update of /cvsroot/spambayes/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv1392/spambayes Modified Files: hammiebulk.py Log Message: When the (second) options changeover occured, certain options were merged. This resulted in the default for persisent_storage_file changing. I patched hammiefilter at the time to avoid problems with this, but (dammit!) missed that I needed to patch hammiebulk as well. This is that rather belated patch. Index: hammiebulk.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/spambayes/hammiebulk.py,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -d -r1.6 -r1.7 *** hammiebulk.py 21 Jun 2003 04:46:32 -0000 1.6 --- hammiebulk.py 8 Jul 2003 00:08:53 -0000 1.7 *************** *** 61,64 **** --- 61,70 ---- # Default database name DEFAULTDB = os.path.expanduser(options.hammiefilter_persistent_storage_file) + # This is a bit of a hack to counter the default for + # persistent_storage_file changing from ~/.hammiedb to hammie.db + # This will work unless a user had hammie.db as their value for + # persistent_storage_file + if DEFAULTDB == options.default("Storage", "persistent_storage_file"): + DEFAULTDB = "~/.hammiedb" # Probability at which a message is considered spam From mhammond at users.sourceforge.net Tue Jul 8 04:53:19 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Tue Jul 8 06:53:22 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000/docs configuration.html, 1.3, 1.4 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000/docs In directory sc8-pr-cvs1:/tmp/cvs-serv15394 Modified Files: configuration.html Log Message: Couple of typos. Index: configuration.html =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/docs/configuration.html,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** configuration.html 19 Jun 2003 23:47:40 -0000 1.3 --- configuration.html 8 Jul 2003 10:53:17 -0000 1.4 *************** *** 59,63 **** uncommon for you to add a line
    [General]
    ! if you need to set options in this section, as by default, you INI file will have no such section.

    Additional Options

    --- 59,64 ---- uncommon for you to add a line
    [General]
    ! if you need to set options in this section, as by default, your INI ! file will have no such section.

    Additional Options

    *************** *** 167,171 **** ! [Genera]
    verbose
    --- 168,172 ---- ! [General]
    verbose
    *************** *** 219,223 **** in the data directory.  Using the name of the Outlook profile means that SpamBayes will work in a multi-profile environment.
  • !
  • The mail SpamBayes databases are then loaded from the nominated data directory.
--- 220,224 ---- in the data directory.  Using the name of the Outlook profile means that SpamBayes will work in a multi-profile environment. !
  • The main SpamBayes databases are then loaded from the nominated data directory.
  • From mhammond at users.sourceforge.net Tue Jul 8 04:54:30 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Tue Jul 8 06:54:33 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 about.html,1.14,1.15 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv15447 Modified Files: about.html Log Message: Add info about how to trim a large log file, and how to send mail to the list (rather than me ) Index: about.html =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/about.html,v retrieving revision 1.14 retrieving revision 1.15 diff -C2 -d -r1.14 -r1.15 *** about.html 1 Jul 2003 01:13:32 -0000 1.14 --- about.html 8 Jul 2003 10:54:28 -0000 1.15 *************** *** 260,264 ****

    This is free software.  Please offer any help you are able to.  In particular, contributions to this documentation are ! welcome!

    --- 260,266 ----

    This is free software.  Please offer any help you are able to.  In particular, contributions to this documentation are ! welcome!  If you don't know where to start, please send a mail, indicating any ! skills you may have we could use.

    From mhammond at users.sourceforge.net Tue Jul 8 04:54:30 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Tue Jul 8 06:54:35 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000/docs troubleshooting.html, 1.10, 1.11 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000/docs In directory sc8-pr-cvs1:/tmp/cvs-serv15447/docs Modified Files: troubleshooting.html Log Message: Add info about how to trim a large log file, and how to send mail to the list (rather than me ) Index: troubleshooting.html =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/docs/troubleshooting.html,v retrieving revision 1.10 retrieving revision 1.11 diff -C2 -d -r1.10 -r1.11 *** troubleshooting.html 25 Jun 2003 00:44:17 -0000 1.10 --- troubleshooting.html 8 Jul 2003 10:54:28 -0000 1.11 *************** *** 24,28 **** use.  You may also wish to see the latest ! online version of this document for problems added since release.

    Addin doesn't load

    --- 24,30 ---- use.  You may also wish to see the latest ! online version of this document for problems added since ! release.  If you must send someone a mail about SpamBayes, please read this first.

    Addin doesn't load

    *************** *** 193,198 ****

    All other problems

    ! If you are simply usnure about what SpamBayes is doing, please send a ! mail to the SpamBayes mailing list with as much information as possible.  If you are fairly sure you --- 195,201 ----

    All other problems

    ! If you are simply usnure about what SpamBayes is doing, please send a ! mail to the SpamBayes mailing list with as much information as possible.  If you are fairly sure you *************** *** 253,256 **** --- 256,277 ---- in some cases there will be errors in this file.  If there are errors, please report a bug.
    +

    If the log file is very large

    + This probably means that SpamBayes failed to process a large number of + (or a few, large) emails.  In that case, please perform the + following steps:
    +
      +
    • Ensure all messages in your watch folders are marked as read
    • +
    • Restart Outlook (use Exit and + Sign off if it is in your File + menu)
    • +
    • Send youself a test message, and wait for it to arrive.
    • +
    • Exit Outlook.
    • +
    + You should have a new log file containing the error when classifying + the test message.  If no error occurs processing the test message, + the previous large log file will still exist (see above).  Either + edit the file using a text editor to extract just the error + information, or zip it up.  If you don't know what that means, + please send a mail.

    Report a bug

    All SpamBayes bugs are maintained in Outlook.  Please ensure you attach the log file to the bug.
    ! If you are unsure about the bug, or need any assistance, please send a ! mail to the SpamBayes mailing ! list.


    --- 282,308 ---- style="font-style: italic;">Outlook.  Please ensure you attach the log file to the bug.
    ! If you are unsure about the bug, or need any assistance, please send a ! mail.

    +

    Send a mail

    + If all else fails, you may want to send someone a mail.,  Please + make sure you have read this document thoroughly before doing do.
    + Your mail should be sent to the SpamBayes + mailing + list (spambayes@python.org)  Please + do not mail any of the contributors directly (see "good karma" + below).
    + Please ensure this mail contains:
    +
      +
    • the version of Windows you are using
    • +
    • the version of SpamBayes
    • +
    • any log files.
    • +
    + If you also mention that you read this trouble-shooting guide and are + still stuck, then you will be more likely to get answered!  (And + if you can subscribe + to this mailing list and help answer other questions, good karma + will come your way!)

    From mhammond at users.sourceforge.net Tue Jul 8 05:26:13 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Tue Jul 8 07:26:16 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 manager.py,1.63,1.64 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv19784 Modified Files: manager.py Log Message: Nag source users they should upgrade win32all. Index: manager.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/manager.py,v retrieving revision 1.63 retrieving revision 1.64 diff -C2 -d -r1.63 -r1.64 *** manager.py 30 Jun 2003 01:06:21 -0000 1.63 --- manager.py 8 Jul 2003 11:26:11 -0000 1.64 *************** *** 479,482 **** --- 479,486 ---- # determine this. profile_name = "unknown_profile" + print "*** NOTE: It appears you are running the source-code version of" + print "* SpamBayes, and running a win32all version pre 154." + print "* If you work with multiple Outlook profiles, it is recommended" + print "* you upgrade - see http://starship.python.net/crew/mhammond""" else: # xxx - remove me sometime - win32all grew this post 154(ish) From mhammond at users.sourceforge.net Tue Jul 8 05:34:06 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Tue Jul 8 07:34:08 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 addin.py,1.69,1.70 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv21335 Modified Files: addin.py Log Message: Dont allow failure of a single toolbar item to prevent other toolbar items from being created (they may well all fail, but...) Index: addin.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/addin.py,v retrieving revision 1.69 retrieving revision 1.70 diff -C2 -d -r1.69 -r1.70 *** addin.py 1 Jul 2003 03:15:37 -0000 1.69 --- addin.py 8 Jul 2003 11:34:03 -0000 1.70 *************** *** 621,625 **** parent = self.toolbar # Now add the item itself to the parent. ! item = parent.Controls.Add(Type=control_type, Temporary=False) # Hook events for the item, but only if we haven't already in some # other explorer instance. --- 621,631 ---- parent = self.toolbar # Now add the item itself to the parent. ! try: ! item = parent.Controls.Add(Type=control_type, Temporary=False) ! except pythoncom.com_error, e: ! # Toolbars seem to still fail randomly for some users. ! # eg, bug [ 755738 ] Latest CVS outllok doesn't work ! print "FAILED to add the toolbar item '%s' - %s" % (tag,e) ! return # Hook events for the item, but only if we haven't already in some # other explorer instance. From mhammond at users.sourceforge.net Tue Jul 8 05:39:12 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Tue Jul 8 07:39:14 2003 Subject: [Spambayes-checkins] spambayes/spambayes storage.py,1.14,1.15 Message-ID: Update of /cvsroot/spambayes/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv22070 Modified Files: storage.py Log Message: Fix [ 760062 ] Traceback untraining a single message - typo in assert. We need a test suite! Index: storage.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/spambayes/storage.py,v retrieving revision 1.14 retrieving revision 1.15 diff -C2 -d -r1.14 -r1.15 *** storage.py 1 Jul 2003 01:19:51 -0000 1.14 --- storage.py 8 Jul 2003 11:39:10 -0000 1.15 *************** *** 190,194 **** self.db[key] = val.__getstate__() elif flag is WORD_DELETED: ! assert word not in self.wordinfo, \ "Should not have a wordinfo for words flagged for delete" # Word may be deleted before it was ever written. --- 190,194 ---- self.db[key] = val.__getstate__() elif flag is WORD_DELETED: ! assert key not in self.wordinfo, \ "Should not have a wordinfo for words flagged for delete" # Word may be deleted before it was ever written. From montanaro at users.sourceforge.net Tue Jul 8 08:33:21 2003 From: montanaro at users.sourceforge.net (Skip Montanaro) Date: Tue Jul 8 10:33:26 2003 Subject: [Spambayes-checkins] website faq.txt,1.9,1.10 Message-ID: Update of /cvsroot/spambayes/website In directory sc8-pr-cvs1:/tmp/cvs-serv19124 Modified Files: faq.txt Log Message: extend the whitelist/blacklist answer based upon Peter Houppermans' spambayes mailing list post. Index: faq.txt =================================================================== RCS file: /cvsroot/spambayes/website/faq.txt,v retrieving revision 1.9 retrieving revision 1.10 diff -C2 -d -r1.9 -r1.10 *** faq.txt 4 Jul 2003 02:57:04 -0000 1.9 --- faq.txt 8 Jul 2003 14:33:19 -0000 1.10 *************** *** 788,796 **** 'whitelist' (of sorts) is generated, as is a similar blacklist. ! These sorts of lists are problematic, because 'spoofing' (pretending you ! are someone else) is reasonably simple, and also fairly common. So, more ! often than not, they'll lead to incorrect results. However, there are some ! commercial products based on SpamBayes that offer whitelisting - see the ! `related page`_ for more information. .. _related page: related.html --- 788,807 ---- 'whitelist' (of sorts) is generated, as is a similar blacklist. ! Whitelists and blacklists are problematic anyway, because 'spoofing' ! (pretending you are someone else) is reasonably simple, and also very ! common. So, more often than not, they'll lead to incorrect results. ! However, there are some commercial products based on SpamBayes that offer ! whitelisting - see the `related page`_ for more information. ! ! Also, blacklisting is really a server side responsibility. SpamBayes is a ! content filter - it looks at what is inside the "envelope". Blacklisting, ! DNS based spam handling like rejecting mail without valid origin or from a ! known spam source is really the job of the mail server. In an ideal ! environment such mail will be rejected before it reaches you as it deals ! with what's "written on" the "envelope". ! ! Applying content based filtering on the server is complex, as everyone's ! feeling about content differs - this is why it is a client end role that ! tools like SpamBayes fill. .. _related page: related.html From anadelonbrin at users.sourceforge.net Tue Jul 8 18:53:40 2003 From: anadelonbrin at users.sourceforge.net (Tony Meyer) Date: Tue Jul 8 21:28:04 2003 Subject: [Spambayes-checkins] spambayes/spambayes hammiebulk.py,1.7,1.8 Message-ID: Update of /cvsroot/spambayes/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv27979/spambayes Modified Files: hammiebulk.py Log Message: Better fix, thanks to Helge Avlesen. (was not expanding the ~, and should really us os.path.join so that this works on other platforms). Index: hammiebulk.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/spambayes/hammiebulk.py,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -d -r1.7 -r1.8 *** hammiebulk.py 8 Jul 2003 00:08:53 -0000 1.7 --- hammiebulk.py 9 Jul 2003 00:53:38 -0000 1.8 *************** *** 66,70 **** # persistent_storage_file if DEFAULTDB == options.default("Storage", "persistent_storage_file"): ! DEFAULTDB = "~/.hammiedb" # Probability at which a message is considered spam --- 66,70 ---- # persistent_storage_file if DEFAULTDB == options.default("Storage", "persistent_storage_file"): ! DEFAULTDB = os.path.expanduser(os.path.join("~", ".hammiedb")) # Probability at which a message is considered spam From anadelonbrin at users.sourceforge.net Tue Jul 8 18:33:39 2003 From: anadelonbrin at users.sourceforge.net (Tony Meyer) Date: Tue Jul 8 21:39:07 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000/docs troubleshooting.html, 1.11, 1.12 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000/docs In directory sc8-pr-cvs1:/tmp/cvs-serv24740/Outlook2000/docs Modified Files: troubleshooting.html Log Message: Typo Index: troubleshooting.html =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/docs/troubleshooting.html,v retrieving revision 1.11 retrieving revision 1.12 diff -C2 -d -r1.11 -r1.12 *** troubleshooting.html 8 Jul 2003 10:54:28 -0000 1.11 --- troubleshooting.html 9 Jul 2003 00:33:37 -0000 1.12 *************** *** 195,199 ****

    All other problems

    ! If you are simply usnure about what SpamBayes is doing, please send a mail to the SpamBayes mailing --- 195,199 ----

    All other problems

    ! If you are simply unsure about what SpamBayes is doing, please send a mail to the SpamBayes mailing From anadelonbrin at users.sourceforge.net Tue Jul 8 22:28:55 2003 From: anadelonbrin at users.sourceforge.net (Tony Meyer) Date: Wed Jul 9 00:29:36 2003 Subject: [Spambayes-checkins] spambayes mboxtrain.py,1.9,1.10 Message-ID: Update of /cvsroot/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv24130 Modified Files: mboxtrain.py Log Message: Use /tmp/ as the temp directory, not /cur/tmp or /new/tmp. Fixes [ 768221 ] v1.0a4 dies when training on Maildir Index: mboxtrain.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/mboxtrain.py,v retrieving revision 1.9 retrieving revision 1.10 diff -C2 -d -r1.9 -r1.10 *** mboxtrain.py 4 Jul 2003 05:02:36 -0000 1.9 --- mboxtrain.py 9 Jul 2003 04:28:53 -0000 1.10 *************** *** 99,103 **** counter += 1 cfn = os.path.join(path, fn) ! tfn = os.path.join(path, "tmp", "%d.%d_%d.%s" % (time.time(), pid, counter, host)) --- 99,104 ---- counter += 1 cfn = os.path.join(path, fn) ! tfn = os.path.join(path, os.path.normpath(os.path.join("..", ! "tmp")), "%d.%d_%d.%s" % (time.time(), pid, counter, host)) From anadelonbrin at users.sourceforge.net Tue Jul 8 22:56:27 2003 From: anadelonbrin at users.sourceforge.net (Tony Meyer) Date: Wed Jul 9 00:57:29 2003 Subject: [Spambayes-checkins] spambayes/spambayes OptionsClass.py,1.2,1.3 Message-ID: Update of /cvsroot/spambayes/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv27214/spambayes Modified Files: OptionsClass.py Log Message: Allow $ in pathnames, and remove and old XXX comment. Note that this may very well fix [ 768162 ] UNC path for data_directory? at least for the original submitter. Index: OptionsClass.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/spambayes/OptionsClass.py,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** OptionsClass.py 16 Jun 2003 03:50:14 -0000 1.2 --- OptionsClass.py 9 Jul 2003 04:56:25 -0000 1.3 *************** *** 36,39 **** --- 36,40 ---- """ + # This module is part of the spambayes project, which is Copyright 2002-3 # The Python Software Foundation and is covered by the Python Software *************** *** 136,146 **** def is_valid(self, value): '''Check if this is a valid value for this option.''' - # XXX This test is in the original code, but makes no sense.... - # XXX self.allowed_values defaults to None, and if that is the - # XXX current value, then whatever is passed would be invalid - # XXX I agree this is a silly state to be in, but it is possible - # XXX I suppose that self.allowed_values should default to *any* - # XXX rather than None, but I'm not sure how to express that, - # XXX unless the regex r"." is correct. if self.allowed_values is None: return False --- 137,140 ---- *************** *** 690,694 **** PORT = r"[\d]+" EMAIL_ADDRESS = r"[\w\-\.]+@[\w\-\.]+" ! PATH = r"[\w\.\-~:\\/\*]+" VARIABLE_PATH = PATH + r"%" FILE = r"[\S]+" --- 684,688 ---- PORT = r"[\d]+" EMAIL_ADDRESS = r"[\w\-\.]+@[\w\-\.]+" ! PATH = r"[\w\$\.\-~:\\/\*]+" VARIABLE_PATH = PATH + r"%" FILE = r"[\S]+" From anadelonbrin at users.sourceforge.net Wed Jul 9 00:35:51 2003 From: anadelonbrin at users.sourceforge.net (Tony Meyer) Date: Wed Jul 9 02:35:58 2003 Subject: [Spambayes-checkins] spambayes mboxtrain.py,1.10,1.11 Message-ID: Update of /cvsroot/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv6865 Modified Files: mboxtrain.py Log Message: A tider method with one fewer call to os.path.join, based on a suggestion from Leonid. Index: mboxtrain.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/mboxtrain.py,v retrieving revision 1.10 retrieving revision 1.11 diff -C2 -d -r1.10 -r1.11 *** mboxtrain.py 9 Jul 2003 04:28:53 -0000 1.10 --- mboxtrain.py 9 Jul 2003 06:35:49 -0000 1.11 *************** *** 99,106 **** counter += 1 cfn = os.path.join(path, fn) ! tfn = os.path.join(path, os.path.normpath(os.path.join("..", ! "tmp")), "%d.%d_%d.%s" % (time.time(), pid, ! counter, host)) if loud: sys.stdout.write(" %s \r" % fn) --- 99,105 ---- counter += 1 cfn = os.path.join(path, fn) ! tfn = os.path.normpath(os.path.join(path, "..", "tmp", "%d.%d_%d.%s" % (time.time(), pid, ! counter, host))) if loud: sys.stdout.write(" %s \r" % fn) From mhammond at users.sourceforge.net Wed Jul 9 01:51:45 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Wed Jul 9 03:51:49 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 filter.py, 1.25, 1.26 msgstore.py, 1.47, 1.48 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv16296 Modified Files: filter.py msgstore.py Log Message: Use the passed field name rather than hardcoded "Spam". msgstore: Don't catch exceptions doing a save - let the caller do that. filter: Catch the above mentioned exceptions :) This puts the dodgy IMAP and hotmail handling in one place and fixes: 765042: IMAP mail fails to filter Index: filter.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/filter.py,v retrieving revision 1.25 retrieving revision 1.26 diff -C2 -d -r1.25 -r1.26 *** filter.py 18 Jun 2003 01:59:02 -0000 1.25 --- filter.py 9 Jul 2003 07:51:42 -0000 1.26 *************** *** 10,13 **** --- 10,14 ---- True, False = 1, 0 + import pythoncom # for the exceptions. def filter_message(msg, mgr, all_actions=True): *************** *** 41,53 **** msg.RememberMessageCurrentFolder() msg.Save() ! except: ! # XXX - unfortunately, for the case I added this code, a failing ! # Save *did* imply a failing Move :( ! # I also heard a rumour hotmail works if we do 2 saves. ! # This should be revisited. ! print "Failed to save the Spam score for message ", msg ! import traceback ! traceback.print_exc() ! print "Still (possibly) atempting to move this message though..." if all_actions and attr_prefix is not None: --- 42,60 ---- msg.RememberMessageCurrentFolder() msg.Save() ! except pythoncom.com_error, (hr, msg, exc, arg_err): ! # This seems to happen for IMAP mails (0x800cccd3) ! # and also for hotmail messages (0x8004dff7) ! known_failure_codes = -2146644781, -2147164169 ! # I also heard a rumour hotmail works if we do 2 saves ! if hr not in known_failure_codes: ! print "Unexpected MAPI error saving the spam score for", msg ! print hr, msg, exc ! else: ! # So we can see if it still happens :) ! mgr.LogDebug(1, "Note: known (but still not understood) " \ ! "error 0x%x saving the spam score." % hr) ! # No need for a traceback in this case. ! # Clear dirty flag anyway ! msg.dirty = False if all_actions and attr_prefix is not None: Index: msgstore.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/msgstore.py,v retrieving revision 1.47 retrieving revision 1.48 diff -C2 -d -r1.47 -r1.48 *** msgstore.py 17 Jun 2003 02:04:11 -0000 1.47 --- msgstore.py 9 Jul 2003 07:51:42 -0000 1.48 *************** *** 427,431 **** table = folder.GetContentsTable(0) # Resolve the field name ! resolve_props = ( (mapi.PS_PUBLIC_STRINGS, "Spam"), ) resolve_ids = folder.GetIDsFromNames(resolve_props, 0) field_id = PROP_TAG( PT_DOUBLE, PROP_ID(resolve_ids[0])) --- 427,431 ---- table = folder.GetContentsTable(0) # Resolve the field name ! resolve_props = ( (mapi.PS_PUBLIC_STRINGS, scoreFieldName), ) resolve_ids = folder.GetIDsFromNames(resolve_props, 0) field_id = PROP_TAG( PT_DOUBLE, PROP_ID(resolve_ids[0])) *************** *** 793,803 **** def Save(self): assert self.dirty, "asking me to save a clean message!" ! try: ! self.mapi_object.SaveChanges(mapi.KEEP_OPEN_READWRITE | USE_DEFERRED_ERRORS) ! except pythoncom.com_error, details: ! # hotmail gives this error - not sure what code, but ! # we don't want to mask other errors. ! if details[0] != -2147164169: # 0x8004dff7 ! raise self.dirty = False --- 793,802 ---- def Save(self): assert self.dirty, "asking me to save a clean message!" ! # There are some known exceptions that can be raised by IMAP and hotmail ! # For now, we just let the caller handle all errors, and manually ! # reset the dirty flag. Only current caller is filter.py ! # There are also some issues with the "unread flag" that fiddling this ! # save code may fix. ! self.mapi_object.SaveChanges(mapi.KEEP_OPEN_READWRITE | USE_DEFERRED_ERRORS) self.dirty = False From mhammond at users.sourceforge.net Wed Jul 9 02:13:15 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Wed Jul 9 04:13:18 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 addin.py,1.70,1.71 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv19221 Modified Files: addin.py Log Message: Include the Windows version in the log. Index: addin.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/addin.py,v retrieving revision 1.70 retrieving revision 1.71 diff -C2 -d -r1.70 -r1.71 *** addin.py 8 Jul 2003 11:34:03 -0000 1.70 --- addin.py 9 Jul 2003 08:13:13 -0000 1.71 *************** *** 813,816 **** --- 813,819 ---- print "%s starting (with engine %s)..." % \ (get_version_string("Outlook"), get_version_string()) + major, minor, spack, platform, ver_str = win32api.GetVersionEx() + print "On Windows version %d.%d.%d (%s)" % \ + (major, minor, spack, ver_str) self.explorers_events = None # create at OnStartupComplete From anadelonbrin at users.sourceforge.net Thu Jul 10 17:19:18 2003 From: anadelonbrin at users.sourceforge.net (Tony Meyer) Date: Thu Jul 10 19:19:21 2003 Subject: [Spambayes-checkins] website faq.txt,1.10,1.11 Message-ID: Update of /cvsroot/spambayes/website In directory sc8-pr-cvs1:/tmp/cvs-serv7027 Modified Files: faq.txt Log Message: Add a question about moving the outlook training data between computers. Index: faq.txt =================================================================== RCS file: /cvsroot/spambayes/website/faq.txt,v retrieving revision 1.10 retrieving revision 1.11 diff -C2 -d -r1.10 -r1.11 *** faq.txt 8 Jul 2003 14:33:19 -0000 1.10 --- faq.txt 10 Jul 2003 23:19:15 -0000 1.11 *************** *** 385,388 **** --- 385,399 ---- + Can I share/move my training data from one computer to another? + --------------------------------------------------------------- + + Yes. All you have to do is move the data directory between the computers. + You will probably want to ignore the 'ini' files, as each computer will + need its own configuration, and move only the 'db' files. For information + about finding this directory, see the `backup question`_. + + .. _`backup question`: #can-i-back-up-the-outlook-database-should-i-do-this + + Using Spambayes =============== From montanaro at users.sourceforge.net Fri Jul 11 06:51:10 2003 From: montanaro at users.sourceforge.net (Skip Montanaro) Date: Fri Jul 11 08:51:12 2003 Subject: [Spambayes-checkins] website faq.txt,1.11,1.12 Message-ID: Update of /cvsroot/spambayes/website In directory sc8-pr-cvs1:/tmp/cvs-serv9212 Modified Files: faq.txt Log Message: link to plugin troubleshooting guide Index: faq.txt =================================================================== RCS file: /cvsroot/spambayes/website/faq.txt,v retrieving revision 1.11 retrieving revision 1.12 diff -C2 -d -r1.11 -r1.12 *** faq.txt 10 Jul 2003 23:19:15 -0000 1.11 --- faq.txt 11 Jul 2003 12:51:07 -0000 1.12 *************** *** 316,323 **** ----------------------------------------------------- ! The 002 installer for the binary has a number of problems with various versions of Outlook/Windows. However, to our knowledge, the 003 installer ! should work with any combination of Windows/Outlook versions. Please ! let us know if this is not the case. --- 316,326 ---- ----------------------------------------------------- ! The 002 installer for the binary had a number of problems with various versions of Outlook/Windows. However, to our knowledge, the 003 installer ! should work with any combination of Windows/Outlook versions. Please let us ! know if this is not the case. The `troubleshooting guide`_ for the Outlook ! plugin contains the most up-to-date help for working around known problems. ! ! .. _troubleshooting guide: http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/*checkout*/spambayes/spambayes/Outlook2000/docs/troubleshooting.html?rev=HEAD&content-type=text/plain From richiehindle at users.sourceforge.net Sun Jul 13 10:12:30 2003 From: richiehindle at users.sourceforge.net (Richie Hindle) Date: Sun Jul 13 13:30:15 2003 Subject: [Spambayes-checkins] spambayes/spambayes/resources classify_gif.py, 1.2, 1.3 config_gif.py, 1.2, 1.3 helmet_gif.py, 1.2, 1.3 message_gif.py, 1.2, 1.3 query_gif.py, 1.2, 1.3 status_gif.py, 1.2, 1.3 train_gif.py, 1.2, 1.3 ui_html.py, 1.15, 1.16 ui_psp.py, 1.2, 1.3 Message-ID: Update of /cvsroot/spambayes/spambayes/spambayes/resources In directory sc8-pr-cvs1:/tmp/cvs-serv16177 Modified Files: classify_gif.py config_gif.py helmet_gif.py message_gif.py query_gif.py status_gif.py train_gif.py ui_html.py ui_psp.py Log Message: Regenerated these using the latest ResourcePackage, which silences the warnings reported in 770175. Index: classify_gif.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/spambayes/resources/classify_gif.py,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** classify_gif.py 29 Jan 2003 03:23:35 -0000 1.2 --- classify_gif.py 13 Jul 2003 16:12:28 -0000 1.3 *************** *** 1,61 **** """Resource classify_gif (from file classify.gif)""" # written by resourcepackage: (1, 0, 0) source = 'classify.gif' package = 'spambayes.resources' ! data = 'GIF89a(\x00(\x00\xf7\x00\x00\x00\x7f\xf6\x04\x81\xf6\x08\x83\xf6\x0c\x85\ ! \xf6\x10\x87\xf7\x14\x89\xf7\x18\x8b\xf7\x1c\x8d\xf7 \x8f\xf7$\x91\xf7(\x93\ ! \xf7,\x95\xf80\x97\xf84\x99\xf88\x9b\xf8<\x9d\xf8@\x9f\xf8D\xa1\xf8H\xa3\xf9\ ! L\xa5\xf9P\xa7\xf9T\xa9\xf9X\xab\xf9\\\xad\xf9`\xaf\xf9d\xb1\xfah\xb3\xfal\ ! \xb5\xfap\xb7\xfat\xb9\xfax\xbb\xfa|\xbd\xfa\x80\xbf\xfb\x84\xc1\xfb\x88\xc3\ ! \xfb\x8c\xc5\xfb\x90\xc7\xfb\x94\xc9\xfb\x98\xcb\xfb\x9c\xcd\xfc\xa0\xcf\xfc\ ! \xa4\xd1\xfc\xa8\xd3\xfc\xac\xd5\xfc\xb0\xd7\xfc\xb4\xd9\xfc\xb8\xdb\xfc\xbc\ ! \xdd\xfd\xc0\xdf\xfd\xc4\xe1\xfd\xc8\xe3\xfd\xcc\xe5\xfd\xd0\xe7\xfd\xd4\xe9\ ! \xfd\xd8\xeb\xfe\xdc\xed\xfe\xe0\xef\xfe\xe4\xf1\xfe\xe8\xf3\xfe\xec\xf5\xfe\ ! \xf0\xf7\xfe\xf4\xf9\xff\xf8\xfb\xff\xfc\xfd\xff\xff\xff\xff\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,\ ! \x00\x00\x00\x00(\x00(\x00\x00\x08\xfe\x00\x81\x08\x1cH\xb0\xa0\xc1\x83\x08\ ! \x13*\\\xc8\xb0\xa1\xc3\x87\x10#J\x9cH\xb1\xa2\xc5\x8b\x12o\x98\xb8\xd0\xc0\ ! \x00\x80\x8f\x06\x18\\(q\x03\xe3\x0f\x14\r>\xaa\\\xb9\xb2\x01\x8a\x1f\x14]$\ ! \xf8\xd8@\x04\x8d\x13+\x03<\x18\x11!\xc0\xc7\x04-"\xfa\xd0\xf0\xf1\x01\x8c\ ! \x81>X\xf0\x00\x92\xc3\x04\x02\x05:n`\xf0\t \x83\x0f\x87=\x1e\x00\x08@\xe2`J\ ! \x03\x1ct<\x88 \x90\x06\x83\xa2;\x18f\xdd\xbab \xcc\x81\x1cTBE\xc0B\xa0\x8f\ ! \x0b4{,\xac\xf01\x05A\x072\x06\xde\xa0\n\xa0\xc3\t\t\x04\xe3\x02\xa0\xa0\x10\ ! \xc5G\x0c\x05\x05\xecx\x10B\x07\x10\n*\x0f\xec @\xf0\x87\x84\x8f(\x12"\xf8X\ ! \x92 \x00 \x1f\x05\x8c\\\x89\xba\xa0\x8d\x8f\x08\x12:\x06 \xe1\xad\xc0\x029F\ ! \xb3\x04\xa0\x993A\xcc\x00B\'\xe4\x0b\x80\x03\xc1\n\'>\xec\x06\xe0!\x05\xe2\ ! \x81\xca\x17/\\\x0b\x00\xc3U 0\x10\x88e\xf9@\x87\x82\xba\x02\xa3p?\xd0;]+\ ! \x00\x064\x04Z\xe8\xee\xe1\x00o\x0f:*\x90\x05\xa2\xe33\x80\xf1\x0e\x7f\x10\ ! \xdd\xba\x01GV\x04\'\xa4\xb5\x03\n\t@\xc5\x03\x08\x04|\xa4\xc1u\x0f\xc9\xf4Q\ ! \x00\x12\x94 \x01a\x01@@\xc2\x05\x02\xfc\x14\xd4D\'\xa5\xb4\x1cK.\xd9V\x91F\ ! \x1cy\x04\x92H$a\xa4\xe2\x8a,\xb6\xe8\xe2\x8b0\xc6(\xe3\x8c4\xd6h\xe3\x8d8\ ! \xe6\xa8\xe3\x8e+\x06\x04\x00;' ### end --- 1,26 ---- + # -*- coding: ISO-8859-1 -*- """Resource classify_gif (from file classify.gif)""" # written by resourcepackage: (1, 0, 0) source = 'classify.gif' package = 'spambayes.resources' ! data = "GIF89a(\000(\000÷\000\000\000ö\004ö\010ƒö\014…ö\020‡÷\024‰÷\030‹÷\034÷ ÷$‘÷(“÷,•ø0—ø4™ø8›ø<\ ! ø@ŸøD¡øH£ùL¥ùP§ùT©ùX«ù\\­ù`¯ùd±úh³úlµúp·út¹úx»ú|½ú€¿û„ÁûˆÃûŒÅ\ ! ûÇû”Éû˜ËûœÍü Ïü¤Ñü¨Óü¬Õü°×ü´Ùü¸Ûü¼ÝýÀßýÄáýÈãýÌåýÐçýÔéýØëþÜí\ ! þàïþäñþèóþìõþð÷þôùÿøûÿüýÿÿÿÿ\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\ ! \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\ ! \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\ ! \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\ ! \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\ ! \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\ ! \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\ ! \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\ ! \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\ ! \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\ ! \000,\000\000\000\000(\000(\000\000\010þ\000\010\034H° Áƒ\010\023*\\È°¡Ã‡\020#JœH±¢Å‹\022o˜¸ÐÀ\000€\006\030\\(q\003ã\017\024\015>\ ! ª\\¹²\001Š\037\024]$øØ@\004\023+\003<\030\021!ÀÇ\004-\"úÐðñ\001Œ>Xð\000’Ã\004\002\005:n`ð\011 ƒ\017‡=\036\000\010@â`J\ ! \003\034t<ˆ \006ƒ¢;\030fݺb Ì\034TBEÀB \0134{,¬ð1\005A\0072\006Þ \012 Ã\011\011\004ã\002  \020ÅG\014\005\005ìx\020\ ! B\007\020\012*\017ì @ð‡„(\022\"øX’ \000 \037\005Œ\\‰º \010\022:\006 á­À\0029F³\004 ™3AÌ\000B'ä\013€\003Á\012'>\ ! ì\006à!\005âÊ\027/\\\013\000ÃU 0\020ˆeù@‡‚º\002£p?Ð;]+\000\0064\004Zèîá\000o\017:*\005¢ã3€ñ\016\020ݺ\001G\ ! V\004'¤µ\003\012\011@Å\003\010\004|¤Áu\017ÉôQ\000\022” \001a\001@@Â\005\002ü\024ÔD'¥´\034K.ÙV‘F\034y\004’H$a¤âŠ,¶è\ ! â‹0Æ(ãŒ4Öhã8æ¨ãŽ+\006\004\000;" ### end Index: config_gif.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/spambayes/resources/config_gif.py,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** config_gif.py 29 Jan 2003 03:23:35 -0000 1.2 --- config_gif.py 13 Jul 2003 16:12:28 -0000 1.3 *************** *** 1,52 **** """Resource config_gif (from file config.gif)""" # written by resourcepackage: (1, 0, 0) source = 'config.gif' package = 'spambayes.resources' ! data = 'GIF89a(\x00(\x00\xf7\x00\x00\x00\x7f\xf6\x04\x81\xf6\x08\x83\xf6\x0c\x85\ ! \xf6\x10\x87\xf7\x14\x89\xf7\x18\x8b\xf7\x1c\x8d\xf7 \x8f\xf7$\x91\xf7(\x93\ ! \xf7,\x95\xf80\x97\xf84\x99\xf88\x9b\xf8<\x9d\xf8@\x9f\xf8D\xa1\xf8H\xa3\xf9\ ! L\xa5\xf9P\xa7\xf9T\xa9\xf9X\xab\xf9\\\xad\xf9`\xaf\xf9d\xb1\xfah\xb3\xfal\ ! \xb5\xfap\xb7\xfat\xb9\xfax\xbb\xfa|\xbd\xfa\x80\xbf\xfb\x84\xc1\xfb\x88\xc3\ ! \xfb\x8c\xc5\xfb\x90\xc7\xfb\x94\xc9\xfb\x98\xcb\xfb\x9c\xcd\xfc\xa0\xcf\xfc\ ! \xa4\xd1\xfc\xa8\xd3\xfc\xac\xd5\xfc\xb0\xd7\xfc\xb4\xd9\xfc\xb8\xdb\xfc\xbc\ ! \xdd\xfd\xc0\xdf\xfd\xc4\xe1\xfd\xc8\xe3\xfd\xcc\xe5\xfd\xd0\xe7\xfd\xd4\xe9\ ! \xfd\xd8\xeb\xfe\xdc\xed\xfe\xe0\xef\xfe\xe4\xf1\xfe\xe8\xf3\xfe\xec\xf5\xfe\ ! \xf0\xf7\xfe\xf4\xf9\xff\xf8\xfb\xff\xfc\xfd\xff\xff\xff\xff\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,\ ! \x00\x00\x00\x00(\x00(\x00\x00\x08\x9b\x00\x81\x08\x1cH\xb0\xa0\xc1\x83\x08\ ! \x13*\\\xc8\xb0\xa1\xc3\x87\x10#J\x9c\x08\x84\x03E\x89\x1c\x00\\\x84\x98Q\ ! \xe3\xc6\x86\x1d=~T\x18R\xe4\xc8\x83%M\x9e$\x98R%C\x8b \x01\xc8\x9c\xe9r!\ ! \x00\x98$i\xd2\x8c(\x13\'J\x9d;!\xce\xf4\xc9\x12\xe8P\x9eG\x0b\xb6L*\x94\xa6\ ! \xcf\xa5=\'\x02\x85\t\xf5&E\xa3\x1c\xaa\x12mj\xb4\xebV\xae]u~\xe5\x18V\xec\ ! \xc9\xaaLG\xa2\x1d{\x11*\xdb\x8d-\xdf~,)Wm\xd4\x95$\xeb\xe2\xdd\xcb\xb7\xaf\ ! \xdf\xbf\x80\x03\x0b\x1eL\xb8\xb0\xe1\x8b\x01\x01\x00;' ### end --- 1,22 ---- + # -*- coding: ISO-8859-1 -*- """Resource config_gif (from file config.gif)""" # written by resourcepackage: (1, 0, 0) source = 'config.gif' package = 'spambayes.resources' ! data = "GIF89a(\000(\000÷\000\000\000ö\004ö\010ƒö\014…ö\020‡÷\024‰÷\030‹÷\034÷ ÷$‘÷(“÷,•ø0—ø4™ø8›ø<\ ! ø@ŸøD¡øH£ùL¥ùP§ùT©ùX«ù\\­ù`¯ùd±úh³úlµúp·út¹úx»ú|½ú€¿û„ÁûˆÃûŒÅ\ ! ûÇû”Éû˜ËûœÍü Ïü¤Ñü¨Óü¬Õü°×ü´Ùü¸Ûü¼ÝýÀßýÄáýÈãýÌåýÐçýÔéýØëþÜí\ ! þàïþäñþèóþìõþð÷þôùÿøûÿüýÿÿÿÿ\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\ ! \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\ ! \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\ ! \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\ ! \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\ ! \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\ ! \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\ ! \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\ ! \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\ ! \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\ ! \000,\000\000\000\000(\000(\000\000\010›\000\010\034H° Áƒ\010\023*\\È°¡Ã‡\020#Jœ\010„\003E‰\034\000\\„˜QãƆ\035=~T\030Räȃ%M\ ! ž$˜R%C‹ \001Èœér!\000˜$iÒŒ(\023'J;!ÎôÉ\022èPžG\013¶L*”¦Ï¥='\002…\011õ&E£\034ª\022mj´ëV\ ! ®]u~å\030VìɪLG¢\035{\021*Û-ß~,)WmÔ•$ëâÝË·¯ß¿€\003\013\036L¸°á‹\001\001\000;" ### end Index: helmet_gif.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/spambayes/resources/helmet_gif.py,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** helmet_gif.py 29 Jan 2003 03:23:35 -0000 1.2 --- helmet_gif.py 13 Jul 2003 16:12:28 -0000 1.3 *************** *** 1,65 **** """Resource helmet_gif (from file helmet.gif)""" # written by resourcepackage: (1, 0, 0) source = 'helmet.gif' package = 'spambayes.resources' ! data = 'GIF89a"\x00\x18\x00\xf7\x00\x00BBFUSTcZR^^^kZVoe\\kkgskcwog\x87tf{wt\x89\ ! \x87\x87\x94~k\xa1\x83p\x9c\x94\x8e\xb4\x9d\x8d\xa5\xa5\xad\xad\xad\xad\xad\ ! \xad\xb5\xaf\xb7\xba\xbd\xad\xad\xc0\xbd\xb7\xb5\xbd\xca\xc0\xc3\xc8\xc6\xc6\ ! \xce\xc6\xd2\xde\xbd\xd6\xef\xc6\xd6\xef\xc6\xde\xef\xc6\xde\xf7\xbd\xde\xff\ ! \xc6\xe7\xff\xce\xa9\x8c\xd6\xaf\x91\xce\xbd\xad\xef\xcb\xad\xce\xcb\xcb\xd6\ ! \xda\xe2\xf7\xd6\xbd\xe4\xe1\xe4\xce\xde\xef\xd6\xde\xef\xd6\xe7\xef\xde\xe7\ ! \xef\xe7\xeb\xeb\xef\xef\xe7\xef\xef\xef\xf7\xf7\xef\xce\xde\xf7\xce\xe7\xf7\ ! \xce\xe7\xff\xd6\xe7\xf7\xd6\xe7\xff\xd6\xef\xff\xde\xe7\xf7\xde\xef\xfb\xe7\ ! \xef\xf7\xe7\xf7\xff\xef\xef\xf7\xef\xf7\xff\xf7\xf7\xf7\xf7\xff\xff\xff\xff\ ! \xf7\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00!\xf9\x04\x01\x00\x00\x1e\x00,\x00\ ! \x00\x00\x00"\x00\x18\x00\x00\x08\xfe\x00=\x08\x1cH\xb0\xa0\xc1\x83\x03e\xc8\ ! \xf0\xf0a\xc6\r\x84\x10#~`\x91\xe3\xc3\x07\x1c;>D\xdcXP\x06\x0b\x1e2b\xb8\ ! \xe0\xa1\x91\xa3I\x1a,|\xd0\x10\xd9c\xa1I\x8e4N\xf8\xb8a\xc3\xc5\x0f\x1a/a\ ! \xa6\xccQ\xf3f\xce\x8d4Z\xfc\xc8\xa1\xc2\xe6\xc3\x9f\x10E\x0eU\xc1\xe2G\xc6\ ! \x8d\x16K"\xfc\xb0\x82\xc7R\x99=p"\x94\xb1\xc1\x02\x86\x0c1 z\xf41\x14\x86\ ! \xcc\xa1R\t~\xc0\xe0@\xc1\x02\x07\x16\xc2\x1a\xa4jsh\x87\x13V{\xdcH\xeb\x01\ ! \x86\x05\x05\x06\x06\x140\xa0 \x02\n\x8d\x1fbth\xf8\xf1G\xd6\x0f%\xea\xea\ ! \x95\x81"\xc3\x86\x18\x13\x14\x0c\xd8\\\xa0\xc0\x81\xc2)P`\x88\x10\xa1\x04\ ! \x8b\x17?\x9c.\xdcp\xf6\x07\x0f\x0c\x0bbC\xd0,\xa0\x00\x81\xce\x9e\x158p\xb0\ ! \xc0\xed\x05\xab\xa9\xf7z\x88\x119u\x0b\x07\x06\x02o\x1e \xe06\x82\x03\xd0\ ! \x0fDÜXP\006\013\0362b¸\ ! à¡‘£I\032,|Ð\020Ùc¡IŽ4Nø¸aÃÅ\017\032/a¦ÌQófÎ4ZüÈ¡Âæß\020E\016UÁâGÆ\026K\"ü°‚ÇR™\ ! =p\"”±Á\002†\0141 zô1\024†Ì¡R\011~Àà@Á\002\007\026Â\032¤jsh‡\023V{ÜHë\001†\005\005\006\006\0240  \002\012\037bthøñ\ ! GÖ\017%êê•\"Æ\030\023\024\014Ø\\ ÀÂ)P`ˆ\020¡\004‹\027?œ.Üpö\007\017\014\013bCÐ, \000Ξ\0258p°Àí\005«©÷z\ ! ˆ\0219u\013\007\006\002o\036 à6‚\003Ð\017`yd\x07\n<\xa5\xd0\t?\x05\x80\xc1\r?H\x90\x82A\ ! 4\xa8f\x90\x0b\x0c\x98\xd0P\x97=t\x10\x80\x04\x06\x8d\xd0AK\x0b\xb0 \x14\x0c\ ! \x08\x14U\xe1K?\x85\x06R\x0c\x0c\xe4t@M#,\x00$\x04A\xb5T\x90\x003\x00A\xc3\ ! \x07 \x12x0\x12\x08U\xb6T\x82\x01\x00@\x00f\x00\x14\x84\xa8\xea\xaf\xc0\x06+\ ! \xec\xb0\xc4\x16k\xacB\x01\x01\x00;' ### end --- 1,29 ---- + # -*- coding: ISO-8859-1 -*- """Resource train_gif (from file train.gif)""" # written by resourcepackage: (1, 0, 0) source = 'train.gif' package = 'spambayes.resources' ! data = "GIF89a(\000(\000÷\000\000\000ö\004ö\010ƒö\014…ö\020‡÷\024‰÷\030‹÷\034÷ ÷$‘÷(“÷,•ø0—ø4™ø8›ø<\ ! ø@ŸøD¡øH£ùL¥ùP§ùT©ùX«ù\\­ù`¯ùd±úh³úlµúp·út¹úx»ú|½ú€¿û„ÁûˆÃûŒÅ\ ! ûÇû”Éû˜ËûœÍü Ïü¤Ñü¨Óü¬Õü°×ü´Ùü¸Ûü¼ÝýÀßýÄáýÈãýÌåýÐçýÔéýØëþÜí\ ! þàïþäñþèóþìõþð÷þôùÿøûÿüýÿÿÿÿ\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\ ! \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\ ! \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\ ! \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\ ! \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\ ! \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\ ! \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\ ! \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\ ! \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\ ! \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\ ! \000,\000\000\000\000(\000(\000\000\010þ\000\010\034H° Áƒ\010\023*\\È°¡Ã‡\020#JœHÑa\015\012\001\0028€\000À@‰Š\010€(\000ƒ„\0174€\ ! Ì\020\000Òà\012\020røX0‚Lj\003\000\0000ˆÑRFN\000\025~\010¼1`\000\002\030@~°XвÃ\010ƒ\022\002tèA\020@C\023\014\\\034d²`\012\ ! \011?n`\010ðóÄÂ\021\012:x88À‡Ë\010\012(¨p\013ÄÅ€…\010fÜ€pÐêÁ\013\031~ؘ\000@#K…~\015\010-8€ÇÁ\037\020\020LX!\ ! ôÅ\001­\011\025Ø\000RamÁ\0062\020†x óE\010\033/\030(\024Á\001H\017\006$\012~\010\0212„\001\001\033èúEÈÃÀ\016 :\024¬ X#'\010:\026\ ! ºh°ÐCl 7\016¼py‚\001Ý‚:`xÈ»Ð\006_5\014þÜ8È¡uU\000\004\034„pÌ\020\001A\026\015\026\023üÑ€\005A÷\014y„p@ g\ ! Áò\007Ý`@\015\003A°™B3 à\001\014É\031ä\003\003'È7eã\001A‚g\0115€YB:DÐ\037\000\004\016´‚\002Éí`\000{\010ùåÃ\006\002\030\020\ ! ‚„\004…ðAA$0@\025\007\"(ÄÀ\0136„ð‚\0179<@ÛA20W\007\025\000aƒ\002\012¹ ]R+L€\000\0040\012ÄÃ]\005ý`€@»!$\ ! €\003dM`Ã\017\031\\âA\020ÜàB\003`æƒ\012\024(\020A•>`yd\007\012<¥Ð\011?\005€Á\015?H‚A4¨f\013\014˜ÐP—=t\020\ ! €\004\006ÐAK\013° \024\014\010\024UáK?…\006R\014\014ät@M#,\000$\004AµT\0003\000AÃ\007 \022x0\022\010U¶T‚\001\000@\000f\000\024„\ ! ¨ê¯À\006+ì°Ä\026k¬B\001\001\000;" ### end Index: ui_html.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/spambayes/resources/ui_html.py,v retrieving revision 1.15 retrieving revision 1.16 diff -C2 -d -r1.15 -r1.16 *** ui_html.py 7 Jul 2003 20:58:37 -0000 1.15 --- ui_html.py 13 Jul 2003 16:12:28 -0000 1.16 *************** *** 1,2 **** --- 1,3 ---- + # -*- coding: ISO-8859-1 -*- """Resource ui_html (from file ui.html)""" # written by resourcepackage: (1, 0, 0) *************** *** 5,185 **** import zlib ! data = zlib.decompress('x\xda\xdd;ms\xdb\xc6\xd1\xdf3\x93\xffpA\xc7\x864\x95HJ\xb2\xdd\x84"1\xb5e%\ ! \xceS;V%\xa6\x9dL&\xa39\x02G\x12\x15\x80C\x81\x83$>\x9e\xfe\xf7\xee\xee\xdd\ ! \x01\x87\x17It\xd3\xb43\x95="\x81\xbb\xdb\xdb\xdd\xdb\xf7=\xcd\xbez\xfb\xf1l\ ! \xf1\xd3\xc59{\xb7\xf8\xf0\x9e]\xfc\xf8\xe6\xfd\xf7g\xcc;\x1c\x8f\xffzr6\x1e\ ! \xbf]\xbc\xd5\x03/F\x93#\xb6(xV\xc6*\x96\x19O\xc6\xe3\xf3\x1f\xbc\xe0\xcb/f\ ! \x1b\x95&\xf4)x\x84\x9f*V\x89`q4\xf7\xe8\x9b\x17\\\xe5<]\xf2\xad(\xd9\x8f\ ! \xa5(\xd8\xf7\x99\x12\xc5\x8a\x87b6\xa6\t\xb8&\x15\x8a\xb3\x8dR\xf9\xa1\xf8{\ ! \x15\xdf\xce\xbd\x8b\x82\xafS\xee\xb1P\xc2\xecL\xcd\xbdL\x1e\x86<\xdc\x08\ ! \x8f\x8d\x07\x17\x9c\xe9\xc1\x9d\xe7\x9f\xdf\xe7q!Jg\xc5bS\x1d0 \xf2\xffx\ ! \xc6\x8e\xbe\xf9\xc3\x84M&S\xfa\xcf\xbe\xfb\xb0xt\xdb\xc33\x80Q\xc8d`\xfb\ ! \x03\x96V\xa5:,\xc4-O\xe2\x88+x\x01C\xa5\x92\x85\xc5\xacT[\xe2\xc1RF[\xf6\ ! \x89\xad\x00\xc2\x94}3y\xc6x\x11\xf3\xe4\x80\x95wqY\x1e\xb0\x8dHn\x85\x8aC~\ ! \xcaR^\xac\xe3l\xca&\xec\x1f_~\xa1\xf8\x12\xb8\xbd\xc3:\x9c\xbc\x92E\ns[\x00\ ! \xbe\xfc\x82O\x938\xbb\x81\xf7\xa1Ld1e\xbf\x9b\xc0OH\x83|z\x1b\xc3\x81\x8b\ ! \xe8\x81\xd1\x8d\xbc\x85\x13m\xc6^M^LV+\x1c\x1b\x19V0n\x90;\xbc\x13\xf1z\x03\ ! 8.e\x12\xd1\x8c\xdbX\xdc\xd1\xce\xbd)\x19\xe0\xc9\x13\x8d\xddh\xc9\xb3\x8c6Y\ ! \xf2\xf0f]\xc8*\x8b`\xa7p"`\xa7S\x96\xf3(\x8a\xb3\xf5\xfce\xfd\xf50\x11+\x80\ ! q\xf4\xf2\xf4\xcb/X\xfd\xb3\x94E$\x8aC%s\x18\xca\xefY)\xe1<\xd82\x01\x98C\ ! \xf3\x96R)\x99\xf6\xa6\x12\xde(\xe8\x84\x10\xe1\\\xc6\xff/`\xde\xc9\xc9\xb3\ ! \x16\xd9\r\x97\x8f^\xd2@*\xca\x92\xaf\x85>/\x85\x0c\xed\xe0+\xee\x1b\x12\n\ ! \xcd\x07xGkK\x11\xa2\xd2\xd9\xb3\xd68\xba\xc8\xfd\xee\xeb\t\xfe;ewq\xa46 \ ! \x07/\x9f\xb9\x0b\x11c\x00\xdb\xe1\xe1j\xb5\xe2br:\x80\x87\xcb\x90\'\x19c\ ! \xf7\x1eZ4|\xf0\x06+#\xf1f{\x009\xc9\xef\xcd\x99\x83\xbe\x80phF\x97lP@\'$\ ! \x82\xbd\x99\xc3\xf2j&7\x12\xf7\x08Dg\xd2c\xc0\x90\x0eU\xc4\xb9\xb8\x96\x99>\ ! \xcf\x96|\x8a\x10\xff\x99\x89U\xfc\x0e\x8c\xe4\xbb!\xb99\x9e<;\xad\xa1\x7fM\ ! \xd0O\x87\xd96\x1b[S1\x1b\x1b[\x0b_\x89\x89hl\xf1\x8bG\xef\x90\xf1\xb3(\xbee\ ! a\xc2\xcbr\xeek\x05\xf2\x033R\xe6`\xe0p\x05\x98\x06\xb0g^0\x8b\xd35+\x8bp\ ! \xee\xeb7\xa3u\xbc\xf2\x19\xd8\xabu6\xf7\xf9\xb2L\xe3(J\x84?\x0e\x9eg\xcb2?\ ! \x05<\x00B\x0b\x9a\xd9H\x9f\x82\xdd\xa8\xbdY^\xc8\xa8\n\xd5\x0f\xc3\xbd\r\x12\x95\x19A <\xe3\xc8"\xac\xf8\xfa\x80\xf8\ ! \xbd\x14@ n\xca.\xb6j\x03F\xc4`\x07p\r\xd7G\xb3q\xee\n\xd4k\x84\n\xa7\xc6\ ! \xd3\xb25\x9a\ ! \x1f\x88*A\xf3\x0f\x98,\xf4\x068J\xf0\x1b\x0b\xaa\xa1\xad\n\x99\xb22,\xb8\ ! \x02{\x16k\xb4\xc0\xb6\xbe\xce\xa2\xbe\x0fB;\x12\xea\xbc&\x01\x1c@\xd1\x04\ ! \x18\xfe\xe5\xd6ZU\x18\x06\xd0z\x1f\xb2\xe6\x87,D>\xe1\xe6\x08\x8c\xf4\xaf\ ! \xdc\x08\xa1\x0e\x98\xc2\xbc\x11\xb4\x1d\xc7\x80\\i\xfc\x1bb\rF8[WH8XERE0\ ! \x88\x99\xb8k\xccm\x87I\x87d\xa5\xb5\x17,E\x8d\rr\x02}\x1ax\x9b-\x13\xbc\xdc\ ! v\x8d\xe7\x1b\x91\x80\xb5\xc4)\xda\xca\xf7\x1ck\xc3,\x98!\x01\x0f4\x9d81.\ ! \x06-yY\xef\x80\xa1@A\xc9\\n\x03\x057\xe2\xf3\x02\n\x8c\xa27h]\x1d\x9c\x9c@\ ! \xcc\x0c{V\x9at\xa4o\xc2*7\xfa\xf7Y(\x92\x04V\x86\x98\xf4\xf8\x8d\xcdRE0\x83\ ! (\xd4\x82\x83Q\xaf\xb3\xde\xbc\xf6Q{p\xeb\xb9\x7f\x0c1\x14m\xcd\xc8\xf0\xab\ ! \x08\xb4\x08\xe0\xf4 \xfa1\x08\xc2\x19\xec\xeb\xa3FPX\x08y\x94\xdf\x81\x8f\ ! \x01\xa8\xaf\x13\x10\x00=q\xc3@\xad~\x10eZ`\xbe\x8e7K\xc5UU\xeax\xd3,|1\xf1\ ! \xc1\x8da\xe4K\xdfm\xd0\xe9\xc4x\x88\xa7\xf3h\x88\x06\n:\xc1Z\x0b/g\x05\x85e\ ! \xe8$\x99\xc3x\xd0\x82\x0f\xb2T\xc31Wi#)\x90\x9e\x06\x0e(\x7f\t\xdb\x01\xf7@\ ! \x93P\x15\xacL\x9aP\xacY\x03\xda\xdc\x9e\xed\x88\xaeN\xad\xeea\xa2v\xde\xd9`\ ! \xac\x88&\x80\xdfJpuQ\x95\'\xe0\x1f\x910\x1b\x8b\x8c\xac\t\xb2\x07\x08\xbfPV\ ! \x0c\xcd&j_\x16\xe3n\xe0\xbb\x83\xe4\xea\x13j\x89\xad\x96M\xe4\xb9\x1e\\\xe0\ ! \xb3g\xf2\xc3\xb9\x07&\xd4\x15Q\xfbl\xf3txn\x0b\xd8`\xf8\xae!{\x0fe\x12\xf7\ ! \xdb\xb7\x90H\xc7Ik\xc6\xc5\xc7\x8b\x13F\x83\x18?ehI\x80G\xb3e\xd0Yz\x01\xbe\ ! \xbb\xbc"\xe3\xe9\x05GGG\x13\xc3\x8f\xd9x\x19\x1c\xb8\xc7\x0bs\xc9\x98\xc96\ ! \x10\x8ae\x8b\x1a\x82\xf1"\x90\xf8\xa7\x0e\xa0\x91\x83y\xc3y\xfcy\rBy+4\xb6\ ! \xa0\t\x08\x8aN\xb3\x9cv\xf4\xc5\xdd\x93\xd3\xa2+\x01Q)\xcc\xf4\x02\x17\xe7Q\ ! g\x83>dm\xadK\xbd\xfa\xb1m\x94T<\xd9m\x97V\xf6D1r\x8a\x07\xa2\xa5(^\xc5\xe8\ ! \xb6v\xdc5\xabR\xcc\x1a:\x1b2\xf8\x96\x1e<\xbe\xec]\x7f\xd5\xe6\xc9E?feU\x88\ ! \xce\xb2\x8a^v\x89\\ ?\x98\xd0\x94\x81\x13\xc3\xf4\xa9C\tb>\xed\xec\x81\x98\ ! \xb7\xe1\xb7\xd7\xbc\xeb/\xd9tW<\xc6n\xc7\x04\xa2\xf93\x91\xae)\xfd\xbc\x12\ ! \xf7\xbe1\x9a\xee\xef\xce\x1a\xd7\x8e\xbb\xdb\xd4\xa5\x00\x10\xa0U\xbc~\xcc4\ ! \xdb\n\x01\x96\x8d\xfc\xf1\xa0\xaaj UAb\xf8\x1e\x13xgZ\x1f\xc7\xfe\xef\x9f W\ ! \x08\xb1\xc0`\x00\t\xcc\x1e\x8a&\xc9\xecpi\x17\x90\xe5\xb6T"\x05\x0bo\x02\ ! \x95\x8e\xb0pSb\xd0;\xfa\xc1\x99K\x02EhXr\x18\xf5N\xc6\xe5\xaf\xe3DkK\xfc\ ! \xa4\xa5\xd5\x85\xac\x05\xc4\x9d\xed\xc0\x85\x18\xd9\x0cZ\x0e.Z5\x00m\xf6\ ! \xa8\xac\\\xd6\xf1\x8d\xa98\x82\xb3S\xa0\x86\xa24H[\x9e\x92<\xd3\xc4Zg!~\xe4\ ! %h.V\xb46\xb2l@\xe8\x955\xcf\x1a6i\xc4\xfc\xe0\x92>\xeb\xf9\xc8#bV\xed\x9bv\ ! \x8c\x94\x0c\xa1\xc8\xb4\xe1XIO \xae\xd6\x8e\x04K-\xe0PuM\xc3(+\xa6\xe7[C)xs\ ! \xb4\xe25\xc1\xa6\xbcPS\r\x0e\xfbl#\xc2\x1b"\x8d\xe7\xc0L\xc8"07]VJ\x01/V\ ! \x10X\x0b,\x01\x10\xf0\x83\xba\xae\x80\x85\xaf\x18\x96\xf9\x0b\x84\xecCF\x0f\ ! !&\x00\xf3\xdf\x8a\x95(|Hw\xf9\xad)\xef\x18\xc6\xe8\xa5\xe8\xe9\x0fL\xd9\xc0\ ! X\x15d9\xa6\xc3\x84\x0b\x01m"\n\xbd\xe8m\\\x86\xbc\x88\xd8\x98\x11t\xf8\x043\ ! \x02\xbfQ\x08\x98\xad\x7f\x02\xcc\x90(ibd\xbdZSR\xea\xe0\x83\xa3c\xa0\x01\x84\x02\x02\xb8\xef\xce\x17\x8e\xcd0%\ ! \x02J\x9b\xfcM\x1cE\x10\xee0,\xbd\xcd}\xe0\xa2\x046`\xd0g\xbe\xea\x84\xca\ ! \x9f\xb8\xf6\xe2\x11\x00\x19\x08\xbc^\xaf\xbf\r.\xd7\xf1\x88\t?`\xac\x15n\ ! \xd8\xe7~\xc4\xecD -\x0c\xcaj\x99\xc6\xcab\xb0\x96\x0e\xfeo\x88\x89\xfeP\xa1\ ! \x1b\x7f\x0cv\x17\xc8/YA"\xc7!\x1e\x8e\xe2\x12\xf1\x03\x10GN\x05\xb5\x15\xf6\ ! h\x93\xbc\x0b\x16\xa0r\xa0\xe0\x9b\xa70\xb84\xd3~\xf5~\xc8\xf5\xdd\x88\xfe\ ! \x01f~.\xc1\x0fY\xe8n\x84\xdf\x0fi1\xd9/\xd2V|\xdbX\x8a\xb0\x88sK\x16\xa6\ ! \xf1\xe3\xbf\xf1[\xae\xdf\xfa\xc1x<\xfb\xea\xe7\xb3\xb7\xaf\x17\xaf\x7f6)q\ ! \x95iM\x90\x99\xb6A{\xb8\x92\xdag\x90$/\xa4)\xa5|j\xf0\x89Wl/\x92a\x95B8?B\x7f\x05\x14t\xe2\x04\x06\xbf\ ! \xb4{ZZ$\x97\xc1`\x05\xa4]\xafq\xc4\xe5R\xde5u\x10\xdb\xa6\xf4\x87\x0f\xcb6<\ ! \xfd\xfe\xc9P\xbe[Q_\xc2\xf4\xde<\x9c\xed\x05}M\xbb\x14S\' \xc5\x06\x87.O\ ! \xb3B\x867_1\xf6\xf5\xe1~\xa7Y7\\\xc8\xc1\x1a\xe5\xb5\x17\\\xc6\xe1&\x16\xec\ ! ]\x9cE\xa0QX\xb8-\xe8\xcd\x1f\xc1PBp\x96a\xbe\xad\xcb\xb1\x83P@t\xdd6\xe3\ ! \xfb\xb8T\x04\xa4\xb4\xaf\xfe\x98Sev$\x8b\xf5\x03`Lz\x13b\xd5\xa6\xf0{u\xa8^\ ! \xe8R\xf0(\x96\xd6\x83\x1aM\xdcNI\t\xfft\xfe\xd3\xb0\x03ET#-\xcd\xb6\xda\xec\ ! \x9b\xe7\xday\xf6\x7f\xff\x16H\xa0\x1ax\x8d?\xa7\xe7\xff,\n\x98\x02\xbb!\x05\ ! <\xffg\x11\xa0\xb4\xddA\x00\x9f\xdb\x89m_H\x8ce\xf3\xf4\'\xd8I\xad3vW\xab4\ ! \xf5sp\x85=\xbb\x10\xe0S\x8e\xf4\xb8*/\x13\x9e\xdd\xa0&\x07M\xb8\xa4M\xef\ ! \xe3\x8f}H\x94e\xec\x00i\x07\r\xe8\xa4\xdc=\xee\xb7#I\x93\x19\x19\x8e\xea\ ! \xa7\xf1\xd3\xb6\xec\xe1h\xefs\x8a\x97U\x9eH\x1e\xf5\x13\x1b\xe4\x88\x1e\xf3\ ! j\xb7N\x1cj\xc9F\xcb\xc13\x01a"\xd1\x97V\x89\x8as^(\xc2\xea0\xe2\x8a[\xc3y\ ! \x1eSGC\x83f\xdc&}\x8eG\x95\xc5u\x8a\xfd\xa6\x00B\xba\x94\x8a\xeeD\r5P\xda-W\ ! \xbd\x19\xbe\xb7\xac\xd4\xdf\r\'\x81\x89\xceA|,\xa8+$(\x97\xbb\xdb\xc8\xa4N8\ ! !p\xcc@\xda\xa8\xafb\xdc\xf1>\xe5\x9fS\xb7 \x8ca2$\xcf\xdc\xec\xa4(\xd9*\xe4\ ! \x1d8\x87\x13\xdd/\x98\xfb\xd8^\x85s13\xdd\xdd\x9d&\xb1>\xfck\xadIC\xf2p\xb7\ ! \x01+\xde\x96\x07\x0cU\xae\\U\xeb\xc3\xdb|&\xb8w\x8fBk\x94\xf3i\x90gfn\x03\ ! \xce\nc]{\xd8\xc3R\x8c9s\x12\xaf5v\xb9+\xac\xa3`\xe4\xbe\x94\xd8EB\xcc\xa8\ ! \xb7\x95E6J\xa3\xe2\xf2\xa1S\x82\x8a3\xb7\xf6\xd0\xb4\x0fX!RyK\x972\xea\x9b\ ! \x01\xfb;WT\xee 1\xfes%\x8a\xed\xb0\x1e\xd4\xc3\x8d*\xe0\xab\xbf\xe3+\xbf\ ! \xcfB\x1c\xf3,\xa7\xe0{#\x90N\xc6\xe5\xebv\xaa\x7f2\xe9\x9eB\x9b\xe1\xf6\xd8\ ! \xfc\x05y5\xedM{\x9f!\x1ab\xf9\x93\xd4\xae ^0\xe1\xf00\xbd\xce\x04o\xb7\x98\ ! \xbe!\x1e\xd7z\xb56f\x8f\x13\x7f\xb4\x1b\xf1\xe7h[\xa9D\x14G\xb6\xfbdu\x17\ ! \xfb\xbe\xb8\xcd\xbf\xc2\x08\xe4\xe0\x95\xe2\xaa\x1c.\xa3\xd5\xc36\x94\xfb\ ! \xa1J\x97\x80\x08`\x80\xca[\x17\xf2:uj\x1c\x0be\x857\xa0\x8e\x8eO\x1eh\x0f4\ ! \xa06\x0fC\xda\xd4\x80^\xbc|\xf5\x00\xa0\x8bB.\xf92\x86Ds\xab\xabV\x8dI\r\ ! \xf5}\x07]\x8f4\x02\x83M=D\xd0\x1a\xd2.\xe2\xa0[K/\x98\x8c\xfe\xf0\xf57\x0fl\ ! \xf89\xce\xc5j\xf1\xa5(\xc1#<\xc0\xe6\xce$\xa7bIe\xbb\xbc!\x10\xd9c{T\xf6\ ! \x1d"Kl\xc6\x8c+\x0f\xfa\xc0!\x8ap\xba\xc6\xf8C\xc6Hg\xa1\xc0\x7f\x9a\xc1\ ! \xd6\xd2t\x17\x0fX\x12\xdf\x08\xcd\xb0%\xca4\x18KV\xf7@\xf7\xdd{wM\x93\x8f`,\ ! \xdczk3\xa9hfPp\xd1\x0f\xadl<\x8es<\xdb\xa9\xe8\xder\x05\xcfrn.5\xe19\xf6\ ! \xabE-PC\x0c\xea-p\x82\x89\xa1\x80\xc2m\xa6\xe4\xc1\xa5PU\x915E\xed\xf6\xf5B\ ! \xbcVa\xcf\x11\xec7\xddZ\x98\x0e\x9f\x87\x9e\xf4Z\xcf\xf1\xb4g\xb0\x1e\xc4\ ! \xf8\x06{\x16\xfb\xc3w\x11w\x11<\xeaH|\x0b\xd0\x1e\x90\xb9z\xbc\x16\xb7o?^~\ ! \xb0\xc6\xce\xa3[\x1aB\xe6 \x8e\xd6\xe0yh\xf0<\xd7\xa95\xe0b\xe7\x86\xa3\xa7\ ! \xef4ba\x1f+\xcc\x10 P\x8d\x9d\xaa\xce\x08\x94\xac\x17@6MG\xae\xec\r\x12\xbc\ ! \xa9f.\x04\xba=\x0bpp\xa5(uO\x87j\xeb#\x1b\x10a\x97\xa2\xa8Aq\xba\xcf%\x0b\ ! \xea\x9e\xf7\xb5\xdb7\xf3.\xb8\xda\xa0u\xf6\x83\xb1\xe9\xca\x8es\xf3\xaa\xa5\ ! \xf0O\xb0\xed\xac\xb9\xe4IS\x16\xaf\xdf\xbc?w\xe6\x0c7\xbc\x07\x1a\xdc\x8bKw\ ! \x15\xf8\x06P\x92\xa3V\xfdf\xf1\xd6\x04\xd9\x1e\xe9\x82\xe7VJ:\x02]#\x9a\xf0\ ! \xa5H\xbc\xe0=~\xd8\x1b\xb3\xfdK\x12\x8b\xb7\xed}\x1e\t\xd9\xcde\'}\x05\xea\ ! \xf8\x95g\x8e\x1d\xc6\x8d\xb3\xd399\xc4\xbc\xe95\x98\xdc\xeb\x14\x12\x9dv\ ! \x0c\xdf\xdd\x8c\x0ee#\x92\x1cN;lR\x87\x87\x0b\xbe\x0f\x02\x18\xb8u\x82q\xa9\ ! \xbd\xbe\xd2!\n\x82\xb1w\xb0\x88!A\x8d\xaa\xd9`i\x00_\xf8z9xZg\xcb\xcf9\xab\ ! \x87\xda\xa9\xff\x8e\x83\xb3\xdd\xd7#0\x93\xbbni\xaf0\xebC\x1c\xb2\xa5\xee\ ! \xf1S\x11\x95n\xc1\xd5k\xae\xe9\xd1\\\x7f\xa3\x8f\xddD\xa1O4,\xbe6\x84\xff\ ! \x85\xaa\xbf.\xf9\x83\xa9\xbc\xb9I\xf7\xbf,] [\xc7]\xd9r\x8e\xd6\xe0Cb\xd69\ ! \xe8\xb3\xaa(\xf0\xcfK\x88\x97\xd3\x01\xd2,\x98I\xdd\xb6?z9\xe9\x001|iL\x9f\ ! \x06J0\xc1k\xd1y\xef\xd7\x16\xf3ir\x8ci\xfb\xadH\xfa\x8dpw\xaa+0\xcd\x91\x95\ ! \x81\xb9+\x99\x80\xad\xef\xc48\x8drz\xc7/\x9fy\x8fY\xd8\xb6\x8aiho\x1eT1\x1a\ ! \xd6\x7f)\xf1\x90-q\xe7|K\xdf\x99\xe3\xe6\xba\x1aE\xa8\xec\xa6S\x8f\xa9\xc4\ ! \xd1d2\xf9\xf7j\xc5\x98|k?\x08\xd2\xd7-\xa9\xeeT\x03q\x121-v\xd7:\x95\xb2Wv\ ! \xed\x93f\xe2\x06\x0b\xe0\x86\xbbW\xfcVxM\x8c_\xc3\xb5/0\xc8\x0c\x0e\ ! \'d\'\x13v\xf4b:y1=9f\xc7\x93\xc9\xb19\x83Q\x0b\x07\xb3\xa7R\xf9t<\xbe\xbb\ ! \xbb\x1b\xd5\xad\x06\xec1\x8c\x1dD\xf0\xb9[\xfcm\xaa\xad\xc6D\xb6\xc9m\x1d\ ! \x16\xc5\x9f\xa8\xa7-c4Tc@\xbe\xd8U\xa6\x8fo\xca\x17 \x87\xfdB\xb8)I\xa0\xba\ ! \xb0\xe7\xc0\x81Sf\x17c\xb9Qck\x12\xab&\xa1r\x8a\x12 12\xda\xea?P\xd3\x7f\ ! \x14\xfcO\x14\x8d\xd5L' ) ### end --- 6,85 ---- import zlib ! data = zlib.decompress("xÚÝ;msÛÆÑß3“ÿpAdž4•HJ²Ý„\"1µe%ÎS;V%¦L&£9\002G\022\025€Cƒ$>žþ÷îîÝ\001‡\027I\ ! tÓ´3•=\"»ÛÛÝÛ÷=;zûñlñÓÅ9{·øðž]üøæý÷gÌ;\034ÿzr6\036¿]¼Õ\003/F“#¶(xVÆ\ ! *–\031OÆãó\037¼àË/f\033•&ô)x„Ÿ*V‰`q4÷è›\027\\å<]ò­(Ù¥(Ø÷™\022ÅŠ‡b6¦\011¸&\025Š³R\ ! ù¡ø{\025ßν‹‚¯Sî±PÂìLͽL\036†<Ü\010\007\027œéÁçŸßçq!JgÅbS\0350 òÿxÆŽ¾ùÄM&S\ ! úϾû°xtÛÃ3€QÈd`û\003–V¥:,Ä-Oâˆ+x\001C¥’…ŬT[âÁRF[ö‰­\000”}3yÆx\021ó䀕w\ ! qY\036°Hn…ŠC~ÊR^¬ãlÊ&ì\037_~¡ø\022¸½Ã:œ¼’E\012s[\000¾ü‚O“8»÷¡Ld1e¿›ÀOHƒ|z\ ! \033ËèѼ…\023mÆ^M^LV+\034\033\031V0n;¼\023ñz\0038.e\022ÑŒÛXÜÑν)\031àÉ\023ÝhɳŒ6Yòðf\ ! ]È*‹`§p\"`§S–ó(Š³õüeýõ0\021+€qôòôË/Xý³”E$ŠC%s\030ÊïY)á<Ø2\001˜Có–R)™ö¦\ ! \022Þ(è„\020á\\Æÿ/`ÞÉɳ\026Ù\015—^Ò@*Ê’¯…>/…\014íà+î\033\022\012Í\007xGkK\021¢ÒÙ³Ö8ºÈýîë\011þ\ ! ;ewq¤6 \007/Ÿ¹\013\021c\000Ûáájµâbr:€‡Ë'\031c÷\036Z4|ð\006+#ñf{\0009ÉïÍ™ƒ¾€phF—lP@'\ ! $‚½™Ãòj&7\022÷\010DgÒcÀ\016UŸ–™>Ï–|Š\020ÿ™‰Uü\016Œä»!¹9ž<;­¡MÐO‡Ù6\033[S1\033\ ! \033[\013_‰‰hlñ‹Gïñ³(¾eaÂËrîk\005ò\0033Ræ`àp\005˜\006°g^0‹Ó5+‹pîë7£u¼ò\031Ø«u6÷ù\ ! ²Lã(J„?\016žgË2?\005<\000B\013šÙHŸ‚ݨ½Y^Ȩ\012Õ\017ý\015\022•\031A <ãÈ\"¬øú€ø½\024@ nÊ.¶j\003FÄ`\007p\015×G³qî\012Ôk„\012\ ! §ÆÓ²5š\037ˆ*Aó\017˜,ô\0068Jð\033\013ª¡­\012™²2,¸\002{\026k´À¶¾Î¢¾\017B;\022ê¼&\001\034@Ñ\004\030\ ! þåÖZU\030\006Ðz\037²æ‡,D>áæ\010Œô¯Ü\010¡\016˜Â¼\021´\035Ç€\\iü\033b\015F8[WH8XERE0ˆ™¸kÌm‡I‡\ ! d¥µ\027,E\015r\002}\032x›-\023¼Üvç\033‘€µÄ)ÚÊ÷\034kÃ,˜!\001\017481.\006-yY@AÉ\\n\003\0057âó\ ! \002\012Œ¢7h]\035œœ@Ì\014{Všt¤oÂ*7ú÷Y(’\004V†˜ôøÍRE0ƒ(Ô‚ƒQ¯³Þ¼öQ{pë¹\0141\024mÍ\ ! Èð«\010´\010àô ú1\010Â\031ìë£FPX\010y”ß\001¨¯\023\020\000=qÃ@­~\020eZ`¾Ž7KÅUUêxÓ,|1ñÁaä\ ! KßmÐéÄxˆ§óhˆ\006\012:ÁZ\013/g\005…eè$™ÃxЂ\017²TÃ1Wi#)ž\006\016(\011Û\001÷@“P\025¬LšP¬Y\003\ ! Úܞ툮N­îa¢vÞÙ`¬ˆ&€ßJpuQ•'à\037‘0\033‹Œ¬\011²\007\010¿PV\014Í&j_\026ãnໃäê\023j‰­–M\ ! ä¹\036\\à³gòù\007&Ô\025Qûlótxn\013Ø`ø®!{\017e\022÷Û·HÇIkÆÅÇ‹\023Fƒ\030?ehI€G³eÐYz\001¾\ ! »¼\"ãé\005GGG\023ÃÙx\031\034¸Ç\013sɘÉ6\020Še‹\032‚ñ\"ø§\016 ‘ƒyÃyüy\015By+4¶ \011\010ŠN³œvôÅ\ ! Ý“Ó¢+\001Q)Ìô\002\027çQgƒ>dm­K½ú±m”T<Ùm—VöD1rŠ\007¢¥(^Åè¶vÜ5«RÌ\032:\0332ø–\036<¾\ ! ì]ÕæÉE?feUˆÎ²Š^v‰\\ ?˜Ð”\023Ãô©C\011b>í옷á·×¼ë/ÙtW<ÆnÇ\004¢ù3‘®)ý¼\ ! \022÷¾1šîïÎ\032׎»ÛÔ¥\000\020 U¼~Ì4Û\012\001–üñ ªj UAbø\036\023xgZ\037ÇþïŸ W\010±À`\000\011Ì\036Š&\ ! Éìpi\027å¶T\"\005\013o\002•Ž°pSbÐ;úÁ™K\002EhXr\030õNÆå¯ãDkKü¤¥Õ…¬\005ÄíÀ…\030Ù\014Z\016.Z\ ! 5\000mö¨¬\\Öñ©8‚³S †¢4H[ž’<ÓÄZg!~ä%h.V´6²l@è•5Ï\0326iÄüà’>ëùÈ#bVí›\ ! vŒ”\014¡È´áXIO ®ÖŽ\004K-àPuMÃ(+¦ç[C)xs´â5Á¦¼PS\015\016ûl#Â\033\"çÀLÈ\"07]VJ\001\ ! /V\020X\013,\001\020ðƒº®€…¯\030–ù\013„ìCF\017!&\000óߊ•(|Hwù­)ï\030Æè¥èé\017LÙÀX\025d9¦Ã„\013\001m\"\ ! \012½èm\\†¼ˆØ˜\021tø\0043\002¿Q\010˜­\002Ì(ibd½ZSRêàƒ£c \001„\002\002¸\ ! ïÎ\027ŽÍ0%\002J›üM\034E\020î0,½Í}à¢\0046`Ðg¾ê„ÊŸ¸öâ\021\000\031\010¼^¯¿\015.×ñˆ\011?`¬\025nØç~Äì\ ! D -\014Êj™ÆÊb°–\016þoˆ‰þP¡\033\014v\027È/YA\"Ç!\036Žâ\022ñ\003\020GN\005µ\025öh“¼\013\026 r à›§0¸4Ó\ ! ~õ~Èõ݈þ\001f~.Á\017Yèn„ß\017i1Ù/ÒV|ÛXŠ°ˆsK\026¦ñã¿ñ[®ßúÁx<ûêç³·¯\027¯6)q•\ ! iM™¶A{¸’Úg$/¤)¥|jð‰Wl/’a•B8?B\005\024tâ\004\006¿´{ZZ$—Á`\005¤]¯qÄåRÞ5u\020Û¦ô‡\017Ë6<ýþÉP\ ! ¾[Q_ÂôÞ<œí\005}M»\024S' Å\006‡.O³B†7_1öõá~§Y7\\ÈÁ\032åµ\027\\Æá&\026ì]œE QX¸-èÍ\037\ ! ÁPBp–a¾­Ë±ƒP@tÝ6ãû¸T\004¤´¯þ˜Sev$‹õ\003`Lz\023bÕ¦ð{u¨^èRð(–Öƒ\032MÜNI\011ÿt\ ! þÓ°\003ET#-ͶÚì›çÚyöÿ\026H \032x?§çÿ,\012˜\002»!\005<ÿg\021 ´ÝA\000ŸÛ‰m_HŒeóô'ØI­3\ ! vW«4õsp…=»\020àSŽô¸*/\023žÝ &\007M¸¤Mïã}H”eì\000i\007\015è¤Ü=î·#I“\031\031Žê§ñÓ¶ìáh\ ! ïsŠ—UžH\036õ\023\033äˆ\036ój·N\034jÉFËÁ3\001a\"Ñ—V‰Šs^(Âê0âŠ[Ãy\036SGCƒfÜ&}ŽG•ÅuŠý\ ! ¦\000Bº”ŠîD\0155PÚ-W½\031¾·¬Ôß\015'‰ÎA|,¨+$(—»ÛȤN8!pÌ@Ú¨¯bÜñ>åŸS· Œa2$\ ! ÏÜì¤(Ù*ä\0358‡\023Ý/˜ûØ^…s13ÝÝ&±>ük­ICòp·\001+Þ–\007\014U®\\UëÃÛ|&¸wBk”ói\ ! gfn\003Î\012c]{ØÃRŒ9s\022¯5v¹+¬£`ä¾”ØEB̨·•E6J£âò¡S‚Š3·öд\017X!RyK—2ê›\001\ ! û;WTî 1þs%Ší°\036ÔÃ*à«¿ã+¿ÏB\034ó,§à{#NÆåëvª2éžB›áöØ ü\005y5íM{Ÿ!\032\ ! bù“Ô® ^0áð0½Î\004o·˜¾!\036×zµ6f\023´\033ñçh[©D\024G¶ûdu\027û¾¸Í¿Â\010äà•âª\034.£ÕÃ\ ! 6”û¡J—€\010`€Ê[\027ò:uj\034\013e…7 ŽŽO\036h\0174 6\017CÚÔ€^¼|õ\000 ‹B.ù2†Ds««VI\015õ}\007\ ! ]4\002ƒM=DÐ\032Ò.â [K/˜Œþðõ7\017lø9ÎÅjñ¥(Á#<ÀæÎ$§bIe»¼!\020Ùc{Tö\035\"KlÆŒ+\ ! \017úÀ!ŠpºÆøCÆHg¡ÀšÁÖÒt\027\017X\022ß\010Í°%Ê4\030KV÷@÷Ý{wM“`,Üzk3©hfPpÑ\017­l<\ ! Žs<Û©èÞr\005Ïrn.5á9ö«E-PC\014ê-p‚‰¡€Âm¦äÁ¥PU‘5EíöõB¼VaÏ\021ì7ÝZ˜\016Ÿ‡žô\ ! ZÏñ´g°\036Äø\006{\026ûÃw\021w\021<êH|\013Ð\036¹z¼\026·o?^~°ÆΣ[\032Bæ ŽÖàyhð<ש5àb熣§\ ! ï4ba\037+Ì\020 PªÎ\010”¬\027@6MG®ì\015\022¼©f.\004º=\013pp¥(uO‡jë#\033\020a—¢¨AqºÏ%\013êž÷µ\ ! Û7ó.¸Ú uöƒ±éÊŽsóª¥ðO°í¬¹äIS\026¯ß¼?wæ\0147¼\007\032Ü‹Kw\025ø\006P’£VýfñÖ\004Ù\036é‚ç\ ! VJ:\002]#šð¥H¼à=~Ø\033³ýK\022‹·í}\036\011ÙÍe'}\005êø•gŽ\035ƳÓ99ļé5˜Üë\024\022v\014ßÝŒ\016\ ! e#’\034N;lR‡‡\013¾\017\002\030¸u‚q©½¾Ò!\012‚±w°ˆ!AªÙ`i\000_øz9xZgËÏ9«‡Ú©ÿŽƒ³Ý×#0\ ! “»ni¯0ëC\034²¥îñS\021•nÁÕk®éÑ\\£ÝD¡O4,¾6„ÿ…ª¿.ùƒ©¼¹I÷¿,] [Ç]ÙrŽÖà\ ! CbÖ9質(ðÏKˆ—Ó\001Ò,˜Iݶ?z9é\0001|iLŸ\006J0ÁkÑyï×\026óirŒiû­Húpwª+0Í‘•\ ! ¹+™€­ïÄ8rzÇ/ŸyYضŠiho\036T1\032Ö)ñ-qç|Kß™ãæº\032E¨ì¦S©ÄÑd2ù÷jŘ|\ ! k?\010Ò×-©îT\003q\0221-v×:•²Wví“fâ\006\013à†»WüVxMŒ_õ/0È\014\ ! \016'd'\023vôb:y1=9fǓɱ9ƒQ\013\007³§Rùt<¾»»\033Õ­\006ì1Œ\035Dð¹[ümª­ÆD¶Ém\035\026ÅŸ¨§-\ ! c4Tc@¾ØU¦oÊ\027 ‡ýB¸)I º°çÀSf\027c¹Qck\022«&¡rŠ\022 12Úê?PÓ\024üO\024ÕL") ### end Index: ui_psp.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/spambayes/resources/ui_psp.py,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** ui_psp.py 29 Jan 2003 03:23:35 -0000 1.2 --- ui_psp.py 13 Jul 2003 16:12:28 -0000 1.3 *************** *** 1,364 **** """Resource ui_psp (from file ui.psp)""" # written by resourcepackage: (1, 0, 0) source = 'ui.psp' package = 'spambayes.resources' ! data = 'Paint Shop Pro Image File\n\x1a\x00\x00\x00\x00\x00\x05\x00\x00\x00~BK\x00\ ! \x00\x00.\x00\x00\x00.\x00\x00\x00\x90\x01\x00\x00F\x00\x00\x00\x7fj\xbct\ ! \x93X<@\x02\x02\x00\x18\x00\x01\x00\x00\x00\x00\x01\x00@\x90\x02\x00\x00\x00\ ! \x00\x00\x02\x00\x03\x00\x00\x05~BK\x00\n\x00\x18\x00\x00\x00~FL\x00\x01\x00\ ! \x0e\x00\x00\x00\xc0\xc0\xc0\x00\n\x00\x00\x00\n\x00\x00\x00\x00\x00~BK\x00\ ! \x01\x008\x00\x00\x00~FL\x00\x01\x00\x04\x00\x00\x00\xd4\xc3\'>~FL\x00\x02\ ! \x00\x04\x00\x00\x00u\xe0\'>~FL\x00\x06\x00\x04\x00\x00\x00\x01\x00\x00\x00~\ ! FL\x00\x07\x00\x04\x00\x00\x00\x04\x04\x00\x07~BK\x00\x10\x00\xcb\x1a\x00\ ! \x00\x08\x00\x00\x00\x02\x00\x00\x00~BK\x00\x11\x00\x18\x00\x00\x00\x18\x00\ ! \x00\x00\xc8\x00\x00\x00#\x00\x00\x00\x18\x00\x03\x00\x01\x00\x00\x00\x00\ ! \x01\x01\x00~BK\x00\x11\x00\x18\x00\x00\x00\x18\x00\x00\x00\x90\x01\x00\x00F\ ! \x00\x00\x00\x18\x00\x03\x00\x01\x00\x00\x00\x00\x01\x00\x00~BK\x00\x12\x00\ ! \x8d\n\x00\x00\x0e\x00\x00\x00\x7f\n\x00\x000R\x00\x00\x05\x00\xff\xd8\xff\ ! \xe0\x00\x10JFIF\x00\x01\x01\x00\x01,\x01,\x00\x00\xff\xdb\x00C\x00\x02\x01\ ! \x01\x01\x01\x01\x02\x01\x01\x01\x02\x02\x02\x02\x02\x04\x03\x02\x02\x02\x02\ ! \x05\x04\x04\x03\x04\x06\x05\x06\x06\x06\x05\x06\x06\x06\x07\t\x08\x06\x07\t\ ! \x07\x06\x06\x08\x0b\x08\t\n\n\n\n\n\x06\x08\x0b\x0c\x0b\n\x0c\t\n\n\n\xff\ ! \xdb\x00C\x01\x02\x02\x02\x02\x02\x02\x05\x03\x03\x05\n\x07\x06\x07\n\n\n\n\ ! \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\ ! \n\n\n\n\n\n\n\n\xff\xc0\x00\x11\x08\x00#\x00\xc8\x03\x01"\x00\x02\x11\x01\ ! \x03\x11\x01\xff\xc4\x00\x1c\x00\x01\x00\x02\x02\x03\x01\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x07\x08\x05\x06\x02\x04\t\x03\xff\xc4\x003\x10\x00\ ! \x01\x03\x03\x03\x03\x03\x02\x05\x02\x07\x00\x00\x00\x00\x00\x01\x02\x03\x04\ ! \x00\x05\x06\x07\x11\x12\x08\x13!\x14"1\x15A\x16#23B\t\x17QRWr\x81\x95\xd2\ ! \xff\xc4\x00\x1a\x01\x01\x00\x03\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x02\x04\x05\x01\x06\x03\xff\xc4\x00*\x11\x00\x02\x01\x04\x02\ ! \x01\x03\x03\x04\x03\x00\x00\x00\x00\x00\x00\x01\x02\x11\x00\x03\x04!\x05\ ! \x121\x06AQ"Ba\x132q\x81\x14\x15b\xff\xda\x00\x0c\x03\x01\x00\x02\x11\x03\ ! \x11\x00?\x00\xf7\xf2\x94\xaf::\xe3\xea\xc3\xad>\x84\xfa\xb2\xcd.\xf8\x8e3\ ! \xf5|7Sb\xc3\x18jf\xb6\xb9\x0cD\xb9\xb7\x024e-\xa0\x9f\x87\x82\xda$\xb0|8\n\ ! \x15\xb7\xcdz_Kzc3\xd5\xbc\x83\xe0\xe2\\E\xba\x10\xb2\x87=C\x90\xca\n\x83\ ! \xf2\x14\x97\xfe\x14\xd7\x9d\xf5/\xa8\xf1}-\x82\xb9\x99H\xcdl\xb0V*\'\xa8!\ ! \x88b>\x0b\x00\xbf\xcb\n\xbb\x97n\xa3\xb4\xb6\xd7\xafv\x9e\x9a\x9b\xbe\tYm\ ! \xd2\xda\xfd\xc1v\xf8\xdb+\xd1Fm<\xbb\x8f\x1d\xfd\x85d\x80\x94\xfc\x91\xb9\ ! \xd8\x0f\'{\xaae\xfd3z\x00\xcet\x9e\xfb3\xab\x9e\xa8/s\xae\x1a\x9d\x942\xe2\ ! \xccYrJ\x95mi\xed\x8a\xfb\xc7\x7f{\xeb\x00\x02?Ki\xf6\x81\xbe\xfb\\\xda\x8f\ ! \xaa08^+\x93\x18|m\xff\x00\xd6\x16\xd4\x07\xb9\xf6\xb5\xc9=\xba\x7f\xc0\xd0\ ! \x07\xde\t\xd83R\xf4\xd6w/\xc9\xf1\xc7+\x90\xb3\xfa%\xd8\x94O\xb9m\xc0\xeb\ ! \xdf\xfe\xce\xc9\x1e\xd3\x1a\x88\xa5)Us\xab\x1c\xd2\xe7\x8d\xeau\xd9Z\xee\ ! \xd2\x93\x83\xc7\xb3Es\x06\x87!\xe7Z\xb1\xdd\xa6s&kW7\x1a#y\x1cF\xd1\xe3\xba\ ! {\x0b\x1e@q\xcfjip\xdcS\xf3\x19\x9f\xa0\x8d\x06\'\xc4\xb1\xd8\x10\xab"N\xe4\ ! \xecB\x86b`U\xde[\x93N\'\x17\xf5\x99dLy\x804L\xb1\x83\x03P4e\x88P$\xd5\xa3\ ! \xa5yE\xd2\x1eC\x84O\xce3\xfc\x9a\xdb\x118L\xf9HS\xfayi\xd3+\xd4y\xf7t\\\n\ ! \x90[\x88\x96\xa2\x1e\xdc\xc6RK\x89)}\x1cKg\x94\x82\x9d\x9br\xbd?\xd2\xc9\ ! \x1a\x87/Ml2uj\x04\x18\xb9C\x96\x88\xea\xc8#\xdb\x1c+\x8e\xdc\xc2\xd8\xee\ ! \xa5\xb2\x7f\x88V\xff\x00r?\xc0\x91\xe4\xeez\xbb\xd2\x0f\xe9[\xe2\xd9\xbd\ ! \xdf\xc0\xd8\nd\xa8mC8`\'\xa9!\x8c6\xbd\xc18\xbe\x96\xf5R\xfa\x9a\xc9qk\xa7\ ! \x9f\x04\xb0\x80\xc5w*\xa5I\x89\x00\xae\xd7~\xc63\x8e\xba\xd4v\x94\xfb\xee\ ! \xa5\x08BJ\x96\xb5\xab`\x90>I?aQ\xdc\x1e\xa84\xde\xe3s\xb71\x19\x8b\x81\xb7]\ ! \xe4\xa9\x8bm\xf0\xa1\x91\x19\xe5%a\xb2\xae=\xce\xf2Q\xdc!\x1c\x94\xd8\x1f\ ! \xcb~\x1e\xfa\xde\xb2\x1b\x1c,\x9a\xc1;\x1b\xb9s\xf4\xd7\x08n\xc6\x91\xdbV\ ! \xca\xe0\xe2\n\x15\xb1\xfb\x1d\x89\xf3T\xf3Dt\xe7(\xb2\xea\xbd\xcb\xa0\xbdGM\ ! \xa1\xe9V\xebKY:\xb3\x08\xd2^\xf5\x17\x9bK\x92\x18am\xfau#\x8b.)\xc8q\xf9\ ! \xa9.\x04\xa1IN\xc1\xc1\xcbz|\x0f\x17\xc7\xf2\x18\xb9\x17/\xb1\x9b`1\x03\xc8\ ! M\x86q\xf2T\xf5\xd6\xf4|\x1d\x95\xb5\xcd\xf2Y\xf896-\xd9Q\x17\t\x00\x9fw\xd1\ ! T?\x01\x87m\xfc\x8f#A\xae})Q\xe7V7\xbb\xce9\xd3fkz\xb0\xdc\x9f\x84\xfb\x16\ ! \x07\xf9\xcf\x8c\xad\x9c\x86\xc9\x1c^\x90\x83\xfcT\xdbEn\x03\xf6(\xdf\xedXXx\ ! \xcd\x99\x99o\x1dL\x17`\xb3\xf1&+o/!q1n_"B)h\xfe\x04\xd7C \xea\xf7I\xed\x17\ ! \x95\xd9\xac\xb0r\x1c\x87\xb3=P^\x99\x8e\xe3\xef\xca\x8a%$\x90\xb8\xe8x\x00\ ! \x87\xddI\x04)\xb6K\x8bI\x04\x10\x08\xda\xb7]<\xd4\xac\'Uq\xff\x00\xc4\xd8%\ ! \xf13c!\xf5\xc7\x90\x85\xb2\xb6^\x8a\xfa6\xe6\xcb\xcc\xba\x94\xb8\xc3\xa9\ ! \xdcn\xdb\x89J\x86\xe3q\xe4U[\xeb\xfb\x15\xd1,S.\xe9\xaf\r\x99\xa4q.0\x13\ ! \xa90l\xd8\xea#]\x1f\x88\xdd\xad\x97\x1c\x8c\x8eHK$\x07@\xe0\xd9\xd9_\xe4\ ! \x1e|\xaby\xbb\xd3\xc4\xb1u\x9c\xcbx\xe2R\xdf\xe2\x1d:\x97+*m\xaf\x01OD\x9b\ ! \r\xab{\xcb\x03\xf9\xa9\xb9\x13\x90\x15\xf2\xa4\xb0\x06\xe46\x00\xf5Y\xbc/\ ! \x15\xfe\xa2\xc6F8\xb8\xadqn8,W\xac[b\x081\xbd\x80H\xd2\xc3BC\xcfq\xe6p\xf9~\ ! K\xfd\xa5\xfb\x17\xca2\xdbkjB\x86\x99\xb8\xa0\x83\xbdh\x90\x0e\xdaVZV:\x99N\ ! \xb5\x9f\xefN\x8e\x7f\xab8\xcf\xfd\xf4\x7f\xfd\xd6\xcdPGM\xda\xa4\xee\x9e\ ! \xf4\x8b\xa3\xb1N\x99\xe5w\xb4I\xd2\xeb\x12\xd3\'\x1e\xb5\xa6R\x10D\x06\x01B\ ! \xc0p)\x07\xc8>F\xc4\x1f\x04\x90\xa00pp\x17+\x19\xeeAb\x19T\x00@\x9e\xc1\xc9\ ! 2A\xf1\xd3\xc7\xe7\xf1[y\xb9\xc7\x1b!-\xc8\x00\xab1$\x13\xfbJ\x00 \x11\xe7\ ! \xb7\x9f\xc5Jlk\x1e\x91Iy\x11\xa3j\xa66\xe3\x8e(%\xb6\xd1|\x8eT\xa5\x13\xb0\ ! \x00\x05\xf95\xb2UC\xea[A\xb1=RE\xdb\xacWo\x1a\x9da\xba\xdaS\x1e\x03x\x95\ ! \xeaCqm\xaf\xa7v\xd9\xee\xaa/\x05)C\x8b\xe4\x85w\x07\xe66\x0e\xde\xdd\x8d\ ! \xbc\xab\x1c\xbf\x1b\x83\x85\x8bb\xee=\xc2\xc5\xbb\x07\x04~\xc7P\xa4\xa8?p\ ! \x86\x1b\xd0\xaa\xfcW!\x9b\x99\x93z\xdd\xf4\n\x17\xa9B\x0f\xeeV,\x03\x11\xf6\ ! \xfe\xd3\xaa\xd5\xf5\x1bR\x9b\xd3\xb96\xa36\xd3\xdc\x87:J\x916r\xdf(DF\xd2\ ! \x01R\xfc%\\\x88I.\x10x\x80\xd3/,\xab\xf2\xf8\xabgJ\x92\xa4\x85%@\x827\x04\ ! \x1f\x9a\xae}Tj\xbeI\xa2z\xafo\xcc\xee\xc8y\xcb\xbf\xe3\xa0m\x8d\x19\x96\x92A\x0b\xe0H\xd7\x92tI\x00\xc1\xab\x1dJR\ ! \xb0\xebj\x94\xa5)JWV\xe9c\xb2_=?\xd6\xac\xf1fz9H\x93\x13\xd5GK\x9d\x87\xd1\ ! \xbf\x17Q\xc8\x1e+\x1b\x9d\x94<\x8d\xce\xc6\xbbT\xae\xab2\x99S\x06\xb8\xca\ ! \xac \x89\x14\xa5)\\\xae\xd2\xb8H\x8f\x1e[\x0b\x8b)\x84:\xd3\x89)q\xb7\x12\ ! \x14\x95\x03\xf2\x08?"\xb9\xd2\x80\x90i\xe6\xb1\xb6\x0c3\x0f\xc5\x14\xea\xf1\ ! |R\xdbm/~\xf1\x81\x05\xb6{\x9f\xee\xe0\x06\xff\x00\xf3Y*R\xa4\xee\xf7\x1b\ ! \xb3\x99?\x9a\x8a"[^\xaa ~)Q\xb5\xdb\xa7v.\x1dW\xd9\xfa\xa6\x89\x96.<\x8bv\ ! \x15\'\x1c\x97h\x10\x82\x84\xc6\\\x90\x99\x08Yw\x98\xe1\xc1a^\xde\'}\xc7\x91\ ! \xb7\x99&\x95c\x173\'\t\x9c\xd9h\xec\xac\xa7@\xca\xb0\x827>G\xbf\x91\xe4A\ ! \xaf\x86N&>b\xa8\xbc\xb3\xd5\x83\x0f"\x19L\x83\xaf\x83\xfd\x1f\x07T\xaf\x94\ ! \xd8P\xeeP\xdd\xb7\\b6\xfcy\r)\xb7\xd8y\x01Hq\n\x1b)*\x07\xc1\x04\x12\x08?5\ ! \xf5\xa5V\x04\x83"\xac\x10\x08\x83U\xb7S\xfa\x04\xbe\xe6\x17<1\xacW[\xd1\x16\ ! \xcb\xa7\xf9\x137\x9cB\xd5\x92c\xce\\\x97jy\xa5%M\xb2\xd3\xedL\x8c\xa5\xb2\ ! \x8e\t\tC\xe1\xe2\x90\x02y\x14\x80\x04\xc7\xa5\x9aC\x0bM\xdd\xb9_\xeeY\x1c\ ! \xec\x83#\xbe-\xb5\xdf2+\xa0@zHl(4\xca\x10\xdaR\x86Xl)|\x1a@\x00sZ\x8f%\xadk\ ! V\xdfJ\xd9\xcc\xf5\x0f/\x9f\x88\xb8\xd7\xeeJ,\xeb\xaa\x83\xb3\xd8\xc9\x00\ ! \x13-\xf5\x19&[\xea2wY8\x9c\x0f\x15\x83\x94\xd9\x16m\xc3\x98\xfb\x98\x8d\x0e\ ! \xa2\x01$\x08_\xa4@\x10\xbfH\xd6\xa9QV\x07\xa0\x19\x96\x1f\xa3\x98\xb6\x8b\ ! \xde2\xbc>\xfdo\xc5lPm\xb1\\\xbb\xe0\xae;\xdd\xf4\xd1\xd2\xc2^(T\xe2\x94\xac\ ! \xa5\'\xe3\xe3\x91\x15*\xd2\xa8c\xe7d\xe2\xdbd\xb4@\x04\x82t\x0e\xd4\x10\x0e\ ! \xc1"\x03\x1f\x1f;\xf6\xab\xb9\x18X\xd97\x03\xdc\x12@#\xc9\x1a0H\xd1\x13=G\ ! \x9f\x8f\xe6\xa2\xcc\xbf@r\xcc\x9fN\xe7\xe9\x95\xbb\'\xc4\xac\x96\xdb\x8b\ ! \xed;)6l\x1d\xc6\tR\x1dmd\x80&\xf1\xe4CiO"\x0f\x8d\xbev\xda\xa5:R\x99\x19\ ! \xd99H\x12\xe9\x90\t>\x00\xdb@\'@L\xf5\x1e~)\x8f\x85\x8d\x8a\xe5\xed\x88$\ ! \x01\xe4\x9d\t l\x98\x8e\xc7\xc7\xcd)JUJ\xb5J\xc3\xdd\xf0lz\xf9\x96\xd9\xf3k\ ! \x84w\x15>\xc6\x1f\xfaz\xd0\xf1JGy\x1c\x16T\x07\xeb\xf6\xee\x00;\x81\xc8\x9d\ ! \xb7\xf3Y\x8aT\xed\xdc\xb9i\xa5\x0c\x18#_\x04A\x1f\xd8$\x1a\x83\xdbK\x82\x1c\ ! H\x90\x7f\xb0d\x1f\xe8\x89\x14\xa5)P\xa9\xd2\x94\xa5)JR\x94\xa5)JR\x94\xa5)J\ ! R\x94\xa5)JR\x94\xa5)JR\x94\xa5)JR\x94\xa5)JR\x94\xa5)JR\x94\xa5)JR\x94\xa5)\ ! JR\x94\xa5\x7f\xff\xd9~BK\x00\x12\x00\xde\x0f\x00\x00\x0e\x00\x00\x00\xd0\ ! \x0f\x00\x00HH\x01\x00\x08\x00\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x00\ ! \x01,\x01,\x00\x00\xff\xdb\x00C\x00\x05\x03\x04\x04\x04\x03\x05\x04\x04\x04\ ! \x05\x05\x05\x06\x07\x0c\x08\x07\x07\x07\x07\x0f\x0b\x0b\t\x0c\x11\x0f\x12\ ! \x12\x11\x0f\x11\x11\x13\x16\x1c\x17\x13\x14\x1a\x15\x11\x11\x18!\x18\x1a\ ! \x1d\x1d\x1f\x1f\x1f\x13\x17"$"\x1e$\x1c\x1e\x1f\x1e\xff\xdb\x00C\x01\x05\ ! \x05\x05\x07\x06\x07\x0e\x08\x08\x0e\x1e\x14\x11\x14\x1e\x1e\x1e\x1e\x1e\x1e\ ! \x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\ ! \x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\ ! \x1e\x1e\x1e\x1e\x1e\x1e\xff\xc0\x00\x11\x08\x00F\x01\x90\x03\x01"\x00\x02\ ! \x11\x01\x03\x11\x01\xff\xc4\x00\x1c\x00\x01\x00\x03\x00\x03\x01\x01\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x05\x06\x07\x01\x03\x08\x02\x04\xff\xc4\x00\ ! F\x10\x00\x01\x04\x02\x01\x02\x03\x05\x03\x06\x08\x0f\x01\x00\x00\x00\x01\ ! \x00\x02\x03\x04\x05\x11\x06\x12!\x07\x131\x14\x15"AQ\x162a#Bq\x81\x91\xc1\ ! \x083CV\x95\xa1\xb2\xd2\x17$&78FRbfuv\x84\xa5\xb1\xb4\xc2\xff\xc4\x00\x1b\ ! \x01\x01\x00\x03\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\ ! \x05\x06\x03\x02\x01\x07\xff\xc4\x001\x11\x00\x02\x01\x02\x04\x04\x04\x06\ ! \x02\x02\x03\x00\x00\x00\x00\x00\x00\x01\x02\x03\x11\x04!1Q\x05\x12Aa\x13"q\ ! \xa12R\x81\x91\xb1\xf0\x14B\x06\xc1\xd1\xe1\xe2\xff\xda\x00\x0c\x03\x01\x00\ ! \x02\x11\x03\x11\x00?\x00\xf6Z" \x08\x88\x80"\x80\xe7|\xb3\x15\xc3\xb0o\xc9\ ! \xe4\xe4\xd9;l\x104\xfcs?\xfd\x96\xfe\xf3\xf2U\xff\x00\x03y>O\x97q\xdc\xa6c(\ ! \xf6\xf9\x8e\xca\xc8\xc8\xa3o\xdd\x8a1\x14D0~\x03g\xf4\x92J\x9b\x1c\x05ia\ ! \xa5\x8a\xb5\xa0\x9aW\xdd\xf6"K\x1dF8\x85\x86\xbf\x9d\xab\xdbe\xdc\xbf\xa2"\ ! \x84K\x08\x88\x80""\x00\x88\x88\x02" \x08\x8b\xe2yc\x82\t\'\x99\xed\x8e8\xda\ ! ^\xf78\xe84\x01\xb2J%p\xf2>\xd1R(\xe7\xf2\x1c\xa4\xcd6.\xf4\x98\x9ct\x10\xb6\ ! ^\xb8\xe1l\x96g\xea`\x90t\x875\xc1\xa0F\xf8\xdc~\x07\x1d\xc8\x07mw\xe3\x8d\ ! \xf2[q\xe4\xebR\xc8^fB\xa5\xc0\xd3Z\xdf\xc1\xd5\xf1o\xa0\x971\xadk\xda\xe2\ ! \xd77}--p\x00\x83\xd4\xd2\xa7\xcb\x87U\x8aw\xb5\xd6\xab;\xfe-\xa7\x7fr\x12\ ! \xc7\xd2mZ\xf6z>\x9f\xf3\xed\xec^\x11\x11@&\x84D@\x11Rs\x9c\xeagf\xa6\xc0q\ ! \x1c4\x99\xfc\x9c\x07V\\\xd9\x04u\xaa\x9f\xa3\xe4=\xba\xbf\xdd\x1fB=F\x94T\\\ ! \x83\xc4\x87d_N98\x05\xabq\xec\xbf\x1d\r\xe9}\xa9\xa0z\x82\t\xd0\xfd\x8a\xc6\ ! \x1c.\xbc\xa3\xcd&\xa3\x95\xf3i;on\x8b\xbb\xb2+\xe7\xc4\xa8\xc6V\x8d\xe5\xd3\ ! $\xda\xbe\xd7\xea\xfb+\x9aZ*\x8f\x14\xe6\xd1d\xf2\xae\xc0\xe6\xb1\x960Y\xd6\ ! \xb7\xaf\xd8\xec89\xb34z\xba\'\x8e\xcf\x1f\xa3\xf1\xf5\xd1V\xe5\x12\xbe\x1e\ ! \xa5\trTV\x7f\x9e\xe9\xe8\xd7tJ\xa3^\x9dx\xf3Sw_\xb95\xaa}\x98DE\xc4\xec\x11\ ! @\xfd\xb5\xe1\xbf\xce\xdc\x0f\xf4\x8c_\xdeO\xb6\xbc7\xf9\xdb\x81\xfe\x91\x8b\ ! \xfb\xcaG\xf11\x1f#\xfb3\x87\xf2\xa8|\xeb\xee\x89\xe4P?mxo\xf3\xb7\x03\xfd#\ ! \x17\xf7\x97en]\xc5,\xd8\x8e\xb5nO\x84\x9ai^\x19\x1cq\xdf\x89\xce{\x89\xd0\ ! \x00\x07l\x92{i\x1e\x12\xba\xcd\xc1\xfd\x98X\xaa/%5\xf7D\xd2"(\xe7p\x88\xa8\ ! \x14%~\x1b\x90\xe43W\x04\xb2yv\xacW\xcaH^O\x95\x13\xde\xd9*\xca\x01\xfeM\x91\ ! \xfc\'^\x84\xb8\xfc\x9c\xa4P\xc3\xf8\xcaVy\xaf\x7f\xdd=Z]H\xf5\xeb\xf8M]d\ ! \xfd\xbfu\xf4M\xf4/\xe8\xb8k\x9a\xe6\x874\x874\x8d\x82\x0e\xc1\x0b\x95\x1c\ ! \x90\x11\x11\x00EX\xces\\n2\xd8\xab\x15<\x8eNO\xec\xa3\xf3\xae5\xc6x\xcf5\ ! \x8b\x1c\xc7d\xa2e\xa0\xd9\xea_\x92\xe0\x92\xbb\x9a\xe2t\x1c\xd6\xb5\xaf\r\ ! \x04h\xb8<\x9d\r\xe8\xfa-\x02\x99\xe6\x975\xc3\xd3\xe5\xbd\x1f\x967[\x1d\xc7\x85\xd8\ ! \x05\x8eP\xdb\xb4"\x90\x98\xa8\xf4I\x1c\xc7g\xbbIp\xf2X\x0e\x86\xdc\x1e\xef\ ! \xa8\x07\xd1l\xb4\xf9._7\x81o\x17\xe0p\xc9r\xd4\xee\x95\xd9\x0c\xdb\xa3tuk\ ! \xbeW\xbaILe\xc3n=Ov\xbboZ#\x7f-G\x14\xa7QS\xa5\x07\xe7K\xe2sMF\xdb\xe7\x9a~\ ! \x8f_\x87\xaa3|6t\xddJ\x92^G\xfdTZn\xfbe\x93^\xbd>.\x8c\xd3\xb8\xbes\x1f\xc9\ ! 0u\xb3\x18\xb9|\xca\xd6\x1b\xb1\xbe\xcei\xf4-p\xf9\x10{)5\x05\xc0\xf8\xbd\ ! \x1e!\xc6\xab\xe1h\x12\xf0\xcd\xbeY\\4e\x90\xfd\xe7\x1f\xd8\x00\x1f \x00S\ ! \xab\xf3\xccJ\xa4\xabIQw\x8d\xdd\xaf\xad\xba\x1b\xdc;\xaa\xe9E\xd5^kgm\xc2\ ! \x8c\xe5\x94\xa6\xc9q\\\xbe:\xb1\xd4\xf6\xa8\xcd\x04gz\xf8\x9c\xc2\xd1\xfdeI\ ! \xa2\xe7Nn\x12RZ\xa3\xa4\xe0\xa7\x17\x17\xd4\xc3|\x1c\xc9A.W\x16\xeb6\xd9J\ ! \xcdV:\xac\xf0\xcczIx\x828]\x11\xdf\xa3\xb5Z\xbb\xc0>\xbf\x94\x03\xbb\n\xb4\ ! \xe5\xf1\x91\xb3\x97bp\xb8\xfe\xe6\x19\x9da\xc0k`>\xecv\xe4q\x1f\x9a\xc6\xf9\ ! A\x80\x9e\xc4\xca\x00\xde\x8e\xa2\xbf\x84_\x17\xc63\x89[\xe4\xf4j\xb6\xaeI\ ! \x92\xc6,\xd8\x84\x96\x19cq\xe9\xd3\x80:wr\xde\xe4o\xb2\xb7x6\xdcd\x9e\x1d\ ! \xe2nc(W\xa8\xd9\xe0\x02A\x14a\xa5\xcea,%\xc4\x0f\x88\xec\x1e\xe7\xb9Z\x9cex\ ! J\x82\xe2\x14\xaff\xf9yz)Y\xbdz\xac\xdd\xb2\xfb\x19\x9c%\t\xc6\xb3\xc0T\xb5\ ! \xd2\xe6\xe6\xea\xd5\xd2\xd3\xa6\x8a\xf9\xfd\xcb\x82",\x99\xa8\n\xa5\xe2\xce\ ! f\xee\x1f\x87H1\x8e\xe8\xc9_\x9e:\x14\xdd\xbdt\xc9)\xd6\xff\x00H\x1dD~ +j\ ! \xa1x\xde\x1d\x07\x1d\xc4\xe6zK\xa1\xc3\xe6\xea_\x9c\x01\xbf\x81\xae-?\xdb\n\ ! w\x0c\x84g\x8b\xa7\x19+\xe6\xb2\xdfe\xf5y\x10\xb8\x8c\xe5\x0c-IE\xdb-v\xdd\ ! \xfd\x11e\xe1\xdcz\x87\x17\xe3\xf5\xf1\x18\xf6\x00\xc8\x9b\xb9$#\xe2\x9aC\ ! \xf7\x9e\xe3\xf3$\xfe\xe1\xe8\x16)\xc4<5\xafG\xc5J\xf37\x9dal\x9a\x97]+k\xc5\ ! l:\xec\x8ea.,{>G\xb1\xea\xee{o\xb2\xf4\x0cR2X\x99,Ok\xd8\xf6\x875\xcd;\x04\ ! \x1fB\x17\x9ax\x1f\xfaPX\xff\x00\x9bd\xbf\xb3:\xbb\xe0\x951\x15!\x8b\x9a\xa9\ ! g\xc8\xdb\xc9;\xeb\xb9O\xc6)\xd0\xa7<,\x1c.\xb9\x92Y\xb5m66\xff\x00\x13\xb8\ ! \xe3y\x07\x1a\x95\xf5\xc9\x87+@\x1bX\xeb,\xec\xf8\xa6op\x01\xfa\x1dh\xfe\xdf\ ! \x90_\xbb\x81\xe6\xfe\xd1\xf0\xec^h\x80\xd7\xda\xae\x1d \x1e\x81\xe3\xe1x\ ! \x1f\x87P+\xf6\xe7\xf2Pa\xf0wr\xb6\\\x1b\rH\x1f+\x89\xf9\xe8o_\xaf\xd1W<\x14\ ! \xa167\xc2\xdc\x15i\xda[!\x81\xd3h\xfa\x81#\xdd \xfe\xa7\x05Qw>\x1f\xe6\xfe\ ! \xb2I}Sr\xfcG\xef\xdc\xb5\xb2\x8e;\xcb\xfd\xa2\xef\xf4j\xdf\x97\xf6\xec\\Q\ ! \x11V\x96\x05\x0b\xf8>\xff\x00\x9a\x1c\'\xfd\xc7\xff\x00D\x8a\xfa\xb3\xbf\ ! \x03`\x96\xd7\x82\xd8x \xbbb\x8c\x8e\xf3\xf5<\ra{5fC\xd8=\xaeo\x7fN\xe0\xfa\ ! \xfd{\xae\xff\x00\xf2\xa7\xfe=\xff\x00\xc2\xab\x9c~\x1b\xc6\xc7W|\xf1^yj\xed\ ! \xd5\x95\x18\x1cG\x85\x82\xa0\xb9\x1b\xf2GE~\x88\xec\xf1\xab\x1d\xcbr|Z\xb4\ ! \x1c6Kq\xe4\x1by\x8f\x90\xd6\xb6+\xbb\xca\xe8\x90\x1d\xb8\xb9\xbb\x1dE\xbd\ ! \xb7\xf4\xfa,\xbe\x86\'\x9eb\xfd\xcb\xf6\xda[\xf2y\xbc\xaf\x15\xec\x9e\xd5|Y\ ! \xd6\xbc\xfe\xbdi\xee\xe9\xf5g\xd3}\xbe\x8b\\\xe3\xfe\xff\x00\xf7\xbc\x1e\ ! \xdb\xf6\xbb\xd9\xfe.\xbfn\xf7_\x93\xf7N\xba\xbc\x8f\xcaz\xeb]?=o\xb6\xd4\ ! \x7f\x8c\x7f\xeag\xfdWG\xff\x00\xda\x9f\xc3\xf1\xb3\xa1\xcb\x82\xb4$\x9d\xdf\ ! 2\xcd\xef\xaf\xd3m\x08X\xec\x1c+\xdf\x19y\xa6\xac\xac\xf2[i\xf5\xdfR\xfa\x88\ ! \x8b.i\x08^]\x91\xb3\x8f\xadM\xb5\xa5\x8a\xb1\xb7m\xb5\x9djVu\xb6\xb8-q\xea\ ! \xd6\xc6\xc9-\x0c\x1f.\xa7\xb7\xd7\xd0\xc2\xf1\xbb\xd4\xebr\xeb8\xfb\xf7r\ ! \xb62W\xe0kc7\xd9]\x8d\x928\xba\xdd\xf02 \x1c\xdf\xe3\x1c\x7f(\xd0H\x1d\xbd\ ! \x14\xe76\xc4\x1c\xef\x15\xc8b\xe3\xe8\xf3\xa5\x8b\xaa\x02\xf0\x0bD\xad!\xf1\ ! \x97\x02\x08 =\xad$\x10A\x1d\x96=\x94\xc9Q\xc5Tl\x14\xf7\x8e\x97\x1f}\x92H\ ! \xcb\xf3U\x85\xd0\xc8\xc9\x00>]j\xa1\xady::|\xbd \x8fC\xdfj\xfb\x86\xe1\xa1\ ! \x8a\xa0\xe1\x1f\x89\xe4\xf7\xe8\xd3\xbe\xba\xea\xbbnRq\x0cD\xb0\xd5\x94\xde\ ! \x9a\xf6\xd9\xabi\xa6\x8f\xbe\xc6\x9bi\xd9>!\x8f\xb1%j\xd5.`k~[O\xb2\xe8\xe6\ ! \xa9\x0f\xab\xda\xd6\x868=\xad\x1b-\x05\xcd\xd0\xf8~@\xabb\xa8\xe5\xadd\xb9f\ ! &\xe6;\x0f\x8e\x88b\xaeDk\xc9z\xe4\xcf\x84\xbd\x8f\x1a{\xa2\x8f\xcb%\xe04\ ! \x9d\x17\x16\x02Om\x8e\xea\xdc\xabqI\xa8\xc5\xcd%<\xef\xbfK_g\xad\xf4{\x96\ ! \x18f\xb9\x9a\x83\xf2\xe5o}7Zn\xb6\n\xb9\xce+\xd7\xb8\xfc\x15\x1b\xd0Gb\x85\ ! \x8c\xa3Yf)X\x1c\xc7\xb4C+\x98\x1c\x0fb<\xc6\xc7\xeb\xf8+\x1a\xfc\xf9\x1a4\ ! \xb2U\x1fO#N\xbd\xca\xcf\xd1t3\xc4$c\xb4v6\xd2\x08=\xfb\xae4*xu\x14\xbf}Wu\ ! \xaa;W\xa7\xe2A\xc7\xf7\xd3\xeaWy\xe7\x1b\xafw\x84I\x8a\xc6\xd0\xae\xd8\xea\ ! \xb9\x93\xc3J6\x16C\'C\xba\x8ce\x8c\xd6\xc1\xef\xf0\xf6\xd9\xd7q\xea\xa9\x10\ ! d\xb2\x12{\x06n\x95\xa6I\x8d\xc2\xcc\xcb\x12\xd6c\xe0h\xa7\x0fId\xc0\xc3\x14\ ! G\xa3Q9\xe41\xd3\x97lo\xa4\xebJ\xf4Y\x17\x11\xb7\xd7\x14m\x8b\x8fXp\xebk\x06\ ! \x99BC\xdb\xa8\x0f\xcd\x89\xdd\xb7\xae\xcdw\x7fG\x12:1\xb8\xe7\xe6\xaed\xeb\ ! \xe6\xb2\xf9\x0bM\xadvF\xba\x811\xc7\x07\x94O\\C\xe0`s\xdb\xd0\xe6\x83\xd4\ ! \xe2\t\x0e\x07}\xc2\xb8\xc3b<*O\x9f\xcd\rn\xf5\xcf)e\x9e}\x1ek^\xa9\xa2\xa7\ ! \x11C\xc4\xa8\xb9<\xb2\xd2\xcbL\xb3Y\xe5\x97U\x93\xd3\xa3L\xb7""\xa1.\xc2" \ ! \x08\x88\x80""\x00\xa3\xfd\xc9\x89\xf7\xf7\xbf\xbd\xdf_\xde~W\x93\xed=?\x1fG\ ! \xd3\x7f\xd5\xbf]v\xf4R\x08\xbdFr\x8d\xf9]\xaey\x94#+s+\xd8""\xf2z\x08\x88\ ! \x80""\x00\xba\xec\xd7\x82\xd4.\x82\xcc\x11O\x13\xbe\xf3$`sO\xe9\x05v"\xfa\ ! \x9bN\xe8\xf8\xd2y2\x11\xbcC\x89\xb2_5\xbc_\x08\xd97\xbe\xb1B \x7foJ\x99\x8a\ ! 6E\x1bc\x89\x8dc\x1a4\xd6\xb4h\x01\xf8\x05\xf4\x8b\xdc\xea\xd4\xa9\xf1\xc9\ ! \xbfVy\x85(C\xe1I\x04D\\\xcfa\x11\x10\x15\x7f\x16q\xef\xc9\xf8o\x9e\xa9\x1cn\ ! \x92CQ\xd21\x8d\x1b.s>0\x00\xf9\x9d\xb5V\xff\x00\x83U\x89f\xf0\xc2(\xa4c\xda\ ! +\xdb\x9a6u\rl\x12\x1d\xb1\xf5\x1bq\x1f\xa4\x15\xa6"\x9f\x1csX)a\x1crrR\xbe\ ! \xd9[B\x0c\xb0W\xc6G\x14\xa5\xa4\\m\xbew\x08\x88\xa0\x13\x82\xe8\xc8\xd3\xad\ ! \x90\xa1=\x1b\xb0\xb6j\xd6#tr\xc6\xefG4\x8d\x10\xbb\xd1}M\xc5\xdd\x1f\x1aMY\ ! \x99\x9e>\xcf#\xf0\xe0{\xae\xee:\xee\x7f\x8cF\x7f\xc4\xeeTg\x99f\xa3>Q\xc8\ ! \xcf\xceh\xf98z\x0f\xd4\x06_\xc6\xaf\xe1q\xde1\xcb\xcb\xdd\x9b\x82\xcc\x0f\ ! \xbdn\xc0\xa5\x05[&\xd6\xa5\x12\x06\xb7\xa4\xc4\x1b\xd5\xf1\x8d\xfc_^\xe5zq\ ! \x15\xf6\x1f\x8d\xc6\x9a\xa9\xcfO\xcd5i4\xed{\xf5i\xa7\x9f\xa5\x8aLG\x07\x95\ ! GO\x92\xa6Pw\x8aj\xf6\xb7{\xac\xbdnf\xb2S\xcf\xf8\x8fr\x0f|cl`\xf8\x9c\x12\t\ ! M;\x1d\xac\xe4\x1c\x0e\xda$h\xfb\x8c\x07\xbe\xbe\x7f\x8fb\xdd%\xadkZ\x1a\xd0\ ! \x1a\xd04\x00\x1d\x80\\\xa2\xaa\xc4\xe2\x9dkE.X\xad\x12\xf7\xf5o\xab\xff\x00\ ! VE\x9e\x1f\x0c\xa8\xdeM\xf3I\xea\xdf\xeeIt_\xec""\x8aI2\xcf\x03yG\x1a\xc7x[\ ! \x87\xa7\x90\xe4X\x8a\x96c\xf3\xfa\xe1\x9e\xecl{w<\x84m\xa4\xecl\x10\x7fZ\ ! \x9e\xc8]\xf0\xa3#q\xf72\x16\xf8U\xbb2k\xaei\xe4\xaa\xf7\xbb@\x01\xb7\x1e\ ! \xe7@\x01\xfa\x95\xd5\x15\x95lu:\x98\x89\xd7\x8ce\x17&\xdeR\xdd\xdf\xe5+\xe8\ ! \xe0\xe7N\x84(\xb7\x16\xa2\x92\xce;+|\xc5+\x1fw\xc2\x8cu\xc6\\\xc7\xdb\xe1U,\ ! \xc7\xbe\x89\xa0\x92\xab\x1e\xdd\x82\x0e\x9c;\x8d\x82G\xebP\x9e\'r\x1c\x06Z\ ! \xc7\x0e\xad\x8a\xcec/\xcc\xdeSE\xee\x8e\xb5\xb6J\xe0\xd0^6CI:\xd9\x03\x7f\ ! \x88Z\x82%,l)\xd5U\\d\xda\xde_\xf9\x150s\x9d\'I4\x93\xda?\xf6\x11\x11V\x96\ ! \x01\x11\x10\x04D@\x11\x11\x01\xf3,l\x96\'E+\x1a\xf8\xde\x0b\\\xd7\r\x87\x03\ ! \xea\x08U\xde\x17\x81\xbd\x873I\x90\xb3\x0c\xd2{4\x14\xa1\x11\x03\xa1\x0c\ ! \x1d}\x05\xc4\xfa\xbc\xf5\x9d\xfe\xa1\xdf[VD]cZp\x84\xa9\xad\x1d\xaf\xf49J\ ! \x94e8\xcd\xea\xbf\xd8DE\xc8\xea\x11\x11\x00DD\x01\x11\x10\x04D@\x11\x11\x00\ ! DD\x01\x11\x10\x04D@\x11\x11\x00DD\x01\x11\x10\x04D@\x11\x11\x00DD\x01\x11\ ! \x10\x04D@\x11\x11\x00DD\x01\x11\x10\x04D@\x11\x11\x00DD\x01\x11\x10\x04D@\ ! \x11\x11\x00DD\x01\x11\x10\x04D@\x11\x11\x00DD\x01\x11\x10\x04D@\x11\x11\x00\ ! DD\x01\x11\x10\x04D@\x11\x11\x00DD\x01\x11\x10\x04D@\x11\x11\x00DD\x01\x11\ ! \x10\x04D@\x11\x11\x00DD\x01\x11\x10\x04D@\x11\x11\x00DD\x01\x11\x10\x04D@\ ! \x7f\xff\xd9~BK\x00\x03\x00P\x06\x00\x00~BK\x00\x04\x00\x81\x01\x00\x00\x83\ ! \x00\x00\x00\n\x00Background\x01\x00\x00\x00\x00\x00\x00\x00\x00\x90\x01\x00\ ! \x00F\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x90\x01\x00\x00F\x00\x00\ ! \x00\xff\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x01\x00\x00\x00\x00\x00\x00\xff\xff\x00\x00\xff\xff\x00\x00\xff\xff\x00\x00\ ! \xff\xff\x00\x00\xff\xff\x00\x00\xff\xff\x00\x00\xff\xff\x00\x00\xff\xff\x00\ ! \x00\xff\xff\x00\x00\xff\xff\x08\x00\x00\x00\x01\x00\x03\x00~BK\x00\x05\x00H\ ! \x00\x00\x00\x10\x00\x00\x008\x00\x00\x00HH\x01\x00\x00\x00\x01\x00x\x9c\xec\ ! \xc11\x01\x00\x00\x00\xc2\xa0\xfe\xa9g\r\x0f\xa0\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00>\x0c\x00\x00\xff\xff\x03\x00\xa7\x88\xf8\xf5~BK\x00\x05\x00H\x00\x00\ ! \x00\x10\x00\x00\x008\x00\x00\x00HH\x01\x00\x00\x00\x02\x00x\x9c\xec\xc11\ ! \x01\x00\x00\x00\xc2\xa0\xfe\xa9g\r\x0f\xa0\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! >\x0c\x00\x00\xff\xff\x03\x00\xa7\x88\xf8\xf5~BK\x00\x05\x00H\x00\x00\x00\ ! \x10\x00\x00\x008\x00\x00\x00HH\x01\x00\x00\x00\x03\x00x\x9c\xec\xc11\x01\ ! \x00\x00\x00\xc2\xa0\xfe\xa9g\r\x0f\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>\ ! \x0c\x00\x00\xff\xff\x03\x00\xa7\x88\xf8\xf5~BK\x00\x04\x00\xbb\x04\x00\x00}\ ! \x00\x00\x00\x04\x00Text\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\xff\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x01\x00\x00\x00\x00\x00\x00\xff\xff\x00\x00\xff\xff\x00\x00\xff\xff\x00\x00\ ! \xff\xff\x00\x00\xff\xff\x00\x00\xff\xff\x00\x00\xff\xff\x00\x00\xff\xff\x00\ ! \x00\xff\xff\x00\x00\xff\xff~BK\x00\r\x00,\x04\x00\x00\x08\x00\x00\x00\x01\ ! \x00\x00\x00~BK\x00\x0e\x00\x1a\x04\x00\x00\x14\x00\x00\x00\x00\x00\x01\x00\ ! \x07\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00U\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c@\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00B@\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0?\ ! \x08\x00\x00\x00\x0c\x00\x00\x00\x06\x00\x00\x00\x03\x00\x08\x00\x00\x00\x00\ ! \x00\x00\x00\x06\x00\x00\x00\x02\x00Y\x00\x00\x00\x08\x00Webdings\x00\x00\ ! \x00\x00\x90\x01\x00\x00\x02\x00\x00\x005\x00\x00\x00\x00UUUUUU5@\x00\x01\ ! \x00\x01\x00\x00\x01\xd7\xa3p=\n\xd7\x1c@\xd7\xa3p=\n\xd7\x1c@\x00\x00\x00\ ! \x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\ ! \x00\x00$@~BK\x00\x0f\x00\x12\x00\x00\x00\x06\x00\x00\x00\x01\x00\x0c\x00\ ! \x00\x00\x00\x00\x00\x00\xff\xff\xff\xff~BK\x00\x0f\x00\x12\x00\x00\x00\x06\ ! \x00\x00\x00\x01\x00\x0c\x00\x00\x00\x00\x7f\xf6\x00\xff\xff\xff\xff~BK\x00\ ! \x13\x00-\x00\x00\x00-\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x01\x00\x08\ ! \x00\x00\x00a\x00\x00\x00\x06\x00\x00\x00\x02\x00Y\x00\x00\x00\x08\x00Webdin\ ! gs\x00\x00\x00\x00\x90\x01\x00\x00\x02\x00\x00\x00%\x00\x00\x00\x00\xde\xdd\ ! \xdd\xdd\xdd\xdd-@\x00\x01\x00\x01\x00\x00\x01\xd7\xa3p=\n\xd7\x1c@\xd7\xa3p\ ! =\n\xd7\x1c@\x00\x00\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\ ! \xf0?\x00\x00\x00\x00\x00\x00\x00$@~BK\x00\x0f\x00\x12\x00\x00\x00\x06\x00\ ! \x00\x00\x01\x00\x0c\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff~BK\x00\x0f\ ! \x00\x12\x00\x00\x00\x06\x00\x00\x00\x01\x00\x0c\x00\x00\x00\x00\x7f\xf6\x00\ ! \xff\xff\xff\xff~BK\x00\x13\x00-\x00\x00\x00-\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\ ! \x00\x00\x00\x01\x00\x08\x00\x00\x00N\x00\x00\x00\x06\x00\x00\x00\x01\x00\ ! \x08\x00\x00\x00L\x00\x00\x00\x06\x00\x00\x00\x01\x00\x08\x00\x00\x00i\x00\ ! \x00\x00\x06\x00\x00\x00\x02\x00Y\x00\x00\x00\x08\x00Webdings\x00\x00\x00\ ! \x00\xbc\x02\x00\x00\x02\x00\x00\x00%\x00\x00\x00\x00\xde\xdd\xdd\xdd\xdd\ ! \xdd-@\x00\x01\x00\x01\x00\x00\x01\xd7\xa3p=\n\xd7\x1c@\xd7\xa3p=\n\xd7\x1c@\ ! \x00\x00\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\ ! \x00\x00\x00\x00\x00$@~BK\x00\x0f\x00\x12\x00\x00\x00\x06\x00\x00\x00\x01\ ! \x00\x0c\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff~BK\x00\x0f\x00\x12\x00\ ! \x00\x00\x06\x00\x00\x00\x01\x00\x0c\x00\x00\x00\x00\x7f\xf6\x00\xff\xff\xff\ ! \xff~BK\x00\x13\x00-\x00\x00\x00-\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\ ! \x01\x00\x08\x00\x00\x00\x9b\x00\x00\x00\x06\x00\x00\x00\x02\x00Z\x00\x00\ ! \x00\t\x00Wingdings\x00\x00\x00\x00\x90\x01\x00\x00\x02\x00\x00\x00%\x00\x00\ ! \x00\x00\xde\xdd\xdd\xdd\xdd\xdd-@\x00\x01\x00\x01\x00\x00\x01\xd7\xa3p=\n\ ! \xd7\x1c@\xd7\xa3p=\n\xd7\x1c@\x00\x00\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\ ! \x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\x00$@~BK\x00\x0f\x00\x12\x00\ ! \x00\x00\x06\x00\x00\x00\x01\x00\x0c\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\ ! \xff~BK\x00\x0f\x00\x12\x00\x00\x00\x06\x00\x00\x00\x01\x00\x0c\x00\x00\x00\ ! \x00\x7f\xf6\x00\xff\xff\xff\xff~BK\x00\x13\x00-\x00\x00\x00-\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ ! \x00\x00\x00\x06\x00\x00\x00\x01\x00\x08\x00\x00\x00C\x00\x00\x00\x06\x00\ ! \x00\x00\x01\x00\x08\x00\x00\x00D\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\ ! \x00' ### end --- 1,151 ---- + # -*- coding: ISO-8859-1 -*- """Resource ui_psp (from file ui.psp)""" # written by resourcepackage: (1, 0, 0) source = 'ui.psp' package = 'spambayes.resources' ! data = "Paint Shop Pro Image File\012\032\000\000\000\000\000\005\000\000\000~BK\000\000\000.\000\000\000.\000\000\000\001\000\000F\000\000\000j\ ! ¼t“X<@\002\002\000\030\000\001\000\000\000\000\001\000@\002\000\000\000\000\000\002\000\003\000\000\005~BK\000\012\000\030\000\000\000~FL\000\001\000\016\000\000\000ÀÀÀ\000\012\000\000\000\ ! \012\000\000\000\000\000~BK\000\001\0008\000\000\000~FL\000\001\000\004\000\000\000ÔÃ'>~FL\000\002\000\004\000\000\000uà'>~FL\000\006\000\004\000\000\000\001\000\000\000~F\ ! L\000\007\000\004\000\000\000\004\004\000\007~BK\000\020\000Ë\032\000\000\010\000\000\000\002\000\000\000~BK\000\021\000\030\000\000\000\030\000\000\000È\000\000\000#\000\000\000\030\000\003\000\001\000\000\000\ ! \000\001\001\000~BK\000\021\000\030\000\000\000\030\000\000\000\001\000\000F\000\000\000\030\000\003\000\001\000\000\000\000\001\000\000~BK\000\022\000\012\000\000\016\000\000\000\012\000\0000R\000\000\ ! \005\000ÿØÿà\000\020JFIF\000\001\001\000\001,\001,\000\000ÿÛ\000C\000\002\001\001\001\001\001\002\001\001\001\002\002\002\002\002\004\003\002\002\002\002\005\004\004\003\004\006\005\006\006\006\005\006\ ! \006\006\007\011\010\006\007\011\007\006\006\010\013\010\011\012\012\012\012\012\006\010\013\014\013\012\014\011\012\012\012ÿÛ\000C\001\002\002\002\002\002\002\005\003\003\005\012\007\006\007\012\012\012\012\012\012\012\012\012\012\ ! \012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012ÿÀ\000\021\010\000#\000È\003\001\"\000\002\021\001\003\021\001ÿ\ ! Ä\000\034\000\001\000\002\002\003\001\000\000\000\000\000\000\000\000\000\000\000\007\010\005\006\002\004\011\003ÿÄ\0003\020\000\001\003\003\003\003\003\002\005\002\007\000\000\000\000\000\001\002\003\004\000\005\006\007\021\022\ ! \010\023!\024\"1\025A\026#23B\011\027QRWr•ÒÿÄ\000\032\001\001\000\003\001\001\001\000\000\000\000\000\000\000\000\000\000\000\002\004\005\001\006\003ÿÄ\000*\021\000\002\001\004\002\ ! \001\003\003\004\003\000\000\000\000\000\000\001\002\021\000\003\004!\005\0221\006AQ\"Ba\0232q\024\025bÿÚ\000\014\003\001\000\002\021\003\021\000?\000÷ò”¯::ãêí>„\ ! ú²Í.øŽ3õ|7SbÃ\030jf¶¹\014D¹·\0024e- Ÿ‡‚Ú$°|8\012\025·Íz_Kzc3Õ¼ƒàâ\\Eº\020²‡=CÊ\ ! \012ƒò\024—þ\024×õ/¨ñ}-‚¹™HÍl°V*'¨!ˆb>\013\000¿Ë\012»—n£´¶×¯vžš›¾\011YmÒÚýÁvøÛ+Ñ\ ! Fm<»\035ý…d€”ü‘¹Ø\017'{ªeý3z\000Îtžû3«ž¨/s®\032”2âÌYrJ•miíŠûÇ{ë\000\002?Kiö\ ! ¾û\\Úª08^+“\030|mÿ\000Ö\026Ô\007¹öµÉ=ºÀÐ\007Þ\011Ø3RôÖw/ÉñÇ+³ú%Ø”O¹mÀëßþÎÉ\036\ ! Ó\032ˆ¥)Us«\034ÒçêuÙZîÒ“ƒÇ³Es\006‡!çZ±Ý¦s&kW7\032#y\034FÑãº{\013\036@qÏjipÜSó\031Ÿ \ ! \006'ıØ\020«\"NäìB†b`UÞ[“N'\027õ™dLy€4L±ƒ\003P4eˆP$Õ£¥yEÒ\036C„OÎ3üšÛ\0218LùH\ ! SúyiÓ+Ôy÷t\\\012[ˆ–¢\036ÜÆRK‰)}\034Kg”‚›r½?ÒÉ\032‡/Ml2uj\004\030¹C–ˆêÈ#Û\034+ŽÜÂ\ ! ØˆVÿ\000r?À‘äîz»Ò\017é[âÙ½ßÀØ\012d¨mC8`'©!Œ6½Á8¾–õRúšÉqk§Ÿ\004°€Åw*¥\ ! I‰\000®×~Æ3ŽºÔv”ûî¥\010BJ–µ«`>I?aQÜ\036¨4Þãs·1\031‹·]ä©‹mð¡‘\031å%a²®=ÎòQ\ ! Ü!\034”Ø\037Ë~\036úÞ²\033\034,šÁ;\033¹sô×\010nÆ‘ÛVÊàâ\012\025±û\035‰óTóDtç(²ê½Ë ½GM¡éVëKY:\ ! ³\010Ò^õ\027›K’\030amúu#‹.)Èqù©.\004¡INÁÁËz|\017\027Çò\030¹\027/±›`1\003ÈM†qòTõÖô|\035•µÍò\ ! Yø96-ÙQ\027\011\000ŸwÑT?\001‡mü#A®})QçV7»Î9Ófkz°ÜŸ„û\026\007ùÏŒ­œ†É\034^ƒüTÛEn\003\ ! ö(ßíXXxÍ™™o\035L\027`³ñ&+o/!q1n_\"B)hþ\004×C ê÷Ií\027•Ù¬°r\034‡³=P^™ŽãïÊŠ%$\ ! ¸èx\000‡ÝI\004)¶K‹I\004\020\010Ú·]<Ô¬'Uqÿ\000ÄØ%ñ3c!õÇ…²¶^Šú6æË̺”¸Ã©ÜnÛ‰J†ãq\ ! äU[ëû\025Ñ,S.é¯\015™¤q.0\023©0lØê#]\037ˆÝ­—\034ŒŽHK$\007@àÙÙ_ä\036|«y»ÓıuœËxâRßâ\ ! \035:—+*m¯\001OD›\015«{Ë\003ù©¹\023\025ò¤°\006ä6\000õY¼/\025þ¢ÆF8¸­qn8,W¬[b\0101½€HÒÃBCÏq\ ! æpù~Ký¥û\027Ê2ÛkjB†™¸ ƒ½h\016ÚVZV:™NµŸïNŽ«8ÏýôýÖÍPGMÚ¤îžô‹£±N™å\ ! w´IÒë\022Ó'\036µ¦R\020D\006\001BÀp)\007È>FÄ\037\004 0pp\027+\031îAb\031T\000@žÁÉ2AñÓÇçñ[y¹Ç\033!-È\ ! \000«1$\023ûJ\000 \021ç·ŸÅJlk\036‘Iy\021£j¦6ãŽ(%¶Ñ|ŽT¥\023°\000\005ù5²UCê[A±=REÛ¬Wo\032aº\ ! ÚS\036\003x•êCqm¯§vÙîª/\005)C‹ä…w\007æ6\016Þݼ«\034¿\033ƒ…‹bî=ÂÅ»\007\004~ÇP¤¨?p†\033ЪüW\ ! !›™“zÝô\012\027©B\017îV,\003\021öþÓªÕõ\033R›Ó¹6£6Ó܇:J‘6rß(DFÒ\001Rü%\\ˆI.\020x€Ó/,«ò\ ! ø«gJ’¤…%@‚7\004\037š®}Tj¾I¢z¯oÌîÈyË¿ã m\031–’A\013àH×’tI\000Á«\035JR°ëj”¥)JWVéc²_=?Ö¬ñfz9H“\023ÕGK\ ! ‡Ñ¿\027QÈ\036+\033”<ÎÆ»T®«2™S\006¸Ê¬ ‰\024¥)\\®Ò¸H\036[\013‹)„:Ó‰)q·\022\024•\003ò\010?\"¹Ò€\ ! i汶\0143\017Å\024êñ|RÛm/~ñ\005¶{Ÿîà\006ÿ\000óY*R¤î÷\033³™?šŠ\"[^ª ~)QµÛ§v.\035WÙú¦\ ! ‰–.<‹v\025'\034—h\020‚„Æ\\™\010Yw˜áÁa^Þ'}Ç‘·™&•c\0273'\011œÙh쬧@Ê°‚7>G¿‘äA¯†N\ ! &>b¨¼³Õƒ\017\"\031Lƒ¯ƒý\037\007T¯”ØPîPÝ·\\b6üy\015)·Øy\001Hq\012\033)*\007Á\004\022\010?5õ¥V\004ƒ\"¬\020\010\ ! ƒU·Sú\004¾æ\027<1¬W[Ñ\026˧ù\0237œBÕ’cÎ\\—jy¥%M²ÓíLŒ¥²Ž\011\011Cáâ\002y\024€\004Ç¥šC\013MÝ\ ! ¹_îY\034ìƒ#¾-µß2+ @zHl(4Ê\020ÚR†Xl)|\032@\000sZ%­kVßJÙÌõ\017/Ÿˆ¸×îJ,몃³ØÉ\ ! \000\023-õ\031&[ê2wY8œ\017\025ƒ”Ù\026mØû˜\016¢\001$\010_¤@\020¿HÖ©QV\007 \031–\037£˜¶‹Þ2¼>ýoÅlPm±\ ! \\»à®;ÝôÑÒÂ^(T┬¥'ãã‘\025*Ò¨cçdâÛd´@\004‚t\016Ô\020\016Á\"\003\037\037;ö«¹\030XÙ7\003Ü\022@#É\032\ ! 0HÑ\023=GŸæ¢Ì¿@rÌŸNçé•»'Ĭ–Û‹í;)6l\035Æ\011R\035md€&ñäCiO\"\017¾vÚ¥:R™\031Ù9H\ ! \022é\011>\000Û@'@Lõ\036~)…Šåíˆ$\001ä\011 l˜ŽÇÇÍ)JUJµJÃÝðlzù–Ùók„w\025>Æ\037úzÐñ\ ! JGy\034\026T\007ëöî\000;È·óYŠTíܹi¥\014\030#_\004A\037Ø$\032ƒÛK‚\034H°d\037è‰\024¥)P©Ò”¥)JR”\ ! ¥)JR”¥)JR”¥)JR”¥)JR”¥)JR”¥)JR”¥)JR”¥)JR”¥)JR”¥ÿÙ~BK\000\022\000Þ\017\000\000\016\ ! \000\000\000Ð\017\000\000HH\001\000\010\000ÿØÿà\000\020JFIF\000\001\001\000\001,\001,\000\000ÿÛ\000C\000\005\003\004\004\004\003\005\004\004\004\005\005\005\006\007\014\010\007\007\007\007\017\ ! \013\013\011\014\021\017\022\022\021\017\021\021\023\026\034\027\023\024\032\025\021\021\030!\030\032\035\035\037\037\037\023\027\"$\"\036$\034\036\037\036ÿÛ\000C\001\005\005\005\007\006\007\016\010\010\016\036\024\021\ ! \024\036\036\036\036\036\036\036\036\036\036\036\036\036\036\036\036\036\036\036\036\036\036\036\036\036\036\036\036\036\036\036\036\036\036\036\036\036\036\036\036\036\036\036\036\036\036\036\036\036\036ÿÀ\000\021\010\000F\001\ ! \003\001\"\000\002\021\001\003\021\001ÿÄ\000\034\000\001\000\003\000\003\001\001\000\000\000\000\000\000\000\000\000\000\005\006\007\001\003\010\002\004ÿÄ\000F\020\000\001\004\002\001\002\003\005\003\006\010\017\001\000\000\ ! \000\001\000\002\003\004\005\021\006\022!\007\0231\024\025\"AQ\0262a#Bq‘Á\0103CV•¡²Ò\027$&78FRbfuv„¥±´ÂÿÄ\000\033\001\001\000\003\ ! \001\001\001\001\000\000\000\000\000\000\000\000\000\000\004\005\006\003\002\001\007ÿÄ\0001\021\000\002\001\002\004\004\004\006\002\002\003\000\000\000\000\000\000\001\002\003\021\004!1Q\005\022Aa\023\"q¡2\ ! R‘±ð\024B\006ÁÑáâÿÚ\000\014\003\001\000\002\021\003\021\000?\000öZ\" \010ˆ€\"€ç|³\025ðoÉääÙ;l\0204üs?ý–þóòUÿ\ ! \000\003y>O—qܦc(öùŽÊÈÈ£oÝŠ1\024D0~\003gô’J›\034\005ia¥Šµ šWÝö\"K\035F8…†¿«ÛeÜ¿¢\"\ ! „K\010ˆ€\"\"\000ˆˆ\002\" \010‹âyc‚\011'™íŽ8Ú^÷8è4\001²J%pò>ÑR(çò\034¤Í6.ô˜œt\020¶^¸ál–g\ ! ê`t‡5Á FøÜ~\007\035È\007mwãò[qäëRÈ^fB¥ÀÓZßÁÕño —1­kÚâ×7}--p\000ƒÔҧˇU\ ! ŠwµÖ«;þ-§r\022ÇÒmZöz>Ÿóíì^\021\021@&„D@\021Rsœêgf¦Àq\0344™üœ\007V\\Ù\004uªŸ£ä=º¿Ý\ ! \037B=F”T\\ƒÄ‡d_N98\005«qì¿\035\015é}© z‚\011ÐýŠÆ\034.¼£Í&£•ói;on‹»²+çĨÆVåÓ$Ú\ ! ¾×êû+šZ*\024æÑdò®Àæ±–0YÖ·¯Øì89³4zº'ŽÏ\037£ñõÑVå\022¾\036¥\011rTVžéè×tJ£^\ ! xóSw_¹5ª}˜DEÄì\021@ýµá¿ÎÜ\017ôŒ_ÞO¶¼7ùÛþ‘‹ûÊGñ1\037#û3‡ò¨|ëî‰äP?mxoó\ ! ·\003ý#\027÷—en]Å,ØŽµnO„ši^\031\034q߉Î{‰Ð\000\007l’{i\036\022ºÍÁý˜Xª/%5÷DÒ\"(çpˆ¨\024%~\ ! \033ä3W\004²yv¬WÊH^O•\023ÞÙ*Ê\001þM‘ü'^„¸üœ¤PÃøÊVy¯Ý=Z]HõëøM]dý¿uôMô/è\ ! ¸kšæ‡4‡4‚\016Á\013•\034\021\021\000EXÎs\\n2Ø«\025<ŽNOì£ó®5ÆxÏ5‹\034Çd¢e Ùê_’à’»šât\ ! \034Öµ¯\015\004h¸<\015èú-\002™æ—5ÃÓå½\037–7[\035Ç…Ø\005ŽP\ ! Û´\"˜¨ôI\034Çg»IpòX\016†Ü\036ï¨\007Ñl´ù._7o\027àpÉrÔî•Ù\014Û£tuk¾WºILeÃn=Ov»o\ ! Z#-G\024§QS¥\007çKâsMFÛçš~_‡ª3|6tÝJ’^GýTZnûe“^½>.ŒÓ¸¾s\037É0u³\030¹|ÊÖ\ ! \033±¾Îiô-pù\020{)5\005Àø½\036!Æ«áh\022ð;Y\\4eýç\037Ø\000\037 \000S«óÌJ¤«IQwݯ­º\033Ü;ªé\ ! EÕ^kgmŒ唦Éq\\¾:±Ôö¨Í\004gzøœÂÑýeI¢çNn\022RZ£¤à§\027\027ÔÃ|\034ÉA.W\026ë6ÙJÍV:\ ! ¬ðÌzIx‚8]\021ߣµZ»À>¿”\003»\012´åñ‘³—bp¸þæ\031aÀk`>ìväq\037šÆùA€žÄÊ\000ÞŽ¢¿„_\ ! \027Æ3‰[äôj¶®I’Æ,Ø„–\031cqéÓ€:wrÞäo²·x6Üdž\035ânc(W¨Ùà\002A\024a¥Îa,%Ä\017ˆì\036ç\ ! ¹ZœexJ‚â\024¯fùyz)Y½z¬Ý²û\031œ%\011ƳÀTµÒææêÕÒÓ¦ŠùýË‚\",™¨\012¥âÎfî\037‡H1Žè\ ! É_ž:\024ݽtÉ)Öÿ\000H\035D~ +j¡xÞ\035\007\035ÄæzK¡Ãæê_œ\001¿®-?Û\012w\014„g‹§\031+æ²ßeõy\020¸\ ! Œå\014-IEÛ-vÝý\021eáÜz‡\027ãõñ\030ö\000È›¹$#âšC÷žãó$þáè\026)Ä<5¯GÅJó7alš—]+kÅ\ ! l:ìŽa.,{>G±êî{o²ô\014R2X™,OkØö‡5Í;\004\037B\027šx\037úPXÿ\000›d¿³:»à•1\025!‹š©gÈÛ\ ! É;ë¹OÆ)Ч<,\034.¹’Yµm66ÿ\000\023¸ãy\007\032•õɇ+@\033Xë,ìø¦op\001ú\035hþß_»æþÑðì^h\ ! €×Ú®\035 \036ãáx\037‡P+öçòPaðwr¶\\\033\015H\037+‰ùèo_¯ÑW<\024¡67ÂÜ\025iÚ[!Óhú#Ý þ§\ ! \005Qw>\037æþ²I}SrüGïܵ²Ž;Ëý¢ïôjß—öì\\Q\021V–\005\013ø>ÿ\000š\034'ýÇÿ\000DŠú³¿\003`–ׂØx\ ! »bŒŽóõ<\015a{5fCØ=®oNàúý{®ÿ\000ò§þ=ÿ\000«œ~\033ÆÇW|ñ^yjíÕ•\030\034G…‚ ¹\033òGE\ ! ~ˆìñ«\035Ër|Z´\0346Kqä\033yÖ¶+»Êè\035¸¹»\035E½·ôú,¾†'žbýËöÚ[òy¼¯\025ìžÕ|YÖ¼\ ! þ½iîéõgÓ}¾‹\\ãþÿ\000÷¼\036Ûö»Ùþ.¿n÷_“÷Nº¼Êzë]?=o¶ÔŒêgýWGÿ\000ÚŸÃñ³¡\ ! Ë‚´$ß2Íï¯Óm\010Xì\034+ß\031y¦¬¬ò[iõßRúˆ‹.i\010^]‘³­Mµ¥Š±·mµjVu¶¸-qêÖÆ\ ! É-\014\037.§·×ÐÂñ»Ôërë8û÷r¶2Wàkc7Ù]’8ºÝð2 \034ßã\034(ÐH\035½\024ç6Ä\034ï\025Èbãèó¥\ ! ‹ª\002ð\013D­!ñ—\002\010 =­$\020A\035–=”ÉQÅTl\024÷Ž—\037}’HËóU…ÐÈÉ\000>]j¡­y::|½ Cßjû†\ ! á¡Š á\037‰ä÷èÓ¾ºê»nRq\014D°Õ”ÞšöÙ«i¦¾Æ›iÙ>!±%jÕ.`k~[O²èæ©\017«ÚÖ†8=\ ! ­\033-\005ÍÐø~@«b¨å­d¹f&æ;\017Žˆb®DkÉzäÏ„½\032{¢Ë%à4\027\026\002OmŽêÜ«qI¨ÅÍ%<ï\ ! ¿K_g­ô{–\030f¹šƒòåo}7Zn¶\012¹Î+׸ü\025\033ÐGb…Œ£Yf)X\034Ç´C+˜\034\017b<ÆÇëø+\032üù\0324\ ! ²U\037O#N½ÊÏÑt3Ä$c´v6Ò\010=û®4*xu\024¿}Wuª;W§âAÇ÷ÓêWyç\033¯w„IŠÆЮØ깓ÃJ\ ! 6\026C'CºŒeŒÖÁïðöÙ×qê©\020d²\022{\006n•¦IÂÌË\022Öcàh§\017IdÀÃ\024G£Q9ä1Ó—lo¤ëJôY\ ! \027\021·×\024m‹Xpëk\006™BCÛ¨\017͉ݷ®ÍwG\022:1¸çæ®dëæ²ù\013M­vFº1Ç\007”O\\Cà`sÛÐæ\ ! ƒÔâ\011\016\007}¸Ãb<*OŸÍ\015nõÏ)ež}\036k^©¢§\021CĨ¹<²ÒËL³Yå—U“Ó£L·\"\"¡.Â\" \010ˆ€\ ! \"\"\000£ýɉ÷÷¿½ß_Þ~W“í=?\037GÓÕ¿]vôR\010½Frù]®y”#+s+Ø\"\"òz\010ˆ€\"\"\000ºìׂÔ\ ! .‚Ì\021O\023¾ó$`sOé\005v\"ú›NèøÒy2\021¼C‰²_5¼_\010Ù7¾±B oJ™Š6E\033c‰c\0324Ö´h\001ø\005\ ! ô‹ÜêÔ©ñÉ¿Vy…(CáI\004D\\Ïa\021\020\025\026qïÉøož©\034n’CQÒ1\033.s>0\000ùµVÿ\000ƒU‰fðÂ(\ ! ¤cÚ+Ûš6u\015l\022\035±õ\033q\037¤\025¦\"Ÿ\034sX)a\034rrR¾Ù[B\014°WÆG\024¥¤\\m¾w\010ˆ \023‚èÈÓ­¡=\033\ ! °¶jÖ#trÆïG4\020»Ñ}MÅÝ\037\032MY™ž>Ï#ðà{®î:îŒFÄîTg™f£>QÈÏÎhù8z\017Ô\006_Æ\ ! ¯áqÞ1ËËÝ›‚Ì\017½nÀ¥\005[&Ö¥\022\006·¤Ä\033Õñü_^åzq\025ö\037Æš©ÏOÍ5i4í{õi§Ÿ¥ŠLG\007\ ! •GO’¦PwŠjö·{¬½nf²SÏør\017|cl`øœ\022\011M;\035¬ä\034\016Ú$hûŒ\007¾¾bÝ%­kZ\032Ð\032Ð4\000\ ! \035€\\¢ªÄâkE.X­\022÷õo«ÿ\000VEž\037\014¨ÞMóIêßîIt_ì\"\"ŠI2Ï\003yG\032Çx[‡§äXŠ–cóú\ ! ážìl{w<„m¤ìl\020ZžÈ]ð£#q÷2\026øU»2k®iäª÷»@\001·\036ç@\001ú•Õ\025•lu:˜‰×Œe\027&ÞR\ ! Ýßå+èàçN„(·\026¢’Î;+|Å+\037wÂŒuÆ\\ÇÛáU,Ǿ‰ ’«\036Ý‚\016œ;‚GëPž'r\034\006ZÇ\016­ŠÎ\ ! c/ÌÞSE¶JàÐ^6CI:Ù\003ˆZ‚%,l)ÕU\\dÚÞ_ù\0250s'I4“Ú?ö\021\021V–\001\021\020\004D@\021\021\001\ ! ó,l–'E+\032øÞ\013\\×\015‡\003ê\010UÞ\027½‡3I³\014Ò{4\024¡\021\003¡\014\035}\005Äú¼õþ¡ß[VD]cZp„©­\035\ ! ¯ô9J”e8Íê¿ØDEÈê\021\021\000DD\001\021\020\004D@\021\021\000DD\001\021\020\004D@\021\021\000DD\001\021\020\004D@\021\021\000DD\001\021\020\004D@\021\ ! \021\000DD\001\021\020\004D@\021\021\000DD\001\021\020\004D@\021\021\000DD\001\021\020\004D@\021\021\000DD\001\021\020\004D@\021\021\000DD\001\021\020\004D@\021\021\000DD\001\ ! \021\020\004D@\021\021\000DD\001\021\020\004D@\021\021\000DD\001\021\020\004D@\021\021\000DD\001\021\020\004D@ÿÙ~BK\000\003\000P\006\000\000~BK\000\004\000\001\000\ ! \000ƒ\000\000\000\012\000Background\001\000\000\000\000\000\000\000\000\001\000\000F\000\000\000\000\000\000\000\000\000\000\000\001\000\000F\000\000\000ÿ\000\001\000\000\000\000\000\000\000\ ! \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000ÿÿ\000\000ÿÿ\000\000ÿÿ\000\000ÿÿ\000\000ÿÿ\000\000ÿÿ\000\000ÿÿ\ ! \000\000ÿÿ\000\000ÿÿ\000\000ÿÿ\010\000\000\000\001\000\003\000~BK\000\005\000H\000\000\000\020\000\000\0008\000\000\000HH\001\000\000\000\001\000xœìÁ1\001\000\000\000 þ©g\ ! \015\017 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000>\014\000\000ÿÿ\003\000§ˆøõ~BK\000\005\000H\000\000\000\020\000\000\0008\000\000\000\ ! HH\001\000\000\000\002\000xœìÁ1\001\000\000\000 þ©g\015\017 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000>\014\000\000ÿÿ\003\000\ ! §ˆøõ~BK\000\005\000H\000\000\000\020\000\000\0008\000\000\000HH\001\000\000\000\003\000xœìÁ1\001\000\000\000 þ©g\015\017 \000\000\000\000\000\000\000\000\000\000\000\000\000\ ! \000\000\000\000\000\000\000\000\000\000\000\000\000\000>\014\000\000ÿÿ\003\000§ˆøõ~BK\000\004\000»\004\000\000}\000\000\000\004\000Text\003\000\000\000\000\000\000\000\000\000\000\000\000\000\ ! \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000ÿ\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\ ! \000\000\000ÿÿ\000\000ÿÿ\000\000ÿÿ\000\000ÿÿ\000\000ÿÿ\000\000ÿÿ\000\000ÿÿ\000\000ÿÿ\000\000ÿÿ\000\000ÿÿ~BK\000\015\000,\004\000\000\010\000\000\000\001\000\000\000~\ ! BK\000\016\000\032\004\000\000\024\000\000\000\000\000\001\000\007\000\000\000\001\000\000\000\000\000\000\000U\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000ð?\000\000\000\000\000\000\000\000\000\000\ ! \000\000\000\000\034@\000\000\000\000\000\000\000\000\000\000\000\000\000\000ð?\000\000\000\000\000\000B@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000ð?\010\000\000\000\014\000\ ! \000\000\006\000\000\000\003\000\010\000\000\000\000\000\000\000\006\000\000\000\002\000Y\000\000\000\010\000Webdings\000\000\000\000\001\000\000\002\000\000\0005\000\000\000\000UUUUUU5\ ! @\000\001\000\001\000\000\001×£p=\012×\034@×£p=\012×\034@\000\000\000\000\000\000\000\000ð?\000\000\000\000\000\000ð?\000\000\000\000\000\000\000$@~BK\000\017\000\022\000\000\ ! \000\006\000\000\000\001\000\014\000\000\000\000\000\000\000ÿÿÿÿ~BK\000\017\000\022\000\000\000\006\000\000\000\001\000\014\000\000\000\000ö\000ÿÿÿÿ~BK\000\023\000-\000\000\000-\000\000\ ! \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\006\000\000\000\001\000\010\000\000\000a\000\000\000\006\000\000\000\ ! \002\000Y\000\000\000\010\000Webdings\000\000\000\000\001\000\000\002\000\000\000%\000\000\000\000ÞÝÝÝÝÝ-@\000\001\000\001\000\000\001×£p=\012×\034@×£p=\ ! \012×\034@\000\000\000\000\000\000\000\000ð?\000\000\000\000\000\000ð?\000\000\000\000\000\000\000$@~BK\000\017\000\022\000\000\000\006\000\000\000\001\000\014\000\000\000\000\000\000\000ÿÿÿÿ~\ ! BK\000\017\000\022\000\000\000\006\000\000\000\001\000\014\000\000\000\000ö\000ÿÿÿÿ~BK\000\023\000-\000\000\000-\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\ ! \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\006\000\000\000\001\000\010\000\000\000N\000\000\000\006\000\000\000\001\000\010\000\000\000L\000\000\000\006\000\000\000\001\000\010\000\000\000\ ! i\000\000\000\006\000\000\000\002\000Y\000\000\000\010\000Webdings\000\000\000\000¼\002\000\000\002\000\000\000%\000\000\000\000ÞÝÝÝÝÝ-@\000\001\000\001\000\000\001×£p=\ ! \012×\034@×£p=\012×\034@\000\000\000\000\000\000\000\000ð?\000\000\000\000\000\000ð?\000\000\000\000\000\000\000$@~BK\000\017\000\022\000\000\000\006\000\000\000\001\000\014\000\000\000\000\ ! \000\000\000ÿÿÿÿ~BK\000\017\000\022\000\000\000\006\000\000\000\001\000\014\000\000\000\000ö\000ÿÿÿÿ~BK\000\023\000-\000\000\000-\000\000\000\000\000\000\000\000\000\000\000\000\000\000\ ! \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\006\000\000\000\001\000\010\000\000\000›\000\000\000\006\000\000\000\002\000Z\000\000\000\011\000Wing\ ! dings\000\000\000\000\001\000\000\002\000\000\000%\000\000\000\000ÞÝÝÝÝÝ-@\000\001\000\001\000\000\001×£p=\012×\034@×£p=\012×\034@\000\000\000\000\000\000\000\ ! \000ð?\000\000\000\000\000\000ð?\000\000\000\000\000\000\000$@~BK\000\017\000\022\000\000\000\006\000\000\000\001\000\014\000\000\000\000\000\000\000ÿÿÿÿ~BK\000\017\000\022\000\000\000\006\000\ ! \000\000\001\000\014\000\000\000\000ö\000ÿÿÿÿ~BK\000\023\000-\000\000\000-\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\ ! \000\000\000\000\000\000\000\000\000\000\000\006\000\000\000\001\000\010\000\000\000C\000\000\000\006\000\000\000\001\000\010\000\000\000D\000\000\000\010\000\000\000\000\000\000\000" ### end From mhammond at users.sourceforge.net Mon Jul 14 04:52:53 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Mon Jul 14 06:52:56 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 msgstore.py,1.48,1.49 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv3579 Modified Files: msgstore.py Log Message: __repr__ didn't handle the fact that IDs get set to None after a move. Index: msgstore.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/msgstore.py,v retrieving revision 1.48 retrieving revision 1.49 diff -C2 -d -r1.48 -r1.49 *** msgstore.py 9 Jul 2003 07:51:42 -0000 1.48 --- msgstore.py 14 Jul 2003 10:52:51 -0000 1.49 *************** *** 479,486 **** def __repr__(self): ! return "<%s, '%s' id=%s/%s>" % (self.__class__.__name__, self.GetSubject(), ! mapi.HexFromBin(self.id[0]), ! mapi.HexFromBin(self.id[1])) def __eq__(self, other): --- 479,489 ---- def __repr__(self): ! if self.id is None: ! id_str = "(deleted/moved)" ! else: ! id_str = mapi.HexFromBin(self.id[0]), mapi.HexFromBin(self.id[1]) ! return "<%s, '%s' id=%s>" % (self.__class__.__name__, self.GetSubject(), ! id_str) def __eq__(self, other): From mhammond at users.sourceforge.net Mon Jul 14 04:53:29 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Mon Jul 14 06:53:31 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 addin.py,1.71,1.72 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv3679 Modified Files: addin.py Log Message: Fix typo, and extra log messages when verbosity set high. Index: addin.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/addin.py,v retrieving revision 1.71 retrieving revision 1.72 diff -C2 -d -r1.71 -r1.72 *** addin.py 9 Jul 2003 08:13:13 -0000 1.71 --- addin.py 14 Jul 2003 10:53:27 -0000 1.72 *************** *** 156,161 **** # outlook one def ProcessMessage(msgstore_message, manager): if msgstore_message.GetField(manager.config.general.field_score_name) is not None: ! # Already seem this message - user probably moving it back # after incorrect classification. # If enabled, re-train as Ham --- 156,162 ---- # outlook one def ProcessMessage(msgstore_message, manager): + manager.LogDebug(2, "ProcessMessage starting for", msgstore_message) if msgstore_message.GetField(manager.config.general.field_score_name) is not None: ! # Already seen this message - user probably moving it back # after incorrect classification. # If enabled, re-train as Ham *************** *** 179,182 **** --- 180,184 ---- else: print "Spam filtering is disabled - ignoring new message" + manager.LogDebug(2, "ProcessMessage finished for", msgstore_message) # Button/Menu and other UI event handler classes *************** *** 212,215 **** --- 214,219 ---- # PR_RECEIVED_BY_ENTRYID # PR_TRANSPORT_MESSAGE_HEADERS + self.manager.LogDebug(2, "OnItemAdd event for folder", self, + "with item", item) msgstore_message = self.manager.message_store.GetMessage(item) if msgstore_message is not None: *************** *** 223,226 **** --- 227,232 ---- # was *not* certain-spam, or it is in the ham corpa, # then it should be trained as such. + self.manager.LogDebug(2, "OnItemAdd event for SPAM folder", self, + "with item", item) if not self.manager.config.training.train_manual_spam: return From montanaro at users.sourceforge.net Mon Jul 14 06:08:19 2003 From: montanaro at users.sourceforge.net (Skip Montanaro) Date: Mon Jul 14 08:08:23 2003 Subject: [Spambayes-checkins] spambayes/spambayes dbmstorage.py,1.4,1.5 Message-ID: Update of /cvsroot/spambayes/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv14867 Modified Files: dbmstorage.py Log Message: trivial hack to give dumbdbm a sync() method (which Shelve will call) and hopefully reduce database corruption Index: dbmstorage.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/spambayes/dbmstorage.py,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** dbmstorage.py 26 Feb 2003 05:12:40 -0000 1.4 --- dbmstorage.py 14 Jul 2003 12:08:17 -0000 1.5 *************** *** 26,30 **** """Open a dumbdbm database.""" import dumbdbm ! return dumbdbm.open(*args) def open_best(*args): --- 26,33 ---- """Open a dumbdbm database.""" import dumbdbm ! db = dumbdbm.open(*args) ! if not hasattr(db, "sync"): ! db.sync = db._commit ! return db def open_best(*args): From anadelonbrin at users.sourceforge.net Fri Jul 18 00:25:50 2003 From: anadelonbrin at users.sourceforge.net (Tony Meyer) Date: Fri Jul 18 02:25:54 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000/dialogs FilterDialog.py, 1.18, 1.19 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000/dialogs In directory sc8-pr-cvs1:/tmp/cvs-serv13913/Outlook2000/dialogs Modified Files: FilterDialog.py Log Message: Allow users to define cutoff point to float accuracy. Fixes [ 773452 ] Unable to use fractional number as spam_threshold. (Mark, if you would rather it was the other way, just roll this back and change the allowed value of the two config options to INTEGER instead of REAL) Index: FilterDialog.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/dialogs/FilterDialog.py,v retrieving revision 1.18 retrieving revision 1.19 diff -C2 -d -r1.18 -r1.19 *** FilterDialog.py 4 Jun 2003 08:25:53 -0000 1.18 --- FilterDialog.py 18 Jul 2003 06:25:48 -0000 1.19 *************** *** 92,98 **** def OnInitDialog(self): ! self.SetDlgItemText(IDC_EDIT_CERTAIN, "%d" % self.mgr.config.filter.spam_threshold) self.HookCommand(self.OnEditChange, IDC_EDIT_CERTAIN) ! self.SetDlgItemText(IDC_EDIT_UNSURE, "%d" % self.mgr.config.filter.unsure_threshold) self.HookCommand(self.OnEditChange, IDC_EDIT_UNSURE) --- 92,98 ---- def OnInitDialog(self): ! self.SetDlgItemText(IDC_EDIT_CERTAIN, "%s" % self.mgr.config.filter.spam_threshold) self.HookCommand(self.OnEditChange, IDC_EDIT_CERTAIN) ! self.SetDlgItemText(IDC_EDIT_UNSURE, "%s" % self.mgr.config.filter.unsure_threshold) self.HookCommand(self.OnEditChange, IDC_EDIT_UNSURE) *************** *** 216,221 **** assert slider.GetSafeHwnd() == lParam idc_edit = IDC_EDIT_UNSURE ! slider_pos = slider.GetPos() ! self.SetDlgItemText(idc_edit, "%d" % slider_pos) def _InitSlider(self, idc_slider, idc_edit): --- 216,221 ---- assert slider.GetSafeHwnd() == lParam idc_edit = IDC_EDIT_UNSURE ! slider_pos = float(slider.GetPos()) ! self.SetDlgItemText(idc_edit, "%s" % slider_pos) def _InitSlider(self, idc_slider, idc_edit): *************** *** 231,235 **** edit = self.GetDlgItem(idc_edit) try: ! val = int(edit.GetWindowText()) except ValueError: return --- 231,235 ---- edit = self.GetDlgItem(idc_edit) try: ! val = float(edit.GetWindowText()) except ValueError: return From richiehindle at users.sourceforge.net Fri Jul 18 14:19:34 2003 From: richiehindle at users.sourceforge.net (Richie Hindle) Date: Fri Jul 18 16:21:38 2003 Subject: [Spambayes-checkins] spambayes/spambayes message.py,1.29,1.30 Message-ID: Update of /cvsroot/spambayes/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv16669 Modified Files: message.py Log Message: Whitespace normalisation. Index: message.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/spambayes/message.py,v retrieving revision 1.29 retrieving revision 1.30 diff -C2 -d -r1.29 -r1.30 *** message.py 26 May 2003 06:43:24 -0000 1.29 --- message.py 18 Jul 2003 20:19:32 -0000 1.30 *************** *** 19,23 **** have been trained differently than their classification, for fp/fn assessment purposes. ! Message is an extension of the email package Message class, to include persistent message information. The persistent state --- 19,23 ---- have been trained differently than their classification, for fp/fn assessment purposes. ! Message is an extension of the email package Message class, to include persistent message information. The persistent state *************** *** 29,53 **** SBHeaderMessage extends Message to include spambayes header specific manipulations. ! Usage: A typical classification usage pattern would be something like: ! >>> msg = spambayes.message.SBHeaderMessage() >>> msg.setPayload(substance) # substance comes from somewhere else >>> id = msg.setIdFromPayload() ! >>> if id is None: >>> msg.setId(time()) # or some unique identifier ! >>> msg.delSBHeaders() # never include sb headers in a classification ! ! >>> # bayes object is your responsibility >>> (prob, clues) = bayes.spamprob(msg.asTokens(), evidence=True) >>> msg.addSBHeaders(prob, clues) ! ! A typical usage pattern to train as spam would be something like: ! >>> msg = spambayes.message.SBHeaderMessage() >>> msg.setPayload(substance) # substance comes from somewhere else --- 29,53 ---- SBHeaderMessage extends Message to include spambayes header specific manipulations. ! Usage: A typical classification usage pattern would be something like: ! >>> msg = spambayes.message.SBHeaderMessage() >>> msg.setPayload(substance) # substance comes from somewhere else >>> id = msg.setIdFromPayload() ! >>> if id is None: >>> msg.setId(time()) # or some unique identifier ! >>> msg.delSBHeaders() # never include sb headers in a classification ! ! >>> # bayes object is your responsibility >>> (prob, clues) = bayes.spamprob(msg.asTokens(), evidence=True) >>> msg.addSBHeaders(prob, clues) ! ! A typical usage pattern to train as spam would be something like: ! >>> msg = spambayes.message.SBHeaderMessage() >>> msg.setPayload(substance) # substance comes from somewhere else *************** *** 55,65 **** >>> msg.delSBHeaders() # never include sb headers in a train ! >>> if msg.getTraining() == False: # could be None, can't do boolean test >>> bayes.unlearn(msg.asTokens(), False) # untrain the ham ! >>> bayes.learn(msg.asTokens(), True) # train as spam >>> msg.rememberTraining(True) ! To Do: --- 55,65 ---- >>> msg.delSBHeaders() # never include sb headers in a train ! >>> if msg.getTraining() == False: # could be None, can't do boolean test >>> bayes.unlearn(msg.asTokens(), False) # untrain the ham ! >>> bayes.learn(msg.asTokens(), True) # train as spam >>> msg.rememberTraining(True) ! To Do: *************** *** 128,132 **** def _delState(self, msg): del self.db[msg.getId()] ! # This should come from a Mark Hammond idea of a master db # For the moment, we get the name of another file from the options, --- 128,132 ---- def _delState(self, msg): del self.db[msg.getId()] ! # This should come from a Mark Hammond idea of a master db # For the moment, we get the name of another file from the options, *************** *** 147,151 **** self.c = None self.t = None ! # non-persistent state includes all of email.Message.Message state --- 147,151 ---- self.c = None self.t = None ! # non-persistent state includes all of email.Message.Message state *************** *** 167,171 **** # to try to extract important headers regardless of malformations prs._parsebody(self, fp) ! def setId(self, id): if self.id: --- 167,171 ---- # to try to extract important headers regardless of malformations prs._parsebody(self, fp) ! def setId(self, id): if self.id: *************** *** 176,184 **** if not type(id) in types.StringTypes: ! raise TypeError, "Id must be a string" ! self.id = id msginfoDB._getState(self) ! def getId(self): return self.id --- 176,184 ---- if not type(id) in types.StringTypes: ! raise TypeError, "Id must be a string" ! self.id = id msginfoDB._getState(self) ! def getId(self): return self.id *************** *** 198,202 **** # append function), but does not, so we do it here return self._force_CRLF(email.Message.Message.as_string(self)) ! def modified(self): if self.id: # only persist if key is present --- 198,202 ---- # append function), but does not, so we do it here return self._force_CRLF(email.Message.Message.as_string(self)) ! def modified(self): if self.id: # only persist if key is present *************** *** 236,240 **** self.t = isSpam self.modified() ! def __repr__(self): return "spambayes.message.Message%r" % repr(self.__getstate__()) --- 236,240 ---- self.t = isSpam self.modified() ! def __repr__(self): return "spambayes.message.Message%r" % repr(self.__getstate__()) *************** *** 250,257 **** '''Message class that is cognizant of Spambayes headers. Adds routines to add/remove headers for Spambayes''' ! def __init__(self): Message.__init__(self) ! def setIdFromPayload(self): try: --- 250,257 ---- '''Message class that is cognizant of Spambayes headers. Adds routines to add/remove headers for Spambayes''' ! def __init__(self): Message.__init__(self) ! def setIdFromPayload(self): try: *************** *** 265,269 **** '''Add hammie header, and remember message's classification. Also, add optional headers if needed.''' ! if prob < options['Categorization','ham_cutoff']: disposition = options['Headers','header_ham_string'] --- 265,269 ---- '''Add hammie header, and remember message's classification. Also, add optional headers if needed.''' ! if prob < options['Categorization','ham_cutoff']: disposition = options['Headers','header_ham_string'] *************** *** 274,286 **** self.RememberClassification(disposition) self[options['Headers','classification_header_name']] = disposition ! if options['Headers','include_score']: self[options['Headers','score_header_name']] = str(prob) ! if options['Headers','include_thermostat']: thermostat = '**********' self[options['Headers','thermostat_header_name']] = \ thermostat[:int(prob*10)] ! if options['Headers','include_evidence']: hco = options['Headers','clue_mailheader_cutoff'] --- 274,286 ---- self.RememberClassification(disposition) self[options['Headers','classification_header_name']] = disposition ! if options['Headers','include_score']: self[options['Headers','score_header_name']] = str(prob) ! if options['Headers','include_thermostat']: thermostat = '**********' self[options['Headers','thermostat_header_name']] = \ thermostat[:int(prob*10)] ! if options['Headers','include_evidence']: hco = options['Headers','clue_mailheader_cutoff'] *************** *** 312,316 **** except KeyError: self["Subject"] = disposition ! if "header" in options['pop3proxy','add_mailid_to']: self[options['pop3proxy','mailid_header_name']] = self.id --- 312,316 ---- except KeyError: self["Subject"] = disposition ! if "header" in options['pop3proxy','add_mailid_to']: self[options['pop3proxy','mailid_header_name']] = self.id From richiehindle at users.sourceforge.net Fri Jul 18 15:20:01 2003 From: richiehindle at users.sourceforge.net (Richie Hindle) Date: Fri Jul 18 17:20:06 2003 Subject: [Spambayes-checkins] spambayes/spambayes message.py,1.30,1.31 Message-ID: Update of /cvsroot/spambayes/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv29031 Modified Files: message.py Log Message: Line-wrap the very long X-Spambayes-Evidence header. Index: message.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/spambayes/message.py,v retrieving revision 1.30 retrieving revision 1.31 diff -C2 -d -r1.30 -r1.31 *** message.py 18 Jul 2003 20:19:32 -0000 1.30 --- message.py 18 Jul 2003 21:19:58 -0000 1.31 *************** *** 290,294 **** if (word[0] == '*' or score <= hco or score >= sco): evd.append("%r: %.2f" % (word, score)) ! self[options['Headers','evidence_header_name']] = "; ".join(evd) # These are pretty ugly, but no-one has a better idea about how to --- 290,310 ---- if (word[0] == '*' or score <= hco or score >= sco): evd.append("%r: %.2f" % (word, score)) ! ! # Line-wrap this header, because it can get very long. We don't ! # use email.Header.Header because that can explode with unencoded ! # non-ASCII characters. We can't use textwrap because that's 2.3. ! wrappedEvd = [] ! headerName = options['Headers','evidence_header_name'] ! lineLength = len(headerName) + len(': ') ! for component, index in zip(evd, range(len(evd))): ! wrappedEvd.append(component) ! lineLength += len(component) ! if index < len(evd)-1: ! if lineLength + len('; ') + len(evd[index+1]) < 78: ! wrappedEvd.append('; ') ! else: ! wrappedEvd.append(';\n\t') ! lineLength = 8 ! self[headerName] = "".join(wrappedEvd) # These are pretty ugly, but no-one has a better idea about how to From richiehindle at users.sourceforge.net Fri Jul 18 15:21:43 2003 From: richiehindle at users.sourceforge.net (Richie Hindle) Date: Fri Jul 18 17:21:46 2003 Subject: [Spambayes-checkins] spambayes pop3proxy.py,1.86,1.87 Message-ID: Update of /cvsroot/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv29300 Modified Files: pop3proxy.py Log Message: Don't use email.Header.Header to pretty-print headers. The only problem header is X-Spambayes-Evidence and that's now line-wrapped by message.py. Thanks to Serge Orlov for prodding me into doing this. Index: pop3proxy.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/pop3proxy.py,v retrieving revision 1.86 retrieving revision 1.87 diff -C2 -d -r1.86 -r1.87 *** pop3proxy.py 7 Jul 2003 21:01:20 -0000 1.86 --- pop3proxy.py 18 Jul 2003 21:21:41 -0000 1.87 *************** *** 472,477 **** headers = [] for name, value in msg.items(): ! enc = Header(value, header_name=name, continuation_ws='\t') ! header = "%s: %s" % (name, str(enc)) headers.append(re.sub(r'\r?\n', '\r\n', header)) body = re.split(r'\n\r?\n', messageText, 1)[1] --- 472,476 ---- headers = [] for name, value in msg.items(): ! header = "%s: %s" % (name, value) headers.append(re.sub(r'\r?\n', '\r\n', header)) body = re.split(r'\n\r?\n', messageText, 1)[1] From anadelonbrin at users.sourceforge.net Fri Jul 18 17:25:51 2003 From: anadelonbrin at users.sourceforge.net (Tony Meyer) Date: Fri Jul 18 19:25:54 2003 Subject: [Spambayes-checkins] website faq.txt,1.12,1.13 Message-ID: Update of /cvsroot/spambayes/website In directory sc8-pr-cvs1:/tmp/cvs-serv20280 Modified Files: faq.txt Log Message: Move an Outlook question into the Outlook section. (I knew this answer was there, but couldn't find it!) Index: faq.txt =================================================================== RCS file: /cvsroot/spambayes/website/faq.txt,v retrieving revision 1.12 retrieving revision 1.13 diff -C2 -d -r1.12 -r1.13 *** faq.txt 11 Jul 2003 12:51:07 -0000 1.12 --- faq.txt 18 Jul 2003 23:25:49 -0000 1.13 *************** *** 399,402 **** --- 399,416 ---- + Why is the enable filter button is grayed out? + --------------------------------------------------------- + + You need to have done these things to enable that button: + + 1. Trained at least 5 ham and 5 spam + + 2. Set at least one folder to watch + + 3. Set folders to move spam to, and to move unsures to + + 4. Changed the action to "copy" or "move", rather than "untouched" + + Using Spambayes =============== *************** *** 661,678 **** numbers (3 and 12) were determined by brute force testing, and produced the best overall results (including compared to no upper or lower limits). - - - Why is the enable filter button is grayed out in Outlook? - --------------------------------------------------------- - - You need to have done these things to enable that button: - - 1. Trained at least 5 ham and 5 spam - - 2. Set at least one folder to watch - - 3. Set folders to move spam to, and to move unsures to - - 4. Changed the action to "copy" or "move", rather than "untouched" --- 675,678 ---- From mhammond at users.sourceforge.net Fri Jul 18 23:37:15 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Sat Jul 19 01:37:20 2003 Subject: [Spambayes-checkins] spambayes/windows pop3proxy_service.py, 1.4, 1.5 Message-ID: Update of /cvsroot/spambayes/spambayes/windows In directory sc8-pr-cvs1:/tmp/cvs-serv29089 Modified Files: pop3proxy_service.py Log Message: Redirect output when running as a service to win32traceutil (for want of a better place) Index: pop3proxy_service.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/windows/pop3proxy_service.py,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** pop3proxy_service.py 13 Apr 2003 22:52:13 -0000 1.4 --- pop3proxy_service.py 19 Jul 2003 05:37:13 -0000 1.5 *************** *** 51,54 **** --- 51,69 ---- from ntsecuritycon import * + # Messages from pop3proxy will go nowhere when executed as a service + # Try and detect that print will go nowhere and redirect. + try: + # redirect output somewhere useful when running as a service. + import win32api + try: + win32api.GetConsoleTitle() + except win32api.error: + # no console - import win32traceutil + import win32traceutil + print "popproxy service module loading (as user %s)..." \ + % win32api.GetUserName() + except ImportError: + pass + class Service(win32serviceutil.ServiceFramework): _svc_name_ = "pop3proxy" From richiehindle at users.sourceforge.net Sat Jul 19 03:15:02 2003 From: richiehindle at users.sourceforge.net (Richie Hindle) Date: Sat Jul 19 05:15:06 2003 Subject: [Spambayes-checkins] spambayes pop3proxy.py,1.87,1.88 Message-ID: Update of /cvsroot/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv23089 Modified Files: pop3proxy.py Log Message: Print a traceback as well as adding an X-Spambayes-Exception header when there's an exception raised while processing a message. Index: pop3proxy.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/pop3proxy.py,v retrieving revision 1.87 retrieving revision 1.88 diff -C2 -d -r1.87 -r1.88 *** pop3proxy.py 18 Jul 2003 21:21:41 -0000 1.87 --- pop3proxy.py 19 Jul 2003 09:15:00 -0000 1.88 *************** *** 499,502 **** --- 499,505 ---- messageText = headers + body + # Print the exception and a traceback. + traceback.print_exc() + # Restore the +OK and the POP3 .\r\n terminator if there was one. retval = ok + "\n" + messageText From montanaro at users.sourceforge.net Sat Jul 19 05:31:41 2003 From: montanaro at users.sourceforge.net (Skip Montanaro) Date: Sat Jul 19 07:31:46 2003 Subject: [Spambayes-checkins] website faq.txt,1.13,1.14 Message-ID: Update of /cvsroot/spambayes/website In directory sc8-pr-cvs1:/tmp/cvs-serv7928 Modified Files: faq.txt Log Message: minor touchup Index: faq.txt =================================================================== RCS file: /cvsroot/spambayes/website/faq.txt,v retrieving revision 1.13 retrieving revision 1.14 diff -C2 -d -r1.13 -r1.14 *** faq.txt 18 Jul 2003 23:25:49 -0000 1.13 --- faq.txt 19 Jul 2003 11:31:39 -0000 1.14 *************** *** 399,404 **** ! Why is the enable filter button is grayed out? ! --------------------------------------------------------- You need to have done these things to enable that button: --- 399,404 ---- ! Why is the enable filter button grayed out? ! ------------------------------------------- You need to have done these things to enable that button: From ta-meyer at ihug.co.nz Sun Jul 20 12:19:51 2003 From: ta-meyer at ihug.co.nz (Tony Meyer) Date: Sat Jul 19 19:20:29 2003 Subject: [Spambayes-checkins] website faq.txt,1.13,1.14 In-Reply-To: <1ED4ECF91CDED24C8D012BCF2B034F13026F86E1@its-xchg4.massey.ac.nz> Message-ID: <1ED4ECF91CDED24C8D012BCF2B034F130212AB5A@its-xchg4.massey.ac.nz> > ! Why is the enable filter button is grayed out? > ! --------------------------------------------------------- [...] > ! Why is the enable filter button grayed out? > ! ------------------------------------------- Good grief :) I don't know how I missed that; checking, even the version I replaced was wrong ("Why is the enable filter button is greyed out in Outlook"). Thanks, Tony From mhammond at users.sourceforge.net Sun Jul 20 01:15:05 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Sun Jul 20 03:15:09 2003 Subject: [Spambayes-checkins] spambayes/spambayes OptionsClass.py,1.3,1.4 Message-ID: Update of /cvsroot/spambayes/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv10083/spambayes Modified Files: OptionsClass.py Log Message: Fix [ 769346 ] Problems after deleting certain spam folder as implemented in [ 769981 ] Outlook plugin: allow user to change spam and unsure by Adam Walker. Index: OptionsClass.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/spambayes/OptionsClass.py,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** OptionsClass.py 9 Jul 2003 04:56:25 -0000 1.3 --- OptionsClass.py 20 Jul 2003 07:15:03 -0000 1.4 *************** *** 140,144 **** return False ! if type(self.value) in MultiContainerTypes: return self.is_valid_multiple(value) else: --- 140,144 ---- return False ! if self.multiple_values_allowed(): return self.is_valid_multiple(value) else: From mhammond at users.sourceforge.net Sun Jul 20 01:15:05 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Sun Jul 20 03:15:11 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 config.py,1.13,1.14 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv10083/Outlook2000 Modified Files: config.py Log Message: Fix [ 769346 ] Problems after deleting certain spam folder as implemented in [ 769981 ] Outlook plugin: allow user to change spam and unsure by Adam Walker. Index: config.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/config.py,v retrieving revision 1.13 retrieving revision 1.14 diff -C2 -d -r1.13 -r1.14 *** config.py 19 Jun 2003 23:47:40 -0000 1.13 --- config.py 20 Jul 2003 07:15:03 -0000 1.14 *************** *** 78,81 **** --- 78,84 ---- return str(self.value) + def multiple_values_allowed(self): + return type(self.value)==types.ListType + def is_valid_single(self, value): return value is None or \ From mhammond at users.sourceforge.net Sun Jul 20 01:54:05 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Sun Jul 20 03:54:10 2003 Subject: [Spambayes-checkins] spambayes/windows pop3proxy_service.py, 1.5, 1.6 Message-ID: Update of /cvsroot/spambayes/spambayes/windows In directory sc8-pr-cvs1:/tmp/cvs-serv14462 Modified Files: pop3proxy_service.py Log Message: Fix [ 761499 ] pop3proxy_service doesn't stop when shutdown from browser Also log exceptions if the server thread dies unexpectedly. Index: pop3proxy_service.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/windows/pop3proxy_service.py,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** pop3proxy_service.py 19 Jul 2003 05:37:13 -0000 1.5 --- pop3proxy_service.py 20 Jul 2003 07:54:03 -0000 1.6 *************** *** 41,44 **** --- 41,45 ---- import traceback import threading + import cStringIO # The spambayes imports we need. *************** *** 118,122 **** state = pop3proxy.state state.buildServerStrings() ! pop3proxy.main(state.servers, state.proxyPorts, state.uiPort, state.launchUI) if __name__=='__main__': --- 119,143 ---- state = pop3proxy.state state.buildServerStrings() ! try: ! try: ! pop3proxy.main(state.servers, state.proxyPorts, state.uiPort, state.launchUI) ! 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.SvcStop() if __name__=='__main__': From mhammond at users.sourceforge.net Sun Jul 20 07:31:16 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Sun Jul 20 09:31:19 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 manager.py,1.64,1.65 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv24653 Modified Files: manager.py Log Message: Minor cleanups: * Log message had strings back to front * Migrating pickle catches all errors rather than just IOError. * Assert we have a config before we attempt to use it! Index: manager.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/manager.py,v retrieving revision 1.64 retrieving revision 1.65 diff -C2 -d -r1.64 -r1.65 *** manager.py 8 Jul 2003 11:26:11 -0000 1.64 --- manager.py 20 Jul 2003 13:31:13 -0000 1.65 *************** *** 367,372 **** folder = msgstore_folder.GetOutlookItem() ! self.LogDebug(2, "Checking folder '%s' for our field '%s'" \ ! % (self.config.general.field_score_name,folder.Name.encode("mbcs", "replace"))) items = folder.Items item = items.GetFirst() --- 367,372 ---- folder = msgstore_folder.GetOutlookItem() ! self.LogDebug(2, "Checking folder '%s' for field '%s'" \ ! % (folder.Name.encode("mbcs", "replace"), self.config.general.field_score_name)) items = folder.Items item = items.GetFirst() *************** *** 516,522 **** try: old_config = cPickle.load(f) ! except IOError, details: print "FAILED to load old pickle" ! print details msg = "There was an error loading your old\r\n" \ "SpamBayes configuration file.\r\n\r\n" \ --- 516,522 ---- try: old_config = cPickle.load(f) ! except: print "FAILED to load old pickle" ! traceback.print_exc() msg = "There was an error loading your old\r\n" \ "SpamBayes configuration file.\r\n\r\n" \ *************** *** 602,608 **** def SaveConfig(self): print "Saving configuration ->", self.config_filename if self.verbose > 1: self.options.display() - assert self.config and self.options, "Have no config to save!" self.options.update_file(self.config_filename) --- 602,608 ---- def SaveConfig(self): print "Saving configuration ->", self.config_filename + assert self.config and self.options, "Have no config to save!" if self.verbose > 1: self.options.display() self.options.update_file(self.config_filename) From mhammond at users.sourceforge.net Sun Jul 20 07:37:03 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Sun Jul 20 09:37:07 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 addin.py, 1.72, 1.73 config.py, 1.14, 1.15 filter.py, 1.26, 1.27 tester.py, 1.8, 1.9 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv24828 Modified Files: addin.py config.py filter.py tester.py Log Message: Add a new filter option - "save_spam_info", default=True. If not set, then we don't attempt to save the message before moving it (meaning spam score and original folder are not saved). Option added mainly to see if it helps any of the "flagged as read" or "leaves duplicate message" bugs we see - but note that in some cases the message save would fail anyway, meaning this option was always implicit. Fix some other incremental training assumptions re this spam score - we assumed the score existed, but as mentioned above, this was always a dangerous assumption. Incremental training should still be effective when the spam score can/is not be saved. Updated the test suite to test all of this (which was a good thing as it caught me out a couple of times!) Index: addin.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/addin.py,v retrieving revision 1.72 retrieving revision 1.73 diff -C2 -d -r1.72 -r1.73 *** addin.py 14 Jul 2003 10:53:27 -0000 1.72 --- addin.py 20 Jul 2003 13:37:00 -0000 1.73 *************** *** 153,161 **** # Whew - we seem to have all the COM support we need - let's rock! # Function to filter a message - note it is a msgstore msg, not an # outlook one def ProcessMessage(msgstore_message, manager): manager.LogDebug(2, "ProcessMessage starting for", msgstore_message) ! if msgstore_message.GetField(manager.config.general.field_score_name) is not None: # Already seen this message - user probably moving it back # after incorrect classification. --- 153,178 ---- # Whew - we seem to have all the COM support we need - let's rock! + # Determine if we have ever seen a message before. If we have saved the spam + # field, then we know we have - but saving the spam field is an option (and may + # fail, depending on the message store). So if no spam field, we check if + # ever been trained on. + def HaveSeenMessage(msgstore_message, manager): + if msgstore_message.GetField(manager.config.general.field_score_name) is not None: + return True + # If the message has been trained on, we certainly have seen it before. + import train + if train.been_trained_as_ham(msgstore_message, manager) or \ + train.been_trained_as_spam(msgstore_message, manager): + return True + # I considered checking if the "save spam score" option is enabled - but + # even when enabled, this sometimes fails (IMAP, hotmail) + # Best we ca do not is to assume if it is read, we have seen it. + return msgstore_message.GetReadState() + # Function to filter a message - note it is a msgstore msg, not an # outlook one def ProcessMessage(msgstore_message, manager): manager.LogDebug(2, "ProcessMessage starting for", msgstore_message) ! if HaveSeenMessage(msgstore_message, manager): # Already seen this message - user probably moving it back # after incorrect classification. *************** *** 232,241 **** return msgstore_message = self.manager.message_store.GetMessage(item) ! prop = msgstore_message.GetField(self.manager.config.general.field_score_name) ! if prop is not None: import train ! trained_as_good = train.been_trained_as_ham(msgstore_message, self.manager) ! if self.manager.config.filter.spam_threshold > prop * 100 or \ ! trained_as_good: subject = item.Subject.encode("mbcs", "replace") print "Training on message '%s' - " % subject, --- 249,272 ---- return msgstore_message = self.manager.message_store.GetMessage(item) ! if HaveSeenMessage(msgstore_message, self.manager): ! # If the message has ever been previously trained as ham, then ! # we *must* train as spam (well, we must untrain, but re-training ! # makes sense. ! # If we haven't been trained, but the spam score on the message ! # if not inside our spam threshold, then we also train as spam ! # (hopefully moving closer towards the spam threshold.) ! ! # Assuming that rescoring is more expensive than checking if ! # previously trained, try and optimize. import train ! if train.been_trained_as_ham(msgstore_message, self.manager): ! need_train = True ! else: ! prop = msgstore_message.GetField(self.manager.config.general.field_score_name) ! # We may not have been able to save the score - re-score now ! if prop is None: ! prop = self.manager.score(msgstore_message) ! need_train = self.manager.config.filter.spam_threshold > prop * 100 ! if need_train: subject = item.Subject.encode("mbcs", "replace") print "Training on message '%s' - " % subject, *************** *** 244,249 **** else: # This shouldn't really happen, but strange shit does - # (and there are cases where it could given a big enough - # idiot at the other end of the mouse ) print "already was trained as spam" assert train.been_trained_as_spam(msgstore_message, self.manager) --- 275,278 ---- Index: config.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/config.py,v retrieving revision 1.14 retrieving revision 1.15 diff -C2 -d -r1.14 -r1.15 *** config.py 20 Jul 2003 07:15:03 -0000 1.14 --- config.py 20 Jul 2003 13:37:00 -0000 1.15 *************** *** 146,149 **** --- 146,153 ---- """Something useful.""", BOOLEAN, RESTORE), + ("save_spam_info", "Save spam score", True, + """Should the spam score and other information be saved in each message + as it is filtered or scored?""", + BOOLEAN, RESTORE), (FolderIDOption, "watch_folder_ids", "Folders to watch for new messages", [], Index: filter.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/filter.py,v retrieving revision 1.26 retrieving revision 1.27 diff -C2 -d -r1.26 -r1.27 *** filter.py 9 Jul 2003 07:51:42 -0000 1.26 --- filter.py 20 Jul 2003 13:37:00 -0000 1.27 *************** *** 31,45 **** try: try: ! # Save the score ! # Catch this exception, as failing to save the score need not ! # be fatal - it may still be possible to perform the move. ! msg.SetField(mgr.config.general.field_score_name, prob) ! # and the ID of the folder we were in when scored. ! # (but only if we want to perform all actions) ! # Note we must do this, and the Save, before the ! # filter, else the save will fail. ! if all_actions: ! msg.RememberMessageCurrentFolder() ! msg.Save() except pythoncom.com_error, (hr, msg, exc, arg_err): # This seems to happen for IMAP mails (0x800cccd3) --- 31,46 ---- try: try: ! if config.save_spam_info: ! # Save the score ! # Catch this exception, as failing to save the score need not ! # be fatal - it may still be possible to perform the move. ! msg.SetField(mgr.config.general.field_score_name, prob) ! # and the ID of the folder we were in when scored. ! # (but only if we want to perform all actions) ! # Note we must do this, and the Save, before the ! # filter, else the save will fail. ! if all_actions: ! msg.RememberMessageCurrentFolder() ! msg.Save() except pythoncom.com_error, (hr, msg, exc, arg_err): # This seems to happen for IMAP mails (0x800cccd3) Index: tester.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/tester.py,v retrieving revision 1.8 retrieving revision 1.9 diff -C2 -d -r1.8 -r1.9 *** tester.py 15 May 2003 23:18:12 -0000 1.8 --- tester.py 20 Jul 2003 13:37:00 -0000 1.9 *************** *** 207,210 **** --- 207,212 ---- WaitForFilters() spam_msg = driver.FindTestMessage(driver.folder_watch) + if spam_msg is None: + TestFailed("The message appears to have been filtered out of the watch folder") store_msg = driver.manager.message_store.GetMessage(spam_msg) need_untrain = True *************** *** 281,285 **** def TestHamFilter(driver): ! # Create a spam message in the Inbox - it should get immediately filtered msg, words = driver.CreateTestMessageInFolder(HAM, driver.folder_watch) # sleep to ensure filtering. --- 283,287 ---- def TestHamFilter(driver): ! # Create a ham message in the Inbox - it should not get filtered msg, words = driver.CreateTestMessageInFolder(HAM, driver.folder_watch) # sleep to ensure filtering. *************** *** 306,311 **** print "Created an unsure message, and saw it get filtered" ! def test(manager = None): ! # Run the tests - called from our plugin. driver = Driver(manager) manager.Save() # necessary after a full retrain --- 308,312 ---- print "Created an unsure message, and saw it get filtered" ! def run_tests(manager): driver = Driver(manager) manager.Save() # necessary after a full retrain *************** *** 318,321 **** --- 319,340 ---- TestHamFilter(driver) driver.CleanAllTestMessages() + + def test(manager = None): + # Run the tests - called from our plugin. + try: + # setup config to save info with the message, and test + print "Running tests with save_spam_info=True" + manager.config.filter.save_spam_info = True + run_tests(manager) + # do it again with the same config, just to prove we can. + print "Running them again with save_spam_info=True" + run_tests(manager) + # and with save_spam_info False. + print "Running tests with save_spam_info=False" + manager.config.filter.save_spam_info = False + run_tests(manager) + finally: + # Always restore configuration to how we started. + manager.LoadConfig() if __name__=='__main__': From mhammond at users.sourceforge.net Sun Jul 20 07:43:10 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Sun Jul 20 09:43:14 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000/docs configuration.html, 1.4, 1.5 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000/docs In directory sc8-pr-cvs1:/tmp/cvs-serv27282 Modified Files: configuration.html Log Message: Document the save_spam_info option. Index: configuration.html =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/docs/configuration.html,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** configuration.html 8 Jul 2003 10:53:17 -0000 1.4 --- configuration.html 20 Jul 2003 13:43:08 -0000 1.5 *************** *** 108,111 **** --- 108,130 ---- + [Filter]
    + + save_spam_info
    + + True, False
    + + True
    + + Determines if the spam score and + other information be saved in + each        message as it is + filtered or scored.  Note that if this option is disabled, then + the Recover From Spam + function may recover messages back to the Inbox rather than the folder + it was filtered on (as the originating folder is part of the spam + information saved.)
    + + + [General]
    From mhammond at users.sourceforge.net Sun Jul 20 08:24:59 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Sun Jul 20 10:25:02 2003 Subject: [Spambayes-checkins] spambayes/spambayes OptionsClass.py,1.4,1.5 Message-ID: Update of /cvsroot/spambayes/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv5448 Modified Files: OptionsClass.py Log Message: Allow spaces (but still no other whitespace characters) in option filenames Index: OptionsClass.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/spambayes/OptionsClass.py,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** OptionsClass.py 20 Jul 2003 07:15:03 -0000 1.4 --- OptionsClass.py 20 Jul 2003 14:24:57 -0000 1.5 *************** *** 684,688 **** PORT = r"[\d]+" EMAIL_ADDRESS = r"[\w\-\.]+@[\w\-\.]+" ! PATH = r"[\w\$\.\-~:\\/\*]+" VARIABLE_PATH = PATH + r"%" FILE = r"[\S]+" --- 684,688 ---- PORT = r"[\d]+" EMAIL_ADDRESS = r"[\w\-\.]+@[\w\-\.]+" ! PATH = r"[\w \$\.\-~:\\/\*]+" VARIABLE_PATH = PATH + r"%" FILE = r"[\S]+" From mhammond at users.sourceforge.net Sun Jul 20 08:25:44 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Sun Jul 20 10:25:47 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 config.py,1.15,1.16 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv5579 Modified Files: config.py Log Message: Add some simple filename tests. Index: config.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/config.py,v retrieving revision 1.15 retrieving revision 1.16 diff -C2 -d -r1.15 -r1.16 *** config.py 20 Jul 2003 13:37:00 -0000 1.15 --- config.py 20 Jul 2003 14:25:42 -0000 1.16 *************** *** 295,298 **** --- 295,307 ---- print "Filter_now from container is finally", c.filter.filter_now print "Only unread is", c.filter_now.only_unread + v = r"/foo/bar" + c.general.data_directory=v + if c.general.data_directory!=v: print "Bad directory!", c.general.data_directory + v = r"c:\test directory\some sub directory" + c.general.data_directory=v + if c.general.data_directory!=v: print "Bad directory!", c.general.data_directory + v = r"\\server\c$" + c.general.data_directory=v + if c.general.data_directory!=v: print "Bad directory!", c.general.data_directory options.update_file("delme.cfg") print "Created 'delme.cfg'" From mhammond at users.sourceforge.net Sun Jul 20 17:47:44 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Sun Jul 20 19:47:46 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000/dialogs AsyncDialog.py, 1.4, 1.5 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000/dialogs In directory sc8-pr-cvs1:/tmp/cvs-serv29051 Modified Files: AsyncDialog.py Log Message: *sob* - I can't believe this assertion is failing - the values are constants in the source code! How is it possible that: assert (abs((.3+.6+.1)-1.0)) < 0.001 (or for the other branch, .9+.1) fails? Index: AsyncDialog.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/dialogs/AsyncDialog.py,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** AsyncDialog.py 15 May 2003 22:52:01 -0000 1.4 --- AsyncDialog.py 20 Jul 2003 23:47:41 -0000 1.5 *************** *** 43,47 **** start_pos += prop self.stages.append(stage) ! assert(abs(start_pos-1.0)) < 0.001, "Proportions must add to 1.0" def _next_stage(self): --- 43,48 ---- start_pos += prop self.stages.append(stage) ! assert (abs(start_pos-1.0)) < 0.001, \ ! "Proportions must add to 1.0 (%g,%r)" % (start_pos, stages) def _next_stage(self): From tim.one at comcast.net Sun Jul 20 21:40:18 2003 From: tim.one at comcast.net (Tim Peters) Date: Sun Jul 20 20:40:51 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000/dialogs AsyncDialog.py, 1.4, 1.5 In-Reply-To: Message-ID: > Modified Files: > AsyncDialog.py > Log Message: > *sob* - I can't believe this assertion is failing - the values are > constants in the source code! How is it possible that: > > assert (abs((.3+.6+.1)-1.0)) < 0.001 > > (or for the other branch, .9+.1) fails? Heh. I stared at that when the original bug report was entered, and came away empty-handed. It's not possible! So I'm real curious too to see why it is . From ta-meyer at ihug.co.nz Mon Jul 21 13:49:06 2003 From: ta-meyer at ihug.co.nz (Tony Meyer) Date: Sun Jul 20 20:49:46 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000/dialogs AsyncDialog.py, 1.4, 1.5 In-Reply-To: <1ED4ECF91CDED24C8D012BCF2B034F13026F89F5@its-xchg4.massey.ac.nz> Message-ID: <1ED4ECF91CDED24C8D012BCF2B034F13026F2818@its-xchg4.massey.ac.nz> > > *sob* - I can't believe this assertion is failing - the values are > > constants in the source code! How is it possible that: > > > > assert (abs((.3+.6+.1)-1.0)) < 0.001 > > > > (or for the other branch, .9+.1) fails? > > Heh. I stared at that when the original bug report was > entered, and came away empty-handed. It's not possible! So > I'm real curious too to see why it is . It is possible in a non-English locale, though, right? Because 1.0 becomes 10, and 1,0 becomes (what English calls) 1.0, yes? (Well, here that would be 3+6+1-10 < 1, which is True, but I suspect the actual code is 0.3, 0.6, and 0.1, which becomes 30+60+10-10 < 1, which is False). I know that the last two people in the list said that they're in English, but maybe they're not and don't realise it? (this happened to someone I know who is almost in the Tim's sister category). =Tony Meyer From mhammond at skippinet.com.au Mon Jul 21 12:11:55 2003 From: mhammond at skippinet.com.au (Mark Hammond) Date: Sun Jul 20 21:12:04 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000/dialogs AsyncDialog.py, 1.4, 1.5 In-Reply-To: Message-ID: <000901c34f25$141dfe00$f502a8c0@eden> > Heh. I stared at that when the original bug report was > entered, and came > away empty-handed. It's not possible! So I'm real curious > too to see why > it is . Well I am sure glad it isn't me <0.1 wink> Thanks! Mark. From tim.one at comcast.net Sun Jul 20 22:45:56 2003 From: tim.one at comcast.net (Tim Peters) Date: Sun Jul 20 21:46:30 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000/dialogs AsyncDialog.py, 1.4, 1.5 In-Reply-To: <1ED4ECF91CDED24C8D012BCF2B034F13026F2818@its-xchg4.massey.ac.nz> Message-ID: [Tony Meyer] > It is possible in a non-English locale, though, right? Offhand I didn't think so, but I'm no locale expert. In locales that swap the God-given meanings of "." and ",", what I've always seen is bizarre tracebacks raising SyntaxError due to "invalid literals". > Because 1.0 becomes 10, In what locale would a period be interpreted as "multiply the integer to the left of the period by 10"? > and 1,0 becomes (what English calls) 1.0, yes? (Well, > here that would be 3+6+1-10 < 1, which is True, but I suspect the > actual code is 0.3, 0.6, and 0.1, which becomes 30+60+10-10 < 1, > which is False). Now a period means "multiply the integer to the *right* of the period by 100"?! You're making this up as you go along . > I know that the last two people in the list said that they're in > English, but maybe they're not and don't realise it? (this happened > to someone I know who is almost in the Tim's sister category). Anything's possible with Windows users ... From mhammond at users.sourceforge.net Sun Jul 20 19:55:16 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Sun Jul 20 21:55:19 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 manager.py,1.65,1.66 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv14322 Modified Files: manager.py Log Message: Work better with a unicode data directory. Index: manager.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/manager.py,v retrieving revision 1.65 retrieving revision 1.66 diff -C2 -d -r1.65 -r1.66 *** manager.py 20 Jul 2003 13:31:13 -0000 1.65 --- manager.py 21 Jul 2003 01:55:13 -0000 1.66 *************** *** 21,24 **** --- 21,32 ---- True, False = 1, 0 + # Notes on Unicode directory names + # You will have much more success with extended characters in + # directory names using Python 2.3. + try: + filesystem_encoding = sys.getfilesystemencoding() + except AttributeError: + filesystem_encoding = "mbcs" + # Work out our "application directory", which is # the directory of our main .py/.dll/.exe file we *************** *** 73,77 **** "'spambayes.Options' was imported too early" global bayes_classifier, bayes_tokenize, bayes_storage ! os.environ["BAYESCUSTOMIZE"] = ini_filename from spambayes import classifier from spambayes.tokenizer import tokenize --- 81,86 ---- "'spambayes.Options' was imported too early" global bayes_classifier, bayes_tokenize, bayes_storage ! # ini_filename is Unicode, but environ not unicode aware ! os.environ["BAYESCUSTOMIZE"] = ini_filename.encode(filesystem_encoding) from spambayes import classifier from spambayes.tokenizer import tokenize *************** *** 157,166 **** db_extension = ".db" def open_bayes(self): ! return bayes_storage.DBDictClassifier(self.bayes_filename) def close_bayes(self, bayes): bayes.db.close() bayes.dbm.close() def open_mdb(self): ! return bsddb.hashopen(self.mdb_filename) def new_mdb(self): try: --- 166,178 ---- db_extension = ".db" def open_bayes(self): ! # bsddb doesn't handle unicode filenames yet :( ! fname = self.bayes_filename.encode(filesystem_encoding) ! return bayes_storage.DBDictClassifier(fname) def close_bayes(self, bayes): bayes.db.close() bayes.dbm.close() def open_mdb(self): ! fname = self.mdb_filename.encode(filesystem_encoding) ! return bsddb.hashopen(fname) def new_mdb(self): try: *************** *** 201,204 **** --- 213,225 ---- value = self.config.general.data_directory if value: + # until I know otherwise, config files are ASCII - but our + # file system is unicode to some degree. + # (do config files support encodings at all?) + # Assume the file system encoding for file names! + try: + value = value.decode(filesystem_encoding) + except AttributeError: # May already be Unicode + pass + assert type(value) == type(u''), "%r should be a unicode" % value try: if not os.path.isdir(value): *************** *** 216,220 **** else: self.data_directory = self.windows_data_directory ! # Now we have the data directory, migrate anything needed, and load # any config from it. --- 237,241 ---- else: self.data_directory = self.windows_data_directory ! # Now we have the data directory, migrate anything needed, and load # any config from it. *************** *** 418,427 **** # file-not-found handled gracefully by storage. bayes = self.db_manager.open_bayes() ! print "Loaded bayes database from '%s'" % (self.db_manager.bayes_filename,) except: self.ReportFatalStartupError("Failed to load bayes database") try: message_db = self.db_manager.open_mdb() ! print "Loaded message database from '%s'" % (self.db_manager.mdb_filename,) except IOError: pass --- 439,450 ---- # file-not-found handled gracefully by storage. bayes = self.db_manager.open_bayes() ! fname = self.db_manager.bayes_filename.encode("mbcs", "replace") ! print "Loaded bayes database from '%s'" % (fname,) except: self.ReportFatalStartupError("Failed to load bayes database") try: message_db = self.db_manager.open_mdb() ! fname = self.db_manager.mdb_filename.encode("mbcs", "replace") ! print "Loaded message database from '%s'" % (fname,) except IOError: pass *************** *** 601,605 **** def SaveConfig(self): ! print "Saving configuration ->", self.config_filename assert self.config and self.options, "Have no config to save!" if self.verbose > 1: --- 624,628 ---- def SaveConfig(self): ! print "Saving configuration ->", self.config_filename.encode("mbcs", "replace") assert self.config and self.options, "Have no config to save!" if self.verbose > 1: From ta-meyer at ihug.co.nz Mon Jul 21 16:00:12 2003 From: ta-meyer at ihug.co.nz (Tony Meyer) Date: Sun Jul 20 23:00:51 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000/dialogs AsyncDialog.py, 1.4, 1.5 In-Reply-To: <1ED4ECF91CDED24C8D012BCF2B034F13026F8A16@its-xchg4.massey.ac.nz> Message-ID: <1ED4ECF91CDED24C8D012BCF2B034F130212AB6F@its-xchg4.massey.ac.nz> > > Because 1.0 becomes 10, > > In what locale would a period be interpreted as "multiply the > integer to the left of the period by 10"? It doesn't seem to multiply, just ignore the '.'. For example: >>> locale.setlocale(locale.LC_NUMERIC, "German") 'German_Germany.1252' >>> s = locale.atof("3,14") >>> s 3.1400000000000001 >>> s = locale.atof("3.14") >>> s 314.0 >>> Back when I was playing around with locale settings & Outlook to try and sort out the problems there, I noticed this behaviour in code without the locale.atof calls as well. I can't remember how to reproduce it now, though ;) classifier.LN2 kept ending up as >0, though, and the call there is just "LN2 = math.log(2)". =Tony Meyer From tim.one at comcast.net Mon Jul 21 00:12:17 2003 From: tim.one at comcast.net (Tim Peters) Date: Sun Jul 20 23:12:49 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000/dialogs AsyncDialog.py, 1.4, 1.5 In-Reply-To: <1ED4ECF91CDED24C8D012BCF2B034F130212AB6F@its-xchg4.massey.ac.nz> Message-ID: [Tony Meyer] > It doesn't seem to multiply, just ignore the '.'. For example: > >>> locale.setlocale(locale.LC_NUMERIC, "German") > >>> 'German_Germany.1252' s = locale.atof("3,14") s > 3.1400000000000001 > >>> s = locale.atof("3.14") > >>> s > 314.0 > >>> Damn foreigners . If this somehow managed to be in effect while the .py files were getting compiled, then I suppose stages = ("Training", .9), ("Saving", .1) could turn into (in God's spelling) stages = ("Training", 9.0), ("Saving", 1.0) but then also assert (abs(start_pos-1.0)) < 0.001, would turn into assert (abs(start_pos-10.0)) < 1.0, \ and that still would be true (asserting 0.0 < 1.0). So maybe it's that stages = ("Training", .3), ("Saving", .1), ("Scoring", .6) turns into stages = ("Training", 3.0), ("Saving", 1.0), ("Scoring", 4.0) But same thing in the end: they sum to 10.0, and the difference is again 0. > Back when I was playing around with locale settings & Outlook to try > and sort out the problems there, I noticed this behaviour in code > without the locale.atof calls as well. I can't remember how to > reproduce it now, though ;) classifier.LN2 kept ending up as >0, > though, and the call there is just "LN2 = math.log(2)". classifier.LN2 should be > 0; log(2) ~= 0.69. From mhammond at users.sourceforge.net Sun Jul 20 21:14:58 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Sun Jul 20 23:15:00 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000/sandbox mapi_driver.py, 1.1, 1.2 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000/sandbox In directory sc8-pr-cvs1:/tmp/cvs-serv24408 Modified Files: mapi_driver.py Log Message: Ignore errors when enumerating stores. Index: mapi_driver.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/sandbox/mapi_driver.py,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** mapi_driver.py 23 Nov 2002 02:57:46 -0000 1.1 --- mapi_driver.py 21 Jul 2003 03:14:55 -0000 1.2 *************** *** 46,59 **** (eid_tag, eid), (name_tag, name), (def_store_tag, def_store) = row # Open the store. ! store = self.session.OpenMsgStore( ! 0, # no parent window ! eid, # msg store to open ! None, # IID; accept default IMsgStore ! # need write access to add score fields ! mapi.MDB_WRITE | ! # we won't send or receive email ! mapi.MDB_NO_MAIL | ! mapi.MAPI_DEFERRED_ERRORS) ! yield store, name, def_store def _FindSubfolder(self, store, folder, find_name): --- 46,65 ---- (eid_tag, eid), (name_tag, name), (def_store_tag, def_store) = row # Open the store. ! try: ! store = self.session.OpenMsgStore( ! 0, # no parent window ! eid, # msg store to open ! None, # IID; accept default IMsgStore ! # need write access to add score fields ! mapi.MDB_WRITE | ! # we won't send or receive email ! mapi.MDB_NO_MAIL | ! mapi.MAPI_DEFERRED_ERRORS) ! yield store, name, def_store ! except pythoncom.com_error, details: ! print "Error opening message store" ! print details ! print "Ignoring this store" ! def _FindSubfolder(self, store, folder, find_name): From mhammond at users.sourceforge.net Sun Jul 20 21:50:43 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Sun Jul 20 23:50:47 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 msgstore.py,1.49,1.50 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv29259 Modified Files: msgstore.py Log Message: Rationalize code that creates a message object. Add IsFilterCandidate() method to a message object to determine if this is a message we should try and filter. Add similar concept to the Message generators used by the training ops. Index: msgstore.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/msgstore.py,v retrieving revision 1.49 retrieving revision 1.50 diff -C2 -d -r1.49 -r1.50 *** msgstore.py 14 Jul 2003 10:52:51 -0000 1.49 --- msgstore.py 21 Jul 2003 03:50:41 -0000 1.50 *************** *** 46,50 **** # return a folder object with the parent, or None raise NotImplementedError ! def GetMessageGenerator(self, folder): # Return a generator of MsgStoreMsg objects for the folder raise NotImplementedError --- 46,50 ---- # return a folder object with the parent, or None raise NotImplementedError ! def GetMessageGenerator(self, folder, only_filter_candidates = True): # Return a generator of MsgStoreMsg objects for the folder raise NotImplementedError *************** *** 77,80 **** --- 77,85 ---- # Copy the message to a folder. raise NotImplementedError + def IsFilterCandidate(self): + # Return True if this is a message that should be checked for spam + # Return False if it should be ignored (eg, user-composed message, + # undeliverable report, meeting request etc. + raise NotImplementedError # Our MAPI implementation *************** *** 328,341 **** print GetCOMExceptionString(details) return None - prop_ids = PR_PARENT_ENTRYID, PR_SEARCH_KEY, PR_MESSAGE_FLAGS mapi_object = self._OpenEntry(message_id) ! hr, data = mapi_object.GetProps(prop_ids,0) ! folder_eid = data[0][1] ! searchkey = data[1][1] ! flags = data[2][1] ! folder_id = message_id[0], folder_eid ! folder = MAPIMsgStoreFolder(self, folder_id, ! "Unknown - temp message", -1) ! return MAPIMsgStoreMsg(self, folder, message_id, searchkey, flags) _MapiTypeMap = { --- 333,339 ---- print GetCOMExceptionString(details) return None mapi_object = self._OpenEntry(message_id) ! hr, data = mapi_object.GetProps(MAPIMsgStoreMsg.message_init_props,0) ! return MAPIMsgStoreMsg(self, data) _MapiTypeMap = { *************** *** 401,415 **** return self.msgstore.outlook.Session.GetFolderFromID(hex_item_id, hex_store_id) ! def GetMessageGenerator(self): folder = self.OpenEntry() table = folder.GetContentsTable(0) ! # Limit ourselves to IPM.Note objects - ie, messages. ! restriction = (mapi.RES_PROPERTY, # a property restriction ! (mapi.RELOP_GE, # >= ! PR_MESSAGE_CLASS_A, # of the this prop ! (PR_MESSAGE_CLASS_A, "IPM.Note"))) # with this value ! table.Restrict(restriction, 0) ! prop_ids = PR_ENTRYID, PR_SEARCH_KEY, PR_MESSAGE_FLAGS ! table.SetColumns(prop_ids, 0) while 1: # Getting 70 at a time was the random number that gave best --- 399,413 ---- return self.msgstore.outlook.Session.GetFolderFromID(hex_item_id, hex_store_id) ! def GetMessageGenerator(self, only_filter_candidates = True): folder = self.OpenEntry() table = folder.GetContentsTable(0) ! if only_filter_candidates: ! # Limit ourselves to IPM.Note objects - ie, messages. ! restriction = (mapi.RES_PROPERTY, # a property restriction ! (mapi.RELOP_GE, # >= ! PR_MESSAGE_CLASS_A, # of the this prop ! (PR_MESSAGE_CLASS_A, "IPM.Note"))) # with this value ! table.Restrict(restriction, 0) ! table.SetColumns(MAPIMsgStoreMsg.message_init_props, 0) while 1: # Getting 70 at a time was the random number that gave best *************** *** 419,425 **** break for row in rows: ! item_id = self.id[0], row[0][1] # assume in same store as folder! ! yield MAPIMsgStoreMsg(self.msgstore, self, ! item_id, row[1][1], row[2][1]) def GetNewUnscoredMessageGenerator(self, scoreFieldName): --- 417,425 ---- break for row in rows: ! # Our restriction helped, but may not have filtered ! # every message we don't want to touch. ! msg = MAPIMsgStoreMsg(self.msgstore, row) ! if not only_filter_candidates or msg.IsFilterCandidate(): ! yield msg def GetNewUnscoredMessageGenerator(self, scoreFieldName): *************** *** 431,436 **** field_id = PROP_TAG( PT_DOUBLE, PROP_ID(resolve_ids[0])) # Setup the properties we want to read. ! prop_ids = PR_ENTRYID, PR_SEARCH_KEY, PR_MESSAGE_FLAGS ! table.SetColumns(prop_ids, 0) # Set up the restriction # Need to check message-flags --- 431,435 ---- field_id = PROP_TAG( PT_DOUBLE, PROP_ID(resolve_ids[0])) # Setup the properties we want to read. ! table.SetColumns(MAPIMsgStoreMsg.message_init_props, 0) # Set up the restriction # Need to check message-flags *************** *** 458,471 **** break for row in rows: ! item_id = self.id[0], row[0][1] # assume in same store as folder! ! yield MAPIMsgStoreMsg(self.msgstore, self, ! item_id, row[1][1], row[2][1]) class MAPIMsgStoreMsg(MsgStoreMsg): ! def __init__(self, msgstore, folder, entryid, searchkey, flags): ! self.folder = folder self.msgstore = msgstore self.mapi_object = None ! self.id = entryid self.subject = None # Search key is the only reliable thing after a move/copy operation --- 457,484 ---- break for row in rows: ! yield MAPIMsgStoreMsg(self.msgstore, row) class MAPIMsgStoreMsg(MsgStoreMsg): ! # All the properties we must initialize a message with. ! # These include all the IDs we need, parent IDs, any properties needed ! # to determine if this is a "filterable" message, etc ! message_init_props = (PR_ENTRYID, PR_STORE_ENTRYID, PR_SEARCH_KEY, ! PR_PARENT_ENTRYID, # folder ID ! PR_MESSAGE_CLASS_A) # 'IPM.Note' etc ! ! def __init__(self, msgstore, prop_row): self.msgstore = msgstore self.mapi_object = None ! ! # prop_row is a single mapi property row, with fields as above. ! tag, eid = prop_row[0] # ID ! tag, store_eid = prop_row[1] ! tag, searchkey = prop_row[2] ! tag, parent_eid = prop_row[3] ! tag, msgclass = prop_row[4] ! ! self.id = store_eid, eid ! self.folder_id = store_eid, parent_eid ! self.msgclass = msgclass self.subject = None # Search key is the only reliable thing after a move/copy operation *************** *** 475,479 **** # Thus, searchkey is the only reliable long-lived message key. self.searchkey = searchkey - self.flags = flags # flags are unreliable - they change! self.dirty = False --- 488,491 ---- *************** *** 509,512 **** --- 521,531 ---- return self.msgstore.outlook.Session.GetItemFromID(hex_item_id, hex_store_id) + def IsFilterCandidate(self): + # We don't attempt to filter: + # * Non-mail items + # Later we would like to add: + # * Messages that have never been sent (ie, user-composed) + return self.msgclass.lower().startswith("ipm.note") + def _GetPropFromStream(self, prop_id): try: *************** *** 809,813 **** "asking me to move a dirty message - later saves will fail!" dest_folder = self.msgstore._OpenEntry(folder.id) ! source_folder = self.msgstore._OpenEntry(self.folder.id) flags = 0 if isMove: flags |= MESSAGE_MOVE --- 828,832 ---- "asking me to move a dirty message - later saves will fail!" dest_folder = self.msgstore._OpenEntry(folder.id) ! source_folder = self.msgstore._OpenEntry(self.folder_id) flags = 0 if isMove: flags |= MESSAGE_MOVE *************** *** 824,828 **** # the item, and set the store_id to the dest folder. self.id = None ! self.folder = None def MoveTo(self, folder): --- 843,847 ---- # the item, and set the store_id to the dest folder. self.id = None ! self.folder_id = None def MoveTo(self, folder): *************** *** 833,848 **** def GetFolder(self): # return a folder object with the parent, or None ! folder = self.msgstore._OpenEntry(self.id) ! prop_ids = PR_PARENT_ENTRYID, ! hr, data = folder.GetProps(prop_ids,0) ! # Put parent ids together ! parent_eid = data[0][1] ! parent_id = self.id[0], parent_eid ! parent = self.msgstore._OpenEntry(parent_id) ! # Finally get the display name. ! hr, data = folder.GetProps((PR_DISPLAY_NAME_A,), 0) ! name = data[0][1] ! count = parent.GetContentsTable(0).GetRowCount(0) ! return MAPIMsgStoreFolder(self.msgstore, parent_id, name, count) def RememberMessageCurrentFolder(self): --- 852,858 ---- def GetFolder(self): # return a folder object with the parent, or None ! folder_id = (mapi.HexFromBin(self.folder_id[0]), ! mapi.HexFromBin(self.folder_id[1])) ! return self.msgstore.GetFolder(folder_id) def RememberMessageCurrentFolder(self): *************** *** 882,889 **** from win32com.client import Dispatch outlook = Dispatch("Outlook.Application") ! eid = outlook.Session.GetDefaultFolder(constants.olFolderInbox).EntryID ! store = MAPIMsgStore() ! for folder in store.GetFolderGenerator([eid,], True): print folder for msg in folder.GetMessageGenerator(): --- 892,899 ---- from win32com.client import Dispatch outlook = Dispatch("Outlook.Application") ! inbox = outlook.Session.GetDefaultFolder(constants.olFolderInbox) ! folder_id = inbox.Parent.StoreID, inbox.EntryID store = MAPIMsgStore() ! for folder in store.GetFolderGenerator([folder_id,], True): print folder for msg in folder.GetMessageGenerator(): From mhammond at users.sourceforge.net Sun Jul 20 21:53:54 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Sun Jul 20 23:53:58 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 addin.py,1.73,1.74 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv29486 Modified Files: addin.py Log Message: Only filter mail items. Fix: 690418: Non mail items filtered by Outlook 719586: Cannot View Spam Cues for Undeliverable Reports Index: addin.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/addin.py,v retrieving revision 1.73 retrieving revision 1.74 diff -C2 -d -r1.73 -r1.74 *** addin.py 20 Jul 2003 13:37:00 -0000 1.73 --- addin.py 21 Jul 2003 03:53:52 -0000 1.74 *************** *** 174,177 **** --- 174,181 ---- def ProcessMessage(msgstore_message, manager): manager.LogDebug(2, "ProcessMessage starting for", msgstore_message) + if not msgstore_message.IsFilterCandidate(): + manager.LogDebug(1, "Skipping message '%s' - we don't filter ones like that!") + return + if HaveSeenMessage(msgstore_message, manager): # Already seen this message - user probably moving it back *************** *** 249,252 **** --- 253,259 ---- return msgstore_message = self.manager.message_store.GetMessage(item) + if not msgstore_message.IsFilterCandidate(): + self.manager.LogDebug(1, "Not training message '%s' - we don't filter ones like that!") + return if HaveSeenMessage(msgstore_message, self.manager): # If the message has ever been previously trained as ham, then *************** *** 687,692 **** for i in range(sel.Count): item = sel.Item(i+1) ! if item.Class == constants.olMail: ! msgstore_message = self.manager.message_store.GetMessage(item) ret.append(msgstore_message) --- 694,699 ---- for i in range(sel.Count): item = sel.Item(i+1) ! msgstore_message = self.manager.message_store.GetMessage(item) ! if msgstore_message and msgstore_message.IsFilterCandidate(): ret.append(msgstore_message) From mhammond at users.sourceforge.net Sun Jul 20 23:13:30 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Mon Jul 21 01:13:32 2003 Subject: [Spambayes-checkins] spambayes/spambayes Version.py,1.5,1.6 Message-ID: Update of /cvsroot/spambayes/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv6532 Modified Files: Version.py Log Message: Preparing for a new Outlook binary. Index: Version.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/spambayes/Version.py,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** Version.py 7 Jul 2003 00:09:27 -0000 1.5 --- Version.py 21 Jul 2003 05:13:27 -0000 1.6 *************** *** 19,25 **** }, "Outlook" : { ! "Version": 0.3, ! "BinaryVersion": 003, ! "Description": "SpamBayes Outlook Addin Beta1", "Date": "July 2003", "Full Description": "%(Description)s, version %(Version)s (%(Date)s)", --- 19,25 ---- }, "Outlook" : { ! "Version": 0.4, ! "BinaryVersion": 004, ! "Description": "SpamBayes Outlook Addin (beta)", "Date": "July 2003", "Full Description": "%(Description)s, version %(Version)s (%(Date)s)", From mhammond at users.sourceforge.net Sun Jul 20 23:15:54 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Mon Jul 21 01:15:57 2003 Subject: [Spambayes-checkins] spambayes/spambayes Version.py,1.6,1.7 Message-ID: Update of /cvsroot/spambayes/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv6797 Modified Files: Version.py Log Message: I'm pretty sure I didn't intend octal constants <0.7 wink> Index: Version.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/spambayes/Version.py,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -d -r1.6 -r1.7 *** Version.py 21 Jul 2003 05:13:27 -0000 1.6 --- Version.py 21 Jul 2003 05:15:52 -0000 1.7 *************** *** 20,24 **** "Outlook" : { "Version": 0.4, ! "BinaryVersion": 004, "Description": "SpamBayes Outlook Addin (beta)", "Date": "July 2003", --- 20,24 ---- "Outlook" : { "Version": 0.4, ! "BinaryVersion": 0.4, "Description": "SpamBayes Outlook Addin (beta)", "Date": "July 2003", From mhammond at users.sourceforge.net Mon Jul 21 00:22:57 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Mon Jul 21 02:23:00 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000/installer spambayes_addin.iss, 1.3, 1.4 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000/installer In directory sc8-pr-cvs1:/tmp/cvs-serv15842 Modified Files: spambayes_addin.iss Log Message: Addin version 0.4 Inno setup v4, to give macros - so we can check Outlook is actually installed! Index: spambayes_addin.iss =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/installer/spambayes_addin.iss,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** spambayes_addin.iss 2 Jul 2003 01:22:54 -0000 1.3 --- spambayes_addin.iss 21 Jul 2003 06:22:55 -0000 1.4 *************** *** 1,10 **** ; ! ; Inno Setup 3.x setup file for the Spambayes Outlook Addin ; [Setup] AppName=Spambayes Outlook Addin ! AppVerName=Spambayes Outlook Addin 0.3 ! AppVersion=0.3 DefaultDirName={pf}\Spambayes Outlook Addin DefaultGroupName=Spambayes Outlook Addin --- 1,10 ---- ; ! ; Inno Setup 4.x setup file for the Spambayes Outlook Addin ; [Setup] AppName=Spambayes Outlook Addin ! AppVerName=Spambayes Outlook Addin 0.4 ! AppVersion=0.4 DefaultDirName={pf}\Spambayes Outlook Addin DefaultGroupName=Spambayes Outlook Addin *************** *** 19,21 **** --- 19,33 ---- [UninstallDelete] Type: filesandordirs; Name: "{app}\support" + + [Code] + function InitializeSetup(): Boolean; + begin + Result := true; + if not RegKeyExists( HKCU, 'Software\Microsoft\Office\Outlook') then + begin + MsgBox('Outlook appears to not be installed' + #13 + #13 + 'Please correct this and restart the installation', + mbInformation, MB_OK); + Result := false; + end; + end; From anadelonbrin at users.sourceforge.net Mon Jul 21 19:19:09 2003 From: anadelonbrin at users.sourceforge.net (Tony Meyer) Date: Mon Jul 21 21:19:13 2003 Subject: [Spambayes-checkins] website applications.ht, 1.13, 1.14 download.ht, 1.10, 1.11 Message-ID: Update of /cvsroot/spambayes/website In directory sc8-pr-cvs1:/tmp/cvs-serv16787 Modified Files: applications.ht download.ht Log Message: Update info about Outlook plugin installer to 004. Index: applications.ht =================================================================== RCS file: /cvsroot/spambayes/website/applications.ht,v retrieving revision 1.13 retrieving revision 1.14 diff -C2 -d -r1.13 -r1.14 *** applications.ht 7 Jul 2003 04:16:41 -0000 1.13 --- applications.ht 22 Jul 2003 01:19:07 -0000 1.14 *************** *** 27,33 ****

    Availability

    !

    Mark has packaged together an installer for the plugin. You can download it from his website. ! This is currently at version 003.

    Download the alpha4 release.

    Alternatively, you can use CVS to get the code - go to the CVS page on the project's sourceforge site for more.

    --- 27,33 ----

    Availability

    !

    Mark has packaged together an installer for the plugin. You can download it from his website. ! This is currently at version 004.

    Download the alpha4 release.

    Alternatively, you can use CVS to get the code - go to the CVS page on the project's sourceforge site for more.

    Index: download.ht =================================================================== RCS file: /cvsroot/spambayes/website/download.ht,v retrieving revision 1.10 retrieving revision 1.11 diff -C2 -d -r1.10 -r1.11 *** download.ht 7 Jul 2003 04:16:41 -0000 1.10 --- download.ht 22 Jul 2003 01:19:07 -0000 1.11 *************** *** 23,29 ****

    Binary Releases

    Outlook Plugin

    !

    Mark has packaged together an installer for the plugin. You can download it from his website. ! This is currently at version 003.

    Other

    --- 23,29 ----

    Binary Releases

    Outlook Plugin

    !

    Mark has packaged together an installer for the plugin. You can download it from his website. ! This is currently at version 004.

    Other

    From mhammond at users.sourceforge.net Tue Jul 22 00:02:55 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Tue Jul 22 02:02:58 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 msgstore.py,1.50,1.51 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv22612 Modified Files: msgstore.py Log Message: GetNewUnscoredMessageGenerator() still returned non-mail items - which isn't actually a problem, as the only caller of this then calls ProcessMessage, which does check this. However, this method should call the filter anyway. Index: msgstore.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/msgstore.py,v retrieving revision 1.50 retrieving revision 1.51 diff -C2 -d -r1.50 -r1.51 *** msgstore.py 21 Jul 2003 03:50:41 -0000 1.50 --- msgstore.py 22 Jul 2003 06:02:52 -0000 1.51 *************** *** 457,461 **** break for row in rows: ! yield MAPIMsgStoreMsg(self.msgstore, row) class MAPIMsgStoreMsg(MsgStoreMsg): --- 457,463 ---- break for row in rows: ! msg = MAPIMsgStoreMsg(self.msgstore, row) ! if msg.IsFilterCandidate(): ! yield msg class MAPIMsgStoreMsg(MsgStoreMsg): From mhammond at users.sourceforge.net Tue Jul 22 00:03:44 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Tue Jul 22 02:03:48 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000/docs configuration.html, 1.5, 1.6 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000/docs In directory sc8-pr-cvs1:/tmp/cvs-serv23035 Modified Files: configuration.html Log Message: Remove some stray spaces. Note in the docs that changing the read state of spam etc does not change the outlook newmail icon. Index: configuration.html =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/docs/configuration.html,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** configuration.html 20 Jul 2003 13:43:08 -0000 1.5 --- configuration.html 22 Jul 2003 06:03:42 -0000 1.6 *************** *** 118,122 **** Determines if the spam score and other information be saved in ! each        message as it is filtered or scored.  Note that if this option is disabled, then the Recover From Spam --- 118,122 ---- Determines if the spam score and other information be saved in ! each message as it is filtered or scored.  Note that if this option is disabled, then the Recover From Spam *************** *** 153,157 **** button.  By default, the 'Read' state of the message is not changed, but this allows you to explicitly change it to either 'read' ! or 'unread'.
    --- 153,159 ---- button.  By default, the 'Read' state of the message is not changed, but this allows you to explicitly change it to either 'read' ! or 'unread'.  Note that even if you set new messages to Read, the new mail icon in the ! taskbar does still indicates there is new mail.
    *************** *** 170,174 **** the 'Read' state of the message is not changed, but this allows you to ! explicitly change it to either 'read' or 'unread'. --- 172,178 ---- the 'Read' state of the message is not changed, but this allows you to ! explicitly change it to either 'read' or 'unread'.  See the notes ! about the new mail icon above.
    ! From mhammond at users.sourceforge.net Tue Jul 22 00:09:05 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Tue Jul 22 02:09:09 2003 Subject: [Spambayes-checkins] spambayes/spambayes Version.py,1.7,1.8 Message-ID: Update of /cvsroot/spambayes/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv23626 Modified Files: Version.py Log Message: Binary version 005 (but the plugin itself it still 0.4 - nothing has changed!) Index: Version.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/spambayes/Version.py,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -d -r1.7 -r1.8 *** Version.py 21 Jul 2003 05:15:52 -0000 1.7 --- Version.py 22 Jul 2003 06:09:03 -0000 1.8 *************** *** 20,24 **** "Outlook" : { "Version": 0.4, ! "BinaryVersion": 0.4, "Description": "SpamBayes Outlook Addin (beta)", "Date": "July 2003", --- 20,24 ---- "Outlook" : { "Version": 0.4, ! "BinaryVersion": 0.5, "Description": "SpamBayes Outlook Addin (beta)", "Date": "July 2003", From mhammond at users.sourceforge.net Tue Jul 22 00:25:18 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Tue Jul 22 02:25:21 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000/installer spambayes_addin.iss, 1.4, 1.5 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000/installer In directory sc8-pr-cvs1:/tmp/cvs-serv25921 Modified Files: spambayes_addin.iss Log Message: Version 5 of the binary, and give the user the option of continuing installation if we don't think Outlook is installed. Index: spambayes_addin.iss =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/installer/spambayes_addin.iss,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** spambayes_addin.iss 21 Jul 2003 06:22:55 -0000 1.4 --- spambayes_addin.iss 22 Jul 2003 06:25:16 -0000 1.5 *************** *** 5,10 **** [Setup] AppName=Spambayes Outlook Addin ! AppVerName=Spambayes Outlook Addin 0.4 ! AppVersion=0.4 DefaultDirName={pf}\Spambayes Outlook Addin DefaultGroupName=Spambayes Outlook Addin --- 5,10 ---- [Setup] AppName=Spambayes Outlook Addin ! AppVerName=Spambayes Outlook Addin 0.5 ! AppVersion=0.5 DefaultDirName={pf}\Spambayes Outlook Addin DefaultGroupName=Spambayes Outlook Addin *************** *** 26,32 **** if not RegKeyExists( HKCU, 'Software\Microsoft\Office\Outlook') then begin ! MsgBox('Outlook appears to not be installed' + #13 + #13 + 'Please correct this and restart the installation', ! mbInformation, MB_OK); ! Result := false; end; end; --- 26,36 ---- if not RegKeyExists( HKCU, 'Software\Microsoft\Office\Outlook') then begin ! Result := MsgBox( ! 'Outlook appears to not be installed.' + #13 + #13 + ! 'This addin only works with Microsoft Outlook 2000 and later - it' + #13 + ! 'does not work with Outlook express.' + #13 + #13 + ! 'If you know that Outlook is installed, you may with to continue.' + #13 + #13 + ! 'Continue with installation?', ! mbConfirmation, MB_YESNO) = idYes; end; end; From anadelonbrin at users.sourceforge.net Tue Jul 22 00:36:04 2003 From: anadelonbrin at users.sourceforge.net (Tony Meyer) Date: Tue Jul 22 02:36:07 2003 Subject: [Spambayes-checkins] website applications.ht, 1.14, 1.15 download.ht, 1.11, 1.12 Message-ID: Update of /cvsroot/spambayes/website In directory sc8-pr-cvs1:/tmp/cvs-serv27771 Modified Files: applications.ht download.ht Log Message: Update info about Outlook plugin installer to 005, as we frantically try to keep up with Mark ;) Index: applications.ht =================================================================== RCS file: /cvsroot/spambayes/website/applications.ht,v retrieving revision 1.14 retrieving revision 1.15 diff -C2 -d -r1.14 -r1.15 *** applications.ht 22 Jul 2003 01:19:07 -0000 1.14 --- applications.ht 22 Jul 2003 06:36:02 -0000 1.15 *************** *** 27,33 ****

    Availability

    !

    Mark has packaged together an installer for the plugin. You can download it from his website. ! This is currently at version 004.

    Download the alpha4 release.

    Alternatively, you can use CVS to get the code - go to the CVS page on the project's sourceforge site for more.

    --- 27,33 ----

    Availability

    !

    Mark has packaged together an installer for the plugin. You can download it from his website. ! This is currently at version 005.

    Download the alpha4 release.

    Alternatively, you can use CVS to get the code - go to the CVS page on the project's sourceforge site for more.

    Index: download.ht =================================================================== RCS file: /cvsroot/spambayes/website/download.ht,v retrieving revision 1.11 retrieving revision 1.12 diff -C2 -d -r1.11 -r1.12 *** download.ht 22 Jul 2003 01:19:07 -0000 1.11 --- download.ht 22 Jul 2003 06:36:02 -0000 1.12 *************** *** 23,29 ****

    Binary Releases

    Outlook Plugin

    !

    Mark has packaged together an installer for the plugin. You can download it from his website. ! This is currently at version 004.

    Other

    --- 23,29 ----

    Binary Releases

    Outlook Plugin

    !

    Mark has packaged together an installer for the plugin. You can download it from his website. ! This is currently at version 005.

    Other

    From anadelonbrin at users.sourceforge.net Tue Jul 22 00:37:50 2003 From: anadelonbrin at users.sourceforge.net (Tony Meyer) Date: Tue Jul 22 02:37:53 2003 Subject: [Spambayes-checkins] website windows.ht,1.20,1.21 Message-ID: Update of /cvsroot/spambayes/website In directory sc8-pr-cvs1:/tmp/cvs-serv28064 Modified Files: windows.ht Log Message: Missed a bit (they might as well upgrade all the way). Index: windows.ht =================================================================== RCS file: /cvsroot/spambayes/website/windows.ht,v retrieving revision 1.20 retrieving revision 1.21 diff -C2 -d -r1.20 -r1.21 *** windows.ht 3 Jul 2003 01:54:52 -0000 1.20 --- windows.ht 22 Jul 2003 06:37:48 -0000 1.21 *************** *** 12,16 **** plug-in installer. A separate Python installation is not necessary.

    !

    Note that all users who installed version 002 of the plugin are recommended to upgrade to the 003 release.

    The Outlook add-in was developed mostly using Outlook 2000 on Windows --- 12,16 ---- plug-in installer. A separate Python installation is not necessary.

    !

    Note that all users who installed version 002 of the plugin are recommended to upgrade to the 005 release.

    The Outlook add-in was developed mostly using Outlook 2000 on Windows From richiehindle at users.sourceforge.net Tue Jul 22 01:13:45 2003 From: richiehindle at users.sourceforge.net (Richie Hindle) Date: Tue Jul 22 03:13:49 2003 Subject: [Spambayes-checkins] spambayes/spambayes Options.py,1.57,1.58 Message-ID: Update of /cvsroot/spambayes/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv32318 Modified Files: Options.py Log Message: You can once again specify local addresses as well as ports for the pop3proxy to listen on. Index: Options.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/spambayes/Options.py,v retrieving revision 1.57 retrieving revision 1.58 diff -C2 -d -r1.57 -r1.58 *** Options.py 7 Jul 2003 21:00:01 -0000 1.57 --- Options.py 22 Jul 2003 07:13:43 -0000 1.58 *************** *** 666,670 **** client to use this port. If there are multiple servers, you must specify the same number of ports as servers, separated by commas.""", ! PORT, DO_NOT_RESTORE), ("cache_use_gzip", "Use gzip", False, --- 666,670 ---- client to use this port. If there are multiple servers, you must specify the same number of ports as servers, separated by commas.""", ! SERVER, DO_NOT_RESTORE), ("cache_use_gzip", "Use gzip", False, From mhammond at users.sourceforge.net Tue Jul 22 07:36:15 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Tue Jul 22 09:36:19 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 addin.py,1.74,1.75 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv22034 Modified Files: addin.py Log Message: While we are printing versions, Python gets a go. Index: addin.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/addin.py,v retrieving revision 1.74 retrieving revision 1.75 diff -C2 -d -r1.74 -r1.75 *** addin.py 21 Jul 2003 03:53:52 -0000 1.74 --- addin.py 22 Jul 2003 13:36:12 -0000 1.75 *************** *** 853,861 **** # manager is what munges sys.path for us. from spambayes.Version import get_version_string ! print "%s starting (with engine %s)..." % \ (get_version_string("Outlook"), get_version_string()) major, minor, spack, platform, ver_str = win32api.GetVersionEx() ! print "On Windows version %d.%d.%d (%s)" % \ (major, minor, spack, ver_str) self.explorers_events = None # create at OnStartupComplete --- 853,862 ---- # manager is what munges sys.path for us. from spambayes.Version import get_version_string ! print "%s starting (with engine %s)" % \ (get_version_string("Outlook"), get_version_string()) major, minor, spack, platform, ver_str = win32api.GetVersionEx() ! print "on Windows %d.%d.%d (%s)" % \ (major, minor, spack, ver_str) + print "using Python", sys.version self.explorers_events = None # create at OnStartupComplete From mhammond at users.sourceforge.net Tue Jul 22 07:37:41 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Tue Jul 22 09:37:46 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 msgstore.py,1.51,1.52 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv22143 Modified Files: msgstore.py Log Message: Paul Moore reports that not specifying USER_DEFERRED_ERRORS solves his "unread flag" issue - and we certainly don't need that flag here, so out it goes. I'd love to hear this fixes *all* such reported bugs, but I wont hold my breath. Index: msgstore.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/msgstore.py,v retrieving revision 1.51 retrieving revision 1.52 diff -C2 -d -r1.51 -r1.52 *** msgstore.py 22 Jul 2003 06:02:52 -0000 1.51 --- msgstore.py 22 Jul 2003 13:37:38 -0000 1.52 *************** *** 822,826 **** # There are also some issues with the "unread flag" that fiddling this # save code may fix. ! self.mapi_object.SaveChanges(mapi.KEEP_OPEN_READWRITE | USE_DEFERRED_ERRORS) self.dirty = False --- 822,828 ---- # There are also some issues with the "unread flag" that fiddling this # save code may fix. ! # It seems that *not* specifying mapi.MAPI_DEFERRED_ERRORS solves alot ! # of said problems though! So we don't! ! self.mapi_object.SaveChanges(mapi.KEEP_OPEN_READWRITE) self.dirty = False From mhammond at users.sourceforge.net Tue Jul 22 08:01:44 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Tue Jul 22 10:01:47 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 msgstore.py,1.52,1.53 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv26084 Modified Files: msgstore.py Log Message: Fix [ 693387 ] user-composed messages are filtered. Check the message flag for the "unsent" bit. Index: msgstore.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/msgstore.py,v retrieving revision 1.52 retrieving revision 1.53 diff -C2 -d -r1.52 -r1.53 *** msgstore.py 22 Jul 2003 13:37:38 -0000 1.52 --- msgstore.py 22 Jul 2003 14:01:41 -0000 1.53 *************** *** 96,99 **** --- 96,101 ---- MESSAGE_MOVE = 0x1 # from MAPIdefs.h MSGFLAG_READ = 0x1 # from MAPIdefs.h + MSGFLAG_UNSENT = 0x00000008 + MYPR_BODY_HTML_A = 0x1013001e # magic MYPR_BODY_HTML_W = 0x1013001f # ditto *************** *** 467,471 **** message_init_props = (PR_ENTRYID, PR_STORE_ENTRYID, PR_SEARCH_KEY, PR_PARENT_ENTRYID, # folder ID ! PR_MESSAGE_CLASS_A) # 'IPM.Note' etc def __init__(self, msgstore, prop_row): --- 469,475 ---- message_init_props = (PR_ENTRYID, PR_STORE_ENTRYID, PR_SEARCH_KEY, PR_PARENT_ENTRYID, # folder ID ! PR_MESSAGE_CLASS_A, # 'IPM.Note' etc ! PR_MESSAGE_FLAGS, #unsent, from_me ! ) def __init__(self, msgstore, prop_row): *************** *** 479,482 **** --- 483,487 ---- tag, parent_eid = prop_row[3] tag, msgclass = prop_row[4] + tag, flags = prop_row[5] self.id = store_eid, eid *************** *** 490,493 **** --- 495,499 ---- # Thus, searchkey is the only reliable long-lived message key. self.searchkey = searchkey + self.is_unsent = flags & MSGFLAG_UNSENT self.dirty = False *************** *** 526,532 **** # We don't attempt to filter: # * Non-mail items - # Later we would like to add: # * Messages that have never been sent (ie, user-composed) ! return self.msgclass.lower().startswith("ipm.note") def _GetPropFromStream(self, prop_id): --- 532,538 ---- # We don't attempt to filter: # * Non-mail items # * Messages that have never been sent (ie, user-composed) ! return self.msgclass.lower().startswith("ipm.note") and \ ! not self.is_unsent def _GetPropFromStream(self, prop_id): From mhammond at users.sourceforge.net Tue Jul 22 07:29:59 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Tue Jul 22 10:19:16 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000/dialogs AsyncDialog.py, 1.5, 1.6 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000/dialogs In directory sc8-pr-cvs1:/tmp/cvs-serv19758 Modified Files: AsyncDialog.py Log Message: %g is pretty useless - use %r instead. Of course, this just adds to the mystery. The traceback says: AssertionError: Proportions must add to 1.0 (1,(('', 1.0),)) Meaning that the failing call is in the dialog __init__ function: self.set_stages( (("", 1.0),) ) So, it seems that abs(0.0+1.0-1.0) > 0.001. uh huh... Index: AsyncDialog.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/dialogs/AsyncDialog.py,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** AsyncDialog.py 20 Jul 2003 23:47:41 -0000 1.5 --- AsyncDialog.py 22 Jul 2003 13:29:57 -0000 1.6 *************** *** 44,48 **** self.stages.append(stage) assert (abs(start_pos-1.0)) < 0.001, \ ! "Proportions must add to 1.0 (%g,%r)" % (start_pos, stages) def _next_stage(self): --- 44,48 ---- self.stages.append(stage) assert (abs(start_pos-1.0)) < 0.001, \ ! "Proportions must add to 1.0 (%r,%r)" % (start_pos, stages) def _next_stage(self): From tim.one at comcast.net Tue Jul 22 12:05:29 2003 From: tim.one at comcast.net (Tim Peters) Date: Tue Jul 22 11:06:02 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000/dialogs AsyncDialog.py, 1.5, 1.6 In-Reply-To: Message-ID: > Modified Files: > AsyncDialog.py > Log Message: > %g is pretty useless - use %r instead. Alas, it won't help much. %g would have displayed any difference from 1.0 up to the sixth significant digit: >>> "%g" % 1.000001 # difference in 7th digit suppressed '1' >>> "%g" % 1.00001 # difference in 6th digit survives '1.00001' >>> So if %g displayed "1", the true number is certainly less than 0.001 away from 1.0. %r will tell us more, of course, but I'm afraid it will only tell us there are more zeroes at the end. So I remain baffled. Maybe abs() is broken on the OP's box?! "<"? The mind boggles. From mhammond at users.sourceforge.net Tue Jul 22 22:35:37 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Wed Jul 23 00:35:41 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 msgstore.py,1.53,1.54 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv18004 Modified Files: msgstore.py Log Message: Remove the old code from NormalizeID, and clean up some comments. Index: msgstore.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/msgstore.py,v retrieving revision 1.53 retrieving revision 1.54 diff -C2 -d -r1.53 -r1.54 *** msgstore.py 22 Jul 2003 14:01:41 -0000 1.53 --- msgstore.py 23 Jul 2003 04:35:35 -0000 1.54 *************** *** 127,131 **** def __init__(self, outlook = None): self.outlook = outlook ! cwd = os.getcwd() mapi.MAPIInitialize(None) logonFlags = (mapi.MAPI_NO_MAIL | --- 127,131 ---- def __init__(self, outlook = None): self.outlook = outlook ! cwd = os.getcwd() # remember the cwd - mapi changes it under us! mapi.MAPIInitialize(None) logonFlags = (mapi.MAPI_NO_MAIL | *************** *** 221,245 **** return store.OpenEntry(item_id, iid, flags) ! # Given an ID, normalize it into a (store_id, item_id) binary tuple. ! # item_id may be: ! # - Simple hex EID, in wich case default store ID is assumed. ! # - Tuple of (None, hex_eid), in which case default store assumed. ! # - Tuple of (hex_store_id, hex_id) def NormalizeID(self, item_id): ! if type(item_id)==type(()): ! store_id, item_id = item_id ! item_id = mapi.BinFromHex(item_id) ! if store_id is None: ! # store_id=None was a "backwards compat" hack no longer ! # need - it can go once we are *sure* we dont need it ;) ! assert False, "We expect fully qualified IDs" ! store_id = self.default_store_bin_eid ! else: ! store_id = mapi.BinFromHex(store_id) ! return store_id, item_id ! # See above - this branch can die (I think ;) ! assert type(item_id) in [type(''), type(u'')], "What kind of ID is '%r'?" % (item_id,) ! assert False, "We expect fully qualified IDs" ! return self.default_store_bin_eid, mapi.BinFromHex(item_id) def _GetSubFolderIter(self, folder): --- 221,230 ---- return store.OpenEntry(item_id, iid, flags) ! # Normalize an "external" hex ID to an internal binary ID. def NormalizeID(self, item_id): ! assert type(item_id)==type(()), \ ! "Item IDs must be a tuple (not a %r)" % item_id ! store_id, entry_id = item_id ! return mapi.BinFromHex(store_id), mapi.BinFromHex(entry_id) def _GetSubFolderIter(self, folder): *************** *** 286,289 **** --- 271,275 ---- # Return a single folder given the ID. try: + # See if this is an Outlook folder item sid = mapi.BinFromHex(folder_id.StoreID) eid = mapi.BinFromHex(folder_id.EntryID) *************** *** 493,497 **** # Outlook client provides no such (easy/obvious) way # (ie, someone would need to really want to change it ) ! # Thus, searchkey is the only reliable long-lived message key. self.searchkey = searchkey self.is_unsent = flags & MSGFLAG_UNSENT --- 479,483 ---- # Outlook client provides no such (easy/obvious) way # (ie, someone would need to really want to change it ) ! # Thus, searchkey is our long-lived message key. self.searchkey = searchkey self.is_unsent = flags & MSGFLAG_UNSENT *************** *** 557,561 **** ret = "" if got_val == mapi.MAPI_E_NOT_FOUND: ! pass # No body for this message. elif got_val == mapi.MAPI_E_NOT_ENOUGH_MEMORY: # Too big for simple properties - get via a stream --- 543,547 ---- ret = "" if got_val == mapi.MAPI_E_NOT_FOUND: ! pass # No property for this message. elif got_val == mapi.MAPI_E_NOT_ENOUGH_MEMORY: # Too big for simple properties - get via a stream *************** *** 756,760 **** # property is the same for two objects, assume that these # objects use the same name-to-identifier mapping. ! # [MarkH: Note MAPIUUID object are supported and hashable] # XXX If the SpamProb (Hammie, whatever) property is passed in as an --- 742,746 ---- # property is the same for two objects, assume that these # objects use the same name-to-identifier mapping. ! # [MarkH: MAPIUID objects are supported and hashable] # XXX If the SpamProb (Hammie, whatever) property is passed in as an *************** *** 819,824 **** (is_read, self.GetField(PR_MESSAGE_FLAGS)) - # unsent may also be useful - MSGFLAG_UNSENT bit in PR_MESSAGE_FLAGS . - def Save(self): assert self.dirty, "asking me to save a clean message!" --- 805,808 ---- *************** *** 834,838 **** def _DoCopyMove(self, folder, isMove): - ## self.mapi_object = None # release the COM pointer assert not self.dirty, \ "asking me to move a dirty message - later saves will fail!" --- 818,821 ---- From mhammond at users.sourceforge.net Wed Jul 23 00:12:24 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Wed Jul 23 02:12:27 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000/sandbox dump_props.py, 1.7, 1.8 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000/sandbox In directory sc8-pr-cvs1:/tmp/cvs-serv31825 Modified Files: dump_props.py Log Message: Allow '-l' to fetch huge properties (just to prove we could) Index: dump_props.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/sandbox/dump_props.py,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -d -r1.7 -r1.8 *** dump_props.py 23 Nov 2002 02:57:46 -0000 1.7 --- dump_props.py 23 Jul 2003 06:12:21 -0000 1.8 *************** *** 27,35 **** else: name = tag ! ret.append((name, val)) return ret ! def DumpItemProps(item, shorten): ! for prop_name, prop_val in GetAllProperties(item): prop_repr = repr(prop_val) if shorten: --- 27,54 ---- else: name = tag ! ret.append((name, tag, val)) return ret ! def GetLargeProperty(item, prop_tag): ! prop_tag = PROP_TAG(PT_BINARY, PROP_ID(prop_tag)) ! stream = item.OpenProperty(prop_tag, ! pythoncom.IID_IStream, ! 0, 0) ! chunks = [] ! while 1: ! chunk = stream.Read(4096) ! if not chunk: ! break ! chunks.append(chunk) ! return "".join(chunks) ! ! def DumpItemProps(item, shorten, get_large_props): ! for prop_name, prop_tag, prop_val in GetAllProperties(item): ! if get_large_props and \ ! PROP_TYPE(prop_tag)==PT_ERROR and \ ! prop_val in [mapi.MAPI_E_NOT_ENOUGH_MEMORY,'MAPI_E_NOT_ENOUGH_MEMORY']: ! # Use magic to get a large property. ! prop_val = GetLargeProperty(item, prop_tag) ! prop_repr = repr(prop_val) if shorten: *************** *** 37,45 **** print "%-20s: %s" % (prop_name, prop_repr) ! def DumpProps(driver, mapi_folder, subject, include_attach, shorten): hr, data = mapi_folder.GetProps( (PR_DISPLAY_NAME_A,), 0) name = data[0][1] for item in driver.GetItemsWithValue(mapi_folder, PR_SUBJECT_A, subject): ! DumpItemProps(item, shorten) if include_attach: print --- 56,64 ---- print "%-20s: %s" % (prop_name, prop_repr) ! def DumpProps(driver, mapi_folder, subject, include_attach, shorten, get_large): hr, data = mapi_folder.GetProps( (PR_DISPLAY_NAME_A,), 0) name = data[0][1] for item in driver.GetItemsWithValue(mapi_folder, PR_SUBJECT_A, subject): ! DumpItemProps(item, shorten, get_large) if include_attach: print *************** *** 50,54 **** print "Dumping attachment (PR_ATTACH_NUM=%d)" % (attach_num,) attach = item.OpenAttach(attach_num, None, mapi.MAPI_DEFERRED_ERRORS) ! DumpItemProps(attach, shorten) def usage(driver): --- 69,73 ---- print "Dumping attachment (PR_ATTACH_NUM=%d)" % (attach_num,) attach = item.OpenAttach(attach_num, None, mapi.MAPI_DEFERRED_ERRORS) ! DumpItemProps(attach, shorten, get_large) def usage(driver): *************** *** 59,62 **** --- 78,82 ---- -s - Shorten long property values. -a - Include attachments + -l - Get the data for very large properties -n - Show top-level folder names and exit *************** *** 74,78 **** import getopt try: ! opts, args = getopt.getopt(sys.argv[1:], "af:sn") except getopt.error, e: print e --- 94,98 ---- import getopt try: ! opts, args = getopt.getopt(sys.argv[1:], "af:snl") except getopt.error, e: print e *************** *** 83,86 **** --- 103,107 ---- shorten = False + get_large_props = False include_attach = False for opt, opt_val in opts: *************** *** 91,94 **** --- 112,117 ---- elif opt == "-a": include_attach = True + elif opt == "-l": + get_large_props = True elif opt == "-n": driver.DumpTopLevelFolders() *************** *** 114,118 **** sys.exit(1) ! DumpProps(driver, folder, subject, include_attach, shorten) if __name__=='__main__': --- 137,141 ---- sys.exit(1) ! DumpProps(driver, folder, subject, include_attach, shorten, get_large_props) if __name__=='__main__': From mhammond at users.sourceforge.net Wed Jul 23 00:20:42 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Wed Jul 23 02:20:46 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 msgstore.py,1.54,1.55 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv32410 Modified Files: msgstore.py Log Message: multipart/signed messages could still screw us - particularly when they are multi-part inside the signed multi-part portion. We now recurse through all parts of the message, collecting all text/* portions, combining them together. (Irony: the mail this failed on was from a SpamBayes user [asking for yet another feature]) Also a bug in how attachment properties were fetched - if the body was "large", we attempted to get the "large property" from the mail object itself, rather than the attachment. Thus, these utility functions have been move to global function taking any MAPI object. Index: msgstore.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/msgstore.py,v retrieving revision 1.54 retrieving revision 1.55 diff -C2 -d -r1.54 -r1.55 *** msgstore.py 23 Jul 2003 04:35:35 -0000 1.54 --- msgstore.py 23 Jul 2003 06:20:40 -0000 1.55 *************** *** 334,337 **** --- 334,371 ---- } + def GetPropFromStream(mapi_object, prop_id): + try: + stream = mapi_object.OpenProperty(prop_id, + pythoncom.IID_IStream, + 0, 0) + chunks = [] + while 1: + chunk = stream.Read(4096) + if not chunk: + break + chunks.append(chunk) + return "".join(chunks) + except pythoncom.com_error, d: + print "Error getting property from stream", d + return "" + + def GetPotentiallyLargeStringProp(mapi_object, prop_id, row): + got_tag, got_val = row + if PROP_TYPE(got_tag) == PT_ERROR: + ret = "" + if got_val == mapi.MAPI_E_NOT_FOUND: + pass # No property for this message. + elif got_val == mapi.MAPI_E_NOT_ENOUGH_MEMORY: + # Too big for simple properties - get via a stream + ret = GetPropFromStream(mapi_object, prop_id) + else: + tag_name = mapiutil.GetPropTagName(prop_id) + err_string = mapiutil.GetScodeString(got_val) + print "Warning - failed to get property %s: %s" % (tag_name, + err_string) + else: + ret = got_val + return ret + class MAPIMsgStoreFolder(MsgStoreMsg): def __init__(self, msgstore, id, name, count): *************** *** 522,558 **** not self.is_unsent - def _GetPropFromStream(self, prop_id): - try: - stream = self.mapi_object.OpenProperty(prop_id, - pythoncom.IID_IStream, - 0, 0) - chunks = [] - while 1: - chunk = stream.Read(4096) - if not chunk: - break - chunks.append(chunk) - return "".join(chunks) - except pythoncom.com_error, d: - print "Error getting property from stream", d - return "" - def _GetPotentiallyLargeStringProp(self, prop_id, row): ! got_tag, got_val = row ! if PROP_TYPE(got_tag) == PT_ERROR: ! ret = "" ! if got_val == mapi.MAPI_E_NOT_FOUND: ! pass # No property for this message. ! elif got_val == mapi.MAPI_E_NOT_ENOUGH_MEMORY: ! # Too big for simple properties - get via a stream ! ret = self._GetPropFromStream(prop_id) ! else: ! tag_name = mapiutil.GetPropTagName(prop_id) ! err_string = mapiutil.GetScodeString(got_val) ! print "Warning - failed to get property %s: %s" % (tag_name, ! err_string) ! else: ! ret = got_val ! return ret def _GetMessageText(self): --- 556,561 ---- not self.is_unsent def _GetPotentiallyLargeStringProp(self, prop_id, row): ! return GetPotentiallyLargeStringProp(self.mapi_object, prop_id, row) def _GetMessageText(self): *************** *** 625,630 **** prop_ids = (PR_ATTACH_DATA_BIN,) hr, data = attach.GetProps(prop_ids, 0) ! attach_body = self._GetPotentiallyLargeStringProp( ! prop_ids[0], data[0]) # What we seem to have here now is a *complete* multi-part # mime message - that Outlook must have re-constituted on --- 628,632 ---- prop_ids = (PR_ATTACH_DATA_BIN,) hr, data = attach.GetProps(prop_ids, 0) ! attach_body = GetPotentiallyLargeStringProp(attach, prop_ids[0], data[0]) # What we seem to have here now is a *complete* multi-part # mime message - that Outlook must have re-constituted on *************** *** 635,641 **** import email msg = email.message_from_string(attach_body) ! assert msg.is_multipart() ! sub = msg.get_payload(0) ! body = sub.get_payload() return "%s\n%s\n%s" % (headers, html, body) --- 637,657 ---- import email msg = email.message_from_string(attach_body) ! assert msg.is_multipart(), "Should be multi-part: %r" % attach_body ! # reduce down all sub messages, collecting all text/ subtypes. ! # (we could make a distinction between text and html, but ! # it is all joined together by this method anyway.) ! def collect_text_parts(msg): ! collected = '' ! if msg.is_multipart(): ! for sub in msg.get_payload(): ! collected += collect_text_parts(sub) ! else: ! if msg.get_content_maintype()=='text': ! collected += msg.get_payload() ! else: ! #print "skipping content type", msg.get_content_type() ! pass ! return collected ! body = collect_text_parts(msg) return "%s\n%s\n%s" % (headers, html, body) From anadelonbrin at users.sourceforge.net Wed Jul 23 02:39:29 2003 From: anadelonbrin at users.sourceforge.net (Tony Meyer) Date: Wed Jul 23 04:39:33 2003 Subject: [Spambayes-checkins] website faq.txt,1.14,1.15 Message-ID: Update of /cvsroot/spambayes/website In directory sc8-pr-cvs1:/tmp/cvs-serv19300 Modified Files: faq.txt Log Message: Add a FAQ about that little envelope icon that bothers so many people. Index: faq.txt =================================================================== RCS file: /cvsroot/spambayes/website/faq.txt,v retrieving revision 1.14 retrieving revision 1.15 diff -C2 -d -r1.14 -r1.15 *** faq.txt 19 Jul 2003 11:31:39 -0000 1.14 --- faq.txt 23 Jul 2003 08:39:27 -0000 1.15 *************** *** 413,416 **** --- 413,432 ---- + How can I get rid of the envelope tray icon for spam? + ----------------------------------------------------- + + This is a very difficult thing to do, because Outlook does not expose the hooks + that are necessary to cleanly do this (feel free to write to Microsoft and tell + them that they should correct this). This means that even if you have set + SpamBayes to mark spam as read, the envelope tray icon will not vanish. + + Although there is code available that provides a method to delete this icon, + it doesn't let us determine whether there is other unread mail as well, which + means that we do not know whether we should delete the icon or not. + + Until someone comes up with a clever solution for all of this, you'll have to + put up with the little envelope, sorry. + + Using Spambayes =============== From mhammond at users.sourceforge.net Wed Jul 23 05:02:14 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Wed Jul 23 07:02:18 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000/dialogs AsyncDialog.py, 1.6, 1.7 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000/dialogs In directory sc8-pr-cvs1:/tmp/cvs-serv6693 Modified Files: AsyncDialog.py Log Message: Anything that could fail should be done before we screw with the dialog control state, just so the dialog doesn't look completely broken. Index: AsyncDialog.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/dialogs/AsyncDialog.py,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -d -r1.6 -r1.7 *** AsyncDialog.py 22 Jul 2003 13:29:57 -0000 1.6 --- AsyncDialog.py 23 Jul 2003 11:02:12 -0000 1.7 *************** *** 149,152 **** --- 149,157 ---- self.progress.request_stop() else: + # Do anything likely to fail before we screw around with the + # control states - this way the dialog doesn't look as 'dead' + progress=_Progress(self) + # Now screw around with the control states, restored when + # the thread terminates. for id in self.disable_while_running_ids: self.GetDlgItem(id).EnableWindow(0) *************** *** 173,177 **** # back to the program :) import threading ! t = threading.Thread(target=thread_target, args =(self.GetSafeHwnd(), _Progress(self))) t.start() --- 178,182 ---- # back to the program :) import threading ! t = threading.Thread(target=thread_target, args =(self.GetSafeHwnd(), progress)) t.start() From mhammond at users.sourceforge.net Wed Jul 23 05:43:31 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Wed Jul 23 07:43:34 2003 Subject: [Spambayes-checkins] website faq.txt,1.15,1.16 Message-ID: Update of /cvsroot/spambayes/website In directory sc8-pr-cvs1:/tmp/cvs-serv12185 Modified Files: faq.txt Log Message: Add a link from the "set messages unread" section to the "envelope icon" (at least I hope so - the build process failed for me) Also add a "how can I configure for delete" FAQ I get in mail alot. Index: faq.txt =================================================================== RCS file: /cvsroot/spambayes/website/faq.txt,v retrieving revision 1.15 retrieving revision 1.16 diff -C2 -d -r1.15 -r1.16 *** faq.txt 23 Jul 2003 08:39:27 -0000 1.15 --- faq.txt 23 Jul 2003 11:43:29 -0000 1.16 *************** *** 316,321 **** ----------------------------------------------------- ! The 002 installer for the binary had a number of problems with various ! versions of Outlook/Windows. However, to our knowledge, the 003 installer should work with any combination of Windows/Outlook versions. Please let us know if this is not the case. The `troubleshooting guide`_ for the Outlook --- 316,321 ---- ----------------------------------------------------- ! Previous versions of the binary had a number of problems with various ! versions of Outlook/Windows. However, to our knowledge, the current version should work with any combination of Windows/Outlook versions. Please let us know if this is not the case. The `troubleshooting guide`_ for the Outlook *************** *** 335,351 **** ---------------------------------------------------------------------------- ! It should, yes. There haven't been any problems reported using that ! combination. ! Can mail marked as spam automatically be marked as read? -------------------------------------------------------- ! This is a 'hidden' feature in the 003 release of the binary (also alpha3 ! source release and current CVS). Details about how to enable this feature can be found in the "configuration.html" file in the "docs" directory in the folder Spambayes was installed to. You can also set up mail that is trained using the "Delete as spam" button to be marked as read, rather than ! all mail classified as spam. Outlook forgets all training/configuration when I quit and start again --- 335,353 ---- ---------------------------------------------------------------------------- ! Yes. Can mail marked as spam automatically be marked as read? -------------------------------------------------------- ! This is a 'hidden' feature in the post 003 releases of the binary (also post ! alpha3 source releases and CVS). Details about how to enable this feature can be found in the "configuration.html" file in the "docs" directory in the folder Spambayes was installed to. You can also set up mail that is trained using the "Delete as spam" button to be marked as read, rather than ! all mail classified as spam. However, you should also see the ! `envelope icon question`_. ! ! .. _`envelope icon question`: #how-can-I-get-rid-of-the-envelope-tray-icon-for-spam ! Outlook forgets all training/configuration when I quit and start again *************** *** 427,431 **** Until someone comes up with a clever solution for all of this, you'll have to put up with the little envelope, sorry. ! Using Spambayes --- 429,443 ---- Until someone comes up with a clever solution for all of this, you'll have to put up with the little envelope, sorry. ! ! ! How can I configure SpamBayes to delete spam rather than moving it? ! ------------------------------------------------------------------- ! Sorry, but you can't. However, Outlook has an excellent "auto-archive" ! facility which can be used to the same effect - simply configure ! auto-archive to periodically delete your Spam folder. ! ! It is recommended that you configure auto-complete to keep at least a ! few days of Spam around, should the SpamBayes database become corrupt and ! require you to perform a full re-train. Using Spambayes From montanaro at users.sourceforge.net Wed Jul 23 09:30:17 2003 From: montanaro at users.sourceforge.net (Skip Montanaro) Date: Wed Jul 23 11:30:19 2003 Subject: [Spambayes-checkins] website/scripts/ht2html SpamBayesFAQGenerator.py, NONE, 1.1 Message-ID: Update of /cvsroot/spambayes/website/scripts/ht2html In directory sc8-pr-cvs1:/tmp/cvs-serv16650 Added Files: SpamBayesFAQGenerator.py Log Message: docutils emits utf-8 so we have to generate html with that as the charset --- NEW FILE: SpamBayesFAQGenerator.py --- #! /usr/bin/env python """Minor tweak for faq""" from SpamBayesGenerator import SpamBayesGenerator class SpamBayesFAQGenerator(SpamBayesGenerator): def get_charset(self): return 'utf-8' From montanaro at users.sourceforge.net Wed Jul 23 09:32:57 2003 From: montanaro at users.sourceforge.net (Skip Montanaro) Date: Wed Jul 23 11:33:00 2003 Subject: [Spambayes-checkins] website Makefile,1.4,1.5 Message-ID: Update of /cvsroot/spambayes/website In directory sc8-pr-cvs1:/tmp/cvs-serv17000 Modified Files: Makefile Log Message: hackery to whack the docutils-generated html into an ht file Index: Makefile =================================================================== RCS file: /cvsroot/spambayes/website/Makefile,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** Makefile 17 Jun 2003 22:01:37 -0000 1.4 --- Makefile 23 Jul 2003 15:32:55 -0000 1.5 *************** *** 7,8 **** --- 7,21 ---- $(TARGETS): links.h + + # hackery to whack the faq into ht2html... + + DUHTML = html.py + faq.ht : faq.txt + echo "Title: SpamBayes FAQ" > faq.ht + echo "Author-Email: SpamBayes@python.org" >> faq.ht + echo "Author: SpamBayes" >> faq.ht + echo "" >> faq.ht + $(DUHTML) faq.txt | sed -e '1,//d' -e '/<\/body>/,$$d' >> faq.ht + + faq.html : faq.ht + ./scripts/ht2html/ht2html.py -f -s SpamBayesFAQGenerator -r . ./faq.ht From montanaro at users.sourceforge.net Wed Jul 23 09:32:57 2003 From: montanaro at users.sourceforge.net (Skip Montanaro) Date: Wed Jul 23 11:33:04 2003 Subject: [Spambayes-checkins] website/scripts make.rules,1.3,1.4 Message-ID: Update of /cvsroot/spambayes/website/scripts In directory sc8-pr-cvs1:/tmp/cvs-serv17000/scripts Modified Files: make.rules Log Message: hackery to whack the docutils-generated html into an ht file Index: make.rules =================================================================== RCS file: /cvsroot/spambayes/website/scripts/make.rules,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** make.rules 5 Jun 2003 15:14:31 -0000 1.3 --- make.rules 23 Jul 2003 15:32:55 -0000 1.4 *************** *** 43,47 **** SCRIPTDIR = $(ROOT_DIR)/scripts HT2HTML = $(SCRIPTDIR)/ht2html/ht2html.py - DUHTML = html.py HTSTYLE = SpamBayesGenerator HTALLFLAGS = -f -s $(HTSTYLE) --- 43,46 ---- *************** *** 57,63 **** all: $(TARGETS) - - faq.html : faq.txt - $(DUHTML) faq.txt faq.html # $(TARGETS): $(HT2HTML) --- 56,59 ---- From montanaro at users.sourceforge.net Wed Jul 23 09:35:32 2003 From: montanaro at users.sourceforge.net (Skip Montanaro) Date: Wed Jul 23 11:42:51 2003 Subject: [Spambayes-checkins] website windows.ht,1.21,1.22 Message-ID: Update of /cvsroot/spambayes/website In directory sc8-pr-cvs1:/tmp/cvs-serv17473 Modified Files: windows.ht Log Message: tweak a couple outlook plugin refs Index: windows.ht =================================================================== RCS file: /cvsroot/spambayes/website/windows.ht,v retrieving revision 1.21 retrieving revision 1.22 diff -C2 -d -r1.21 -r1.22 *** windows.ht 22 Jul 2003 06:37:48 -0000 1.21 --- windows.ht 23 Jul 2003 15:35:30 -0000 1.22 *************** *** 9,13 ****

    If you are using Outlook 2000 or Outlook XP (not Outlook Express) you should be able to simply download and run the Outlook plug-in installer. A separate Python installation is not necessary.

    --- 9,13 ----

    If you are using Outlook 2000 or Outlook XP (not Outlook Express) you should be able to simply download and run the Outlook plug-in installer. A separate Python installation is not necessary.

    From montanaro at users.sourceforge.net Wed Jul 23 09:36:04 2003 From: montanaro at users.sourceforge.net (Skip Montanaro) Date: Wed Jul 23 11:45:54 2003 Subject: [Spambayes-checkins] website .cvsignore,1.1.1.1,1.2 Message-ID: Update of /cvsroot/spambayes/website In directory sc8-pr-cvs1:/tmp/cvs-serv17604 Modified Files: .cvsignore Log Message: faq.ht is intermediate, not in cvs Index: .cvsignore =================================================================== RCS file: /cvsroot/spambayes/website/.cvsignore,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -C2 -d -r1.1.1.1 -r1.2 *** .cvsignore 19 Sep 2002 08:40:55 -0000 1.1.1.1 --- .cvsignore 23 Jul 2003 15:36:02 -0000 1.2 *************** *** 1 **** --- 1,2 ---- *.html + faq.ht From tim_one at users.sourceforge.net Wed Jul 23 21:03:38 2003 From: tim_one at users.sourceforge.net (Tim Peters) Date: Wed Jul 23 23:03:41 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000/dialogs AsyncDialog.py, 1.7, 1.8 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000/dialogs In directory sc8-pr-cvs1:/tmp/cvs-serv20257/Outlook2000/dialogs Modified Files: AsyncDialog.py Log Message: Log even more info when the "Proportions must add to 1.0" assert fails. Index: AsyncDialog.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/dialogs/AsyncDialog.py,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -d -r1.7 -r1.8 *** AsyncDialog.py 23 Jul 2003 11:02:12 -0000 1.7 --- AsyncDialog.py 24 Jul 2003 03:03:36 -0000 1.8 *************** *** 43,48 **** start_pos += prop self.stages.append(stage) ! assert (abs(start_pos-1.0)) < 0.001, \ ! "Proportions must add to 1.0 (%r,%r)" % (start_pos, stages) def _next_stage(self): --- 43,49 ---- start_pos += prop self.stages.append(stage) ! assert abs(start_pos-1.0) < 0.001, ( ! "Proportions must add to 1.0 (%r,%r,%r)" % ! (start_pos, stages, start_pos-1.0)) def _next_stage(self): *************** *** 191,195 **** self.current_stage = 0 self.set_stages( (("", 1.0),) ) ! p = HackProgress() p.set_max_ticks(10) --- 192,196 ---- self.current_stage = 0 self.set_stages( (("", 1.0),) ) ! p = HackProgress() p.set_max_ticks(10) *************** *** 208,210 **** for i in range(1000): p.tick() ! --- 209,211 ---- for i in range(1000): p.tick() ! From anadelonbrin at users.sourceforge.net Thu Jul 24 15:31:26 2003 From: anadelonbrin at users.sourceforge.net (Tony Meyer) Date: Thu Jul 24 17:31:29 2003 Subject: [Spambayes-checkins] spambayes/spambayes Options.py,1.58,1.59 Message-ID: Update of /cvsroot/spambayes/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv5929/spambayes Modified Files: Options.py Log Message: Fix for [ 777165 ] Typo in Options.py causes bogus warning on reading config Index: Options.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/spambayes/Options.py,v retrieving revision 1.58 retrieving revision 1.59 diff -C2 -d -r1.58 -r1.59 *** Options.py 22 Jul 2003 07:13:43 -0000 1.58 --- Options.py 24 Jul 2003 21:31:24 -0000 1.59 *************** *** 920,924 **** is "best", which will pick the best DBM type available on your platform.""", ! ("best", "bd3hash", "dbhash", "gdbm", "dumbdbm"), RESTORE), ), } --- 920,924 ---- is "best", which will pick the best DBM type available on your platform.""", ! ("best", "db3hash", "dbhash", "gdbm", "dumbdbm"), RESTORE), ), } From mhammond at users.sourceforge.net Thu Jul 24 21:21:11 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Thu Jul 24 23:21:13 2003 Subject: [Spambayes-checkins] spambayes/spambayes/test - New directory Message-ID: Update of /cvsroot/spambayes/spambayes/spambayes/test In directory sc8-pr-cvs1:/tmp/cvs-serv29319/test Log Message: Directory /cvsroot/spambayes/spambayes/spambayes/test added to the repository From mhammond at users.sourceforge.net Thu Jul 24 21:22:06 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Thu Jul 24 23:22:13 2003 Subject: [Spambayes-checkins] spambayes/spambayes/test README.txt, NONE, 1.1 test_storage.py, NONE, 1.1 Message-ID: Update of /cvsroot/spambayes/spambayes/spambayes/test In directory sc8-pr-cvs1:/tmp/cvs-serv29376 Added Files: README.txt test_storage.py Log Message: A little unit test suite - currently checks the classifier's storage. --- NEW FILE: README.txt --- This is a directory for unit tests of spambayes itself. It is NOT to test the performance of the classification algorithms, but tests the semantics of the insfrastructure. --- NEW FILE: test_storage.py --- # Test the basic storage operations of the classifier. import unittest, os, sys # Hack sys.path - 2 levels up must be on sys.path. try: this_file = __file__ except NameError: this_file = sys.argv[0] sb_dir = os.path.abspath(os.path.dirname(os.path.dirname(os.path.dirname(this_file)))) if sb_dir not in sys.path: sys.path.append(sb_dir) from spambayes.storage import DBDictClassifier, PickledClassifier class _StorageTestBase(unittest.TestCase): StorageClass = None def setUp(self): import tempfile self.db_name = tempfile.mktemp("spambayestest") self.classifier = self.__class__.StorageClass(self.db_name) def tearDown(self): self.classifier = None if os.path.isfile(self.db_name): os.remove(self.db_name) def _checkWordCounts(self, word, expected_ham, expected_spam): assert word info = self.classifier._wordinfoget(word) if info is None: if expected_ham==0 and expected_spam==0: return self.fail("_CheckWordCounts for '%s' got None!") if info.hamcount != expected_ham: self.fail("Hamcount '%s' wrong - got %d, but expected %d" \ % (word, info.hamcount, expected_ham)) if info.spamcount != expected_spam: self.fail("Spamcount '%s' wrong - got %d, but expected %d" \ % (word, info.spamcount, expected_spam)) def _checkAllWordCounts(self, counts, do_persist): for info in counts: self._checkWordCounts(*info) if do_persist: self.classifier.store() self.classifier.load() self._checkAllWordCounts(counts, False) def testHapax(self): self._dotestHapax(False) self._dotestHapax(True) def _dotestHapax(self, do_persist): c = self.classifier c.learn(["common","nearly_hapax", "hapax", ], False) c.learn(["common","nearly_hapax"], False) c.learn(["common"], False) # All the words should be there. self._checkAllWordCounts( (("common", 3, 0), ("nearly_hapax", 2, 0), ("hapax", 1, 0)), do_persist) # Unlearn the complete set. c.unlearn(["common","nearly_hapax", "hapax", ], False) # 'hapax' removed, rest still there self._checkAllWordCounts( (("common", 2, 0), ("nearly_hapax", 1, 0), ("hapax", 0, 0)), do_persist) # Re-learn that set, so deleted hapax is reloaded c.learn(["common","nearly_hapax", "hapax", ], False) self._checkAllWordCounts( (("common", 3, 0), ("nearly_hapax", 2, 0), ("hapax", 1, 0)), do_persist) # Back to where we started - start unlearning all down to zero. c.unlearn(["common","nearly_hapax", "hapax", ], False) # 'hapax' removed, rest still there self._checkAllWordCounts( (("common", 2, 0), ("nearly_hapax", 1, 0), ("hapax", 0, 0)), do_persist) # Unlearn the next set. c.unlearn(["common","nearly_hapax"], False) self._checkAllWordCounts( (("common", 1, 0), ("nearly_hapax", 0, 0), ("hapax", 0, 0)), do_persist) c.unlearn(["common"], False) self._checkAllWordCounts( (("common", 0, 0), ("nearly_hapax", 0, 0), ("hapax", 0, 0)), do_persist) # Test classes for each classifier. class PickleStorageTestCase(_StorageTestBase): StorageClass = PickledClassifier def setUp(self): return _StorageTestBase.setUp(self) class DBStorageTestCase(_StorageTestBase): StorageClass = DBDictClassifier def setUp(self): return _StorageTestBase.setUp(self) def tearDown(self): self.classifier.db.close() _StorageTestBase.tearDown(self) def suite(): # We dont want our base class run suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(PickleStorageTestCase)) suite.addTest(unittest.makeSuite(DBStorageTestCase)) return suite if __name__=='__main__': unittest.main(argv=sys.argv + ['suite']) From tim_one at users.sourceforge.net Thu Jul 24 23:17:24 2003 From: tim_one at users.sourceforge.net (Tim Peters) Date: Fri Jul 25 01:17:27 2003 Subject: [Spambayes-checkins] spambayes/spambayes storage.py,1.15,1.16 Message-ID: Update of /cvsroot/spambayes/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv12238/spambayes Modified Files: storage.py Log Message: SF bug 777026: Possible cause for db corruption in DBDictClassifier. The _wordinfoset method of a DBDictClassifier implicitly relied on that a classifier always called it with the WordInfo record already associated with a word (assuming any such existed). In fact, all calls from a classifier do that, and there wasn't actually a bug here so far as classifiers go. I don't know about all other uses of _wordinfoset, though, and it seems unbearably delicate regardless. So fixed that; added a comment about why a KeyError can be expected to occur in the preceding try/except; and added a (necessarily kinda funky) new test_bug777026 test case, which fails before this patch when a DBDictClassifier is used. Index: storage.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/spambayes/storage.py,v retrieving revision 1.15 retrieving revision 1.16 diff -C2 -d -r1.15 -r1.16 *** storage.py 8 Jul 2003 11:39:10 -0000 1.15 --- storage.py 25 Jul 2003 05:17:22 -0000 1.16 *************** *** 236,245 **** if record.spamcount + record.hamcount <= 1: self.db[word] = record.__getstate__() - # Remove this word from the changed list (not that it should be - # there, but strange things can happen :) try: del self.changed_words[word] except KeyError: pass else: self.wordinfo[word] = record --- 236,251 ---- if record.spamcount + record.hamcount <= 1: self.db[word] = record.__getstate__() try: del self.changed_words[word] except KeyError: + # This can happen if, e.g., a new word is trained as ham + # twice, then untrained once, all before a store(). + pass + + try: + del self.wordinfo[word] + except KeyError: pass + else: self.wordinfo[word] = record From tim_one at users.sourceforge.net Thu Jul 24 23:17:24 2003 From: tim_one at users.sourceforge.net (Tim Peters) Date: Fri Jul 25 01:17:30 2003 Subject: [Spambayes-checkins] spambayes/spambayes/test test_storage.py, 1.1, 1.2 Message-ID: Update of /cvsroot/spambayes/spambayes/spambayes/test In directory sc8-pr-cvs1:/tmp/cvs-serv12238/spambayes/test Modified Files: test_storage.py Log Message: SF bug 777026: Possible cause for db corruption in DBDictClassifier. The _wordinfoset method of a DBDictClassifier implicitly relied on that a classifier always called it with the WordInfo record already associated with a word (assuming any such existed). In fact, all calls from a classifier do that, and there wasn't actually a bug here so far as classifiers go. I don't know about all other uses of _wordinfoset, though, and it seems unbearably delicate regardless. So fixed that; added a comment about why a KeyError can be expected to occur in the preceding try/except; and added a (necessarily kinda funky) new test_bug777026 test case, which fails before this patch when a DBDictClassifier is used. Index: test_storage.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/spambayes/test/test_storage.py,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** test_storage.py 25 Jul 2003 03:22:04 -0000 1.1 --- test_storage.py 25 Jul 2003 05:17:22 -0000 1.2 *************** *** 26,30 **** if os.path.isfile(self.db_name): os.remove(self.db_name) ! def _checkWordCounts(self, word, expected_ham, expected_spam): assert word --- 26,30 ---- if os.path.isfile(self.db_name): os.remove(self.db_name) ! def _checkWordCounts(self, word, expected_ham, expected_spam): assert word *************** *** 91,95 **** do_persist) ! c.unlearn(["common"], False) self._checkAllWordCounts( (("common", 0, 0), --- 91,95 ---- do_persist) ! c.unlearn(["common"], False) self._checkAllWordCounts( (("common", 0, 0), *************** *** 97,100 **** --- 97,130 ---- ("hapax", 0, 0)), do_persist) + + def test_bug777026(self): + c = self.classifier + word = "tim" + c.learn([word], False) + c.learn([word], False) + self._checkAllWordCounts([(word, 2, 0)], False) + + # Clone word's WordInfo record. + record = self.classifier.wordinfo[word] + newrecord = type(record)() + newrecord.__setstate__(record.__getstate__()) + self.assertEqual(newrecord.hamcount, 2) + self.assertEqual(newrecord.spamcount, 0) + + # Reduce the hamcount -- this tickled an excruciatingly subtle + # bug in a DBDictClassifier's _wordinfoset, which, at the time + # this test was written, couldn't actually be provoked by the + # way _wordinfoset got called by way of learn() and unlearn() + # methods. The code implicitly relied on that the record passed + # to _wordinfoset was always the same object as was already + # in wordinfo[word]. + newrecord.hamcount -= 1 + c._wordinfoset(word, newrecord) + # If the bug is present, the DBDictClassifier still believes + # the hamcount is 2. + self._checkAllWordCounts([(word, 1, 0)], False) + + c.unlearn([word], False) + self._checkAllWordCounts([(word, 0, 0)], False) # Test classes for each classifier. From mhammond at users.sourceforge.net Fri Jul 25 00:40:30 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Fri Jul 25 02:40:35 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 msgstore.py, 1.55, 1.56 manager.py, 1.66, 1.67 addin.py, 1.75, 1.76 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv23265 Modified Files: msgstore.py manager.py addin.py Log Message: Hopefully a fix for all our locale issues. Change the locale when we know it is bad, and also every time Outlook calls back into our plugin (as it may have change it in the meantime), and loading/saving our config. We could still get screwed if Outlook truly does change things "randomly", but there is no reasonable fix that could prevent that. manager also corrects the fact we tried to dump the options when saving the config (and also added it for loading it) A similar fix, but heavily instrumented, did work for the poster of the bug ([ 765912 ] AssertionError: Proportions must add to 1.0 ...), and I am waiting for confirmation this code does (but I'm confident :) Index: msgstore.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/msgstore.py,v retrieving revision 1.55 retrieving revision 1.56 diff -C2 -d -r1.55 -r1.56 *** msgstore.py 23 Jul 2003 06:20:40 -0000 1.55 --- msgstore.py 25 Jul 2003 06:40:28 -0000 1.56 *************** *** 133,140 **** mapi.MAPI_USE_DEFAULT) self.session = mapi.MAPILogonEx(0, None, None, logonFlags) ! # Set our locale to be English, so our plugin works OK ! # ([ spambayes-Bugs-725466 ] Include a proper locale fix in Options.py ! # has discussion about this problem.) ! locale.setlocale(locale.LC_NUMERIC, "en") self.mapi_msg_stores = {} self.default_store_bin_eid = None --- 133,139 ---- mapi.MAPI_USE_DEFAULT) self.session = mapi.MAPILogonEx(0, None, None, logonFlags) ! # Note that if the CRT still has a default "C" locale, MAPILogonEx() ! # will change it. See locale comments in addin.py ! locale.setlocale(locale.LC_NUMERIC, "C") self.mapi_msg_stores = {} self.default_store_bin_eid = None Index: manager.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/manager.py,v retrieving revision 1.66 retrieving revision 1.67 diff -C2 -d -r1.66 -r1.67 *** manager.py 21 Jul 2003 01:55:13 -0000 1.66 --- manager.py 25 Jul 2003 06:40:28 -0000 1.67 *************** *** 497,500 **** --- 497,504 ---- def LoadConfig(self): + # Insist on english numeric conventions in config file. + # See addin.py, and [725466] Include a proper locale fix in Options.py + import locale; locale.setlocale(locale.LC_NUMERIC, "C") + profile_name = self.message_store.GetProfileName() if profile_name is None: *************** *** 526,529 **** --- 530,538 ---- self.MigrateOldPickle() + if self.verbose > 1: + print "Dumping loaded configuration:" + print self.options.display() + print "-- end of configuration --" + def MigrateOldPickle(self): assert self.config is not None, "Must have a config" *************** *** 624,631 **** def SaveConfig(self): print "Saving configuration ->", self.config_filename.encode("mbcs", "replace") assert self.config and self.options, "Have no config to save!" if self.verbose > 1: ! self.options.display() self.options.update_file(self.config_filename) --- 633,646 ---- def SaveConfig(self): + # Insist on english numeric conventions in config file. + # See addin.py, and [725466] Include a proper locale fix in Options.py + import locale; locale.setlocale(locale.LC_NUMERIC, "C") + print "Saving configuration ->", self.config_filename.encode("mbcs", "replace") assert self.config and self.options, "Have no config to save!" if self.verbose > 1: ! print "Dumping configuration to save:" ! print self.options.display() ! print "-- end of configuration --" self.options.update_file(self.config_filename) *************** *** 692,696 **** if dlg.mgr.addin is not None: dlg.mgr.addin.FiltersChanged() - import dialogs.ManagerDialog --- 707,710 ---- Index: addin.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/addin.py,v retrieving revision 1.75 retrieving revision 1.76 diff -C2 -d -r1.75 -r1.76 *** addin.py 22 Jul 2003 13:36:12 -0000 1.75 --- addin.py 25 Jul 2003 06:40:28 -0000 1.76 *************** *** 11,14 **** --- 11,29 ---- True, False = 1, 0 + # We have lots of locale woes. The short story: + # * Outlook/MAPI will change the locale on us as some predictable + # times - but also at unpredictable times. + # * Python currently insists on "C" locale - if it isn't, subtle things break, + # such as floating point constants loaded from .pyc files. + # * Our config files also want a consistent locale, so periods and commas + # are the same when they are read as when they are written. + # So, at a few opportune times, we simple set it back. + # We do it here as early as possible, before any imports that may see this + # + # See also [725466] Include a proper locale fix in Options.py, + # assorted errors relating to strange math errors, and spambayes-dev archives, + # starting July 23 2003. + import locale + locale.setlocale(locale.LC_NUMERIC, "C") if sys.version_info >= (2, 3): *************** *** 59,69 **** import win32traceutil - # Set our locale to be English, so our config parser works OK - # (This should almost certainly be done elsewhere, but as no one - # else seems to have an opinion on where this is, here is as good - # as any! - import locale - locale.setlocale(locale.LC_NUMERIC, "en") - # Attempt to catch the most common errors - COM objects not installed. try: --- 74,77 ---- *************** *** 211,214 **** --- 219,224 ---- self.handler = self.args = None def OnClick(self, button, cancel): + # Callback from Outlook - locale may have changed. + locale.setlocale(locale.LC_NUMERIC, "C") # see locale comments above self.handler(*self.args) *************** *** 235,238 **** --- 245,250 ---- # PR_RECEIVED_BY_ENTRYID # PR_TRANSPORT_MESSAGE_HEADERS + # Callback from Outlook - locale may have changed. + locale.setlocale(locale.LC_NUMERIC, "C") # see locale comments above self.manager.LogDebug(2, "OnItemAdd event for folder", self, "with item", item) *************** *** 768,772 **** except: print "Error finding the MAPI folders for a folder switch event" - import traceback traceback.print_exc() if self.but_recover_as is not None: --- 780,783 ---- *************** *** 841,847 **** --- 852,860 ---- # automatically disabled by Outlook. # Our error reporter is in the "manager" module, so we get that first + locale.setlocale(locale.LC_NUMERIC, "C") # see locale comments above import manager try: self.application = application + self.manager = None # if we die while creating it! # Create our bayes manager From mhammond at users.sourceforge.net Fri Jul 25 18:57:38 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Fri Jul 25 21:42:10 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 addin.py,1.77,1.78 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv30530 Modified Files: addin.py Log Message: Oops - I am pretty sure I broke source code users - I relied on a bug I fixed here but am yet to get out in a new win32all. Index: addin.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/addin.py,v retrieving revision 1.77 retrieving revision 1.78 diff -C2 -d -r1.77 -r1.78 *** addin.py 25 Jul 2003 15:00:14 -0000 1.77 --- addin.py 26 Jul 2003 00:57:35 -0000 1.78 *************** *** 92,97 **** # Register what vtable based interfaces we need to implement. ! gencache.EnsureModule('{AC0714F2-3D04-11D1-AE7D-00A0C90F26F4}', 0, 1, 0, ! bForDemand=True, bValidateFile=bValidateGencache) # Addin # A couple of functions that are in new win32all, but we dont want to --- 92,98 ---- # Register what vtable based interfaces we need to implement. ! # Damn - we should use EnsureModule for the _IDTExtensibility2 typelib, but ! # win32all 155 and earlier don't like us pre-generating :( ! universal.RegisterInterfaces('{AC0714F2-3D04-11D1-AE7D-00A0C90F26F4}', 0, 1, 0, ["_IDTExtensibility2"]) # A couple of functions that are in new win32all, but we dont want to From mhammond at users.sourceforge.net Fri Jul 25 09:00:20 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Sat Jul 26 01:15:04 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 addin.py,1.76,1.77 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv27009 Modified Files: addin.py Log Message: * Don't attempt to check the version of the typelibraries in binary builds. * Don't make COM errors "pretty" in this module - binary users never see this message, and anyone running from source should see the full error. * Build a "gencache" version of the vtable interface - this was a perf hit I didn't notice we took. * Log the binary version in the binary. * Remove some registration debug prints. Index: addin.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/addin.py,v retrieving revision 1.76 retrieving revision 1.77 diff -C2 -d -r1.76 -r1.77 *** addin.py 25 Jul 2003 06:40:28 -0000 1.76 --- addin.py 25 Jul 2003 15:00:14 -0000 1.77 *************** *** 32,35 **** --- 32,39 ---- # (but we will wait some time for people to update) warnings.filterwarnings("ignore", category=FutureWarning, append=1) + # Binary builds can avoid our pendingdeprecation too + if hasattr(sys, "frozen"): + warnings.filterwarnings("ignore", category=DeprecationWarning, append=1) + from win32com import universal *************** *** 74,97 **** import win32traceutil ! # Attempt to catch the most common errors - COM objects not installed. ! try: ! # Generate support so we get complete support including events ! gencache.EnsureModule('{00062FFF-0000-0000-C000-000000000046}', 0, 9, 0, bForDemand=True) # Outlook 9 ! gencache.EnsureModule('{2DF8D04C-5BFA-101B-BDE5-00AA0044DE52}', 0, 2, 1, bForDemand=True) # Office 9 ! # Register what vtable based interfaces we need to implement. ! universal.RegisterInterfaces('{AC0714F2-3D04-11D1-AE7D-00A0C90F26F4}', 0, 1, 0, ["_IDTExtensibility2"]) ! except pythoncom.com_error, (hr, msg, exc, arg): ! if __name__ != '__main__': ! # Error when not running as a script - eeek - just let it go. ! raise ! print "This Addin requires that Outlook 2000 be installed on this machine." ! print ! print "This appears to not be installed due to the following error:" ! print "COM Error 0x%x (%s)" % (hr, msg) ! if exc: ! print "Exception: %s" % (exc) ! print "Sorry I can't be more help, but I can't continue while I have this error." ! sys.exit(1) # A couple of functions that are in new win32all, but we dont want to --- 78,97 ---- import win32traceutil ! # We used to catch COM errors - but as most users are now on the binary, this ! # niceness doesn't help anyone. ! # win32com generally checks the gencache is up to date (typelib hasn't ! # changed, makepy hasn't changed, etc), but when frozen we dont want to ! # do this - not just for perf, but because they don't always exist! ! bValidateGencache = not hasattr(sys, "frozen") ! # Generate support so we get complete support including events ! gencache.EnsureModule('{00062FFF-0000-0000-C000-000000000046}', 0, 9, 0, ! bForDemand=True, bValidateFile=bValidateGencache) # Outlook 9 ! gencache.EnsureModule('{2DF8D04C-5BFA-101B-BDE5-00AA0044DE52}', 0, 2, 1, ! bForDemand=True, bValidateFile=bValidateGencache) # Office 9 ! ! # Register what vtable based interfaces we need to implement. ! gencache.EnsureModule('{AC0714F2-3D04-11D1-AE7D-00A0C90F26F4}', 0, 1, 0, ! bForDemand=True, bValidateFile=bValidateGencache) # Addin # A couple of functions that are in new win32all, but we dont want to *************** *** 866,871 **** # manager is what munges sys.path for us. from spambayes.Version import get_version_string print "%s starting (with engine %s)" % \ ! (get_version_string("Outlook"), get_version_string()) major, minor, spack, platform, ver_str = win32api.GetVersionEx() print "on Windows %d.%d.%d (%s)" % \ --- 866,874 ---- # manager is what munges sys.path for us. from spambayes.Version import get_version_string + version_key = "Full Description" + if hasattr(sys, "frozen"): version_key += " Binary" print "%s starting (with engine %s)" % \ ! (get_version_string("Outlook", version_key), ! get_version_string()) major, minor, spack, platform, ver_str = win32api.GetVersionEx() print "on Windows %d.%d.%d (%s)" % \ *************** *** 1018,1027 **** def RegisterAddin(klass): # prints to help debug binary install issues. - print "Starting register" import _winreg key = _winreg.CreateKey(_winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Office\\Outlook\\Addins") subkey = _winreg.CreateKey(key, klass._reg_progid_) - print "Setting values" _winreg.SetValueEx(subkey, "CommandLineSafe", 0, _winreg.REG_DWORD, 0) _winreg.SetValueEx(subkey, "LoadBehavior", 0, _winreg.REG_DWORD, 3) --- 1021,1028 ---- From mhammond at users.sourceforge.net Fri Jul 25 09:58:37 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Sat Jul 26 07:11:15 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000/installer spambayes_addin.spec, 1.5, 1.6 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000/installer In directory sc8-pr-cvs1:/tmp/cvs-serv10164 Modified Files: spambayes_addin.spec Log Message: Enable my gross hacks to McMillan installer to include a pre-built gencache. This means we do not depend on having all the COM typelibraries installed, which is a common problem. Index: spambayes_addin.spec =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/installer/spambayes_addin.spec,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** spambayes_addin.spec 1 Jul 2003 03:16:32 -0000 1.5 --- spambayes_addin.spec 25 Jul 2003 15:58:34 -0000 1.6 *************** *** 47,50 **** --- 47,55 ---- # console=0 ) + typelibs = [ + ('{00062FFF-0000-0000-C000-000000000046}', 0, 9, 0), + ('{2DF8D04C-5BFA-101B-BDE5-00AA0044DE52}', 0, 2, 1), + ('{AC0714F2-3D04-11D1-AE7D-00A0C90F26F4}', 0, 1, 0), + ] dll = DLL(pyz, a.scripts, *************** *** 56,58 **** strip=0, debug=debug, ! name='dist') --- 61,64 ---- strip=0, debug=debug, ! name='dist', ! typelibs=typelibs) From anadelonbrin at users.sourceforge.net Sun Jul 27 01:38:32 2003 From: anadelonbrin at users.sourceforge.net (Tony Meyer) Date: Sun Jul 27 03:38:35 2003 Subject: [Spambayes-checkins] spambayes/scripts - New directory Message-ID: Update of /cvsroot/spambayes/spambayes/scripts In directory sc8-pr-cvs1:/tmp/cvs-serv3505/scripts Log Message: Directory /cvsroot/spambayes/spambayes/scripts added to the repository From anadelonbrin at users.sourceforge.net Sun Jul 27 01:41:11 2003 From: anadelonbrin at users.sourceforge.net (Tony Meyer) Date: Sun Jul 27 03:41:14 2003 Subject: [Spambayes-checkins] spambayes/scripts README.txt,NONE,1.1 Message-ID: Update of /cvsroot/spambayes/spambayes/scripts In directory sc8-pr-cvs1:/tmp/cvs-serv3868/scripts Added Files: README.txt Log Message: Add the proposed scripts/apps directory and an explanatory readme. Moving everything can be done later, but at least new scripts can have a home that isn't the root directory. --- NEW FILE: README.txt --- This directory contains a collection of spambayes applications/scripts. Each file within this directory should be executable, and perform a specific task (export the database, launch a POP3 proxy, and so on). To avoid polluting the end user's python/scripts directory when spambayes is installed, each script should be prefixed with 'sb-'. From anadelonbrin at users.sourceforge.net Sun Jul 27 01:48:17 2003 From: anadelonbrin at users.sourceforge.net (Tony Meyer) Date: Sun Jul 27 03:48:23 2003 Subject: [Spambayes-checkins] spambayes/scripts sb-overkill.py,NONE,1.1 Message-ID: Update of /cvsroot/spambayes/spambayes/scripts In directory sc8-pr-cvs1:/tmp/cvs-serv4911/scripts Added Files: sb-overkill.py Log Message: This is a working draft of the 'overkill' (thanks Greg) app that works like pop3proxy, but allows training via drag and drop in many MUAs (including OE and Mozilla Mail, but not Eudora) courtesy of a local IMAP4 server. (Note that the name will hopefully change at some point). I'm checking this as a standalone script at the moment, so you won't be able to just run it. To do so, you'll need to: * install the latest cvs of twisted. * add the extra options to Options.py (or ask me for a copy of my one) * get a copy of twisted/protocols/imap4.py from me that doesn't have all the bugs of the cvs version, or wait for the cvs version to be fixed. At the moment, it seems to mostly work with Mozilla mail, although I haven't done any thorough testing yet. It works ok with Eudora, except that Eudora doesn't let you view two accounts side-by-side, so it's useless. For some reason messages won't show up in OE at the moment - if anyone has a clue why, I'd love to know. For whoever it was that was interested in writing an IMAP server for spambayes, here is code that you may be able to borrow. --- NEW FILE: sb-overkill.py --- #!/usr/bin/env python from __future__ import generators """ Overkill (someone *please* come up with something to call this script!) This application is a twisted cross between a POP3 proxy and an IMAP server. It sits between your mail client and your POP3 server (like any other POP3 proxy). While messages classified as ham are simply passed through the proxy, messages that are classified as spam or unsure are intercepted and passed to the IMAP server. The IMAP server offers three folders - one where messages classified as spam end up, one for messages it is unsure about, and one for training ham. In other words, to use this application, setup your mail client to connect to localhost, rather than directly to your POP3 server. Additionally, add a new IMAP account, also connecting to localhost. Setup the application via the web interface, and you are ready to go. Good messages will appear as per normal, but you will also have two new incoming folders, one for spam and one for ham. To train SpamBayes, use the spam folder, and the 'train_as_ham' folder. Any messages in these folders will be trained appropriately. This means that all messages that SpamBayes classifies as spam will also be trained as such. If you receive any 'false positives' (ham classified as spam), you *must* copy the message into the 'train_as_ham' folder to correct the training. You may also place any saved spam messages you have into this folder. So that SpamBayes knows about ham as well as spam, you will also need to move or copy mail into the 'train_as_ham' folder. These may come from the unsure folder, or from any other mail you have saved. It is a good idea to leave messages in the 'train_as_ham' and 'spam' folders, so that you can retrain from scratch if required. (However, you should always clear out your unsure folder, preferably moving or copying the messages into the appropriate training folder). This SpamBayes application is designed to work with Outlook Express, and provide the same sort of ease of use as the Outlook plugin. Although the majority of development and testing has been done with Outlook Express, any mail client that supports both IMAP and POP3 should be able to use this application - if the client enables the user to work with an IMAP account and POP3 account side-by-side (and move messages between them), then it should work equally as well as Outlook Express. This module includes the following classes: o IMAPFileMessage o IMAPFileMessageFactory o IMAPMailbox o SpambayesMailbox o Trainer o SpambayesAccount o SpambayesIMAPServer o OneParameterFactory o MyBayesProxy o MyBayesProxyListener o IMAPState """ todo = """ o Message flags are currently not persisted, but should be. The IMAPFileMessage class should be extended to do this. The same goes for the 'internaldate' of the message. o The RECENT flag should be unset at some point, but when? The RFC says that a message is recent if this is the first session to be notified about the message. Perhaps this can be done simply by *not* persisting this flag - i.e. the flag is always loaded as not recent, and only new messages are recent. The RFC says that if it is not possible to determine, then all messages should be recent, and this is what we currently do. o The Mailbox should be calling the appropriate listener functions (currently only newMessages is called on addMessage). flagsChanged should also be called on store, addMessage, or ??? o We cannot currently get part of a message via the BODY calls (with the <> operands), or get a part of a MIME message (by prepending a number). This should be added! o If the user clicks the 'save and shutdown' button on the web interface, this will only kill the POP3 proxy and web interface threads, and not the IMAP server. We need to monitor the thread that we kick off, and if it dies, we should die too. Need to figure out how to do this in twisted. o Suggestions? """ # This module is part of the spambayes project, which is Copyright 2002-3 # The Python Software Foundation and is covered by the Python Software # Foundation license. __author__ = "Tony Meyer " __credits__ = "All the Spambayes folk." try: True, False except NameError: # Maintain compatibility with Python 2.2 True, False = 1, 0 import os import re import sys import md5 import time import errno import types import thread import getopt import imaplib import operator import StringIO import email.Utils from twisted import cred from twisted.internet import defer from twisted.internet import reactor from twisted.internet.app import Application from twisted.internet.defer import maybeDeferred from twisted.internet.protocol import ServerFactory from twisted.protocols.imap4 import parseNestedParens, parseIdList from twisted.protocols.imap4 import IllegalClientResponse, IAccount from twisted.protocols.imap4 import collapseNestedLists, MessageSet from twisted.protocols.imap4 import IMAP4Server, MemoryAccount, IMailbox from twisted.protocols.imap4 import IMailboxListener, collapseNestedLists # Provide for those that don't have spambayes on their PYTHONPATH sys.path.insert(-1, os.path.dirname(os.getcwd())) from spambayes.Options import options from spambayes.message import Message from spambayes.tokenizer import tokenize from spambayes import FileCorpus, Dibbler from spambayes.Version import get_version_string from spambayes.ServerUI import ServerUserInterface from spambayes.UserInterface import UserInterfaceServer from pop3proxy import POP3ProxyBase, State, _addressPortStr, _recreateState def ensureDir(dirname): """Ensure that the given directory exists - in other words, if it does not exist, attempt to create it.""" try: os.mkdir(dirname) if options["globals", "verbose"]: print "Creating directory", dirname except OSError, e: if e.errno != errno.EEXIST: raise class IMAPFileMessage(FileCorpus.FileMessage): '''IMAP Message that persists as a file system artifact.''' def __init__(self, file_name, directory): """Constructor(message file name, corpus directory name).""" FileCorpus.FileMessage.__init__(self, file_name, directory) self.id = file_name self.directory = directory self.date = imaplib.Time2Internaldate(time.time())[1:-1] self.clear_flags() # IMessage implementation def getHeaders(self, negate, names): """Retrieve a group of message headers.""" headers = {} if not isinstance(names, tuple): names = (names,) for header, value in self.items(): if (header.upper() in names and not negate) or names == (): headers[header.upper()] = value return headers def getFlags(self): """Retrieve the flags associated with this message.""" return self._flags_iter() def _flags_iter(self): if self.deleted: yield "\\DELETED" if self.answered: yield "\\ANSWERED" if self.flagged: yield "\\FLAGGED" if self.seen: yield "\\SEEN" if self.draft: yield "\\DRAFT" if self.draft: yield "\\RECENT" def getInternalDate(self): """Retrieve the date internally associated with this message.""" return self.date def getBodyFile(self): """Retrieve a file object containing the body of this message.""" # Note only body, not headers! s = StringIO.StringIO() s.write(self.body()) s.seek(0) return s #return file(os.path.join(self.directory, self.id), "r") def getSize(self): """Retrieve the total size, in octets, of this message.""" return len(self.as_string()) def getUID(self): """Retrieve the unique identifier associated with this message.""" return self.id def getSubPart(self, part): """Retrieve a MIME sub-message @type part: C{int} @param part: The number of the part to retrieve, indexed from 0. @rtype: Any object implementing C{IMessage}. @return: The specified sub-part. """ # IMessage implementation ends def clear_flags(self): """Set all message flags to false.""" self.deleted = False self.answered = False self.flagged = False self.seen = False self.draft = False self.recent = False def set_flag(self, flag, value): # invalid flags are ignored flag = flag.upper() if flag == "\\DELETED": self.deleted = value elif flag == "\\ANSWERED": self.answered = value elif flag == "\\FLAGGED": self.flagged = value elif flag == "\\SEEN": self.seen = value elif flag == "\\DRAFT": self.draft = value else: print "Tried to set invalid flag", flag, "to", value def flags(self): """Return the message flags.""" all_flags = [] if self.deleted: all_flags.append("\\DELETED") if self.answered: all_flags.append("\\ANSWERED") if self.flagged: all_flags.append("\\FLAGGED") if self.seen: all_flags.append("\\SEEN") if self.draft: all_flags.append("\\DRAFT") if self.draft: all_flags.append("\\RECENT") return all_flags def train(self, classifier, isSpam): if self.GetTrained() == (not isSpam): classifier.unlearn(self.asTokens(), not isSpam) self.RememberTrained(None) if self.GetTrained() is None: classifier.learn(self.asTokens(), isSpam) self.RememberTrained(isSpam) classifier.store() def structure(self, ext=False): """Body structure data describes the MIME-IMB format of a message and consists of a sequence of mime type, mime subtype, parameters, content id, description, encoding, and size. The fields following the size field are variable: if the mime type/subtype is message/rfc822, the contained message's envelope information, body structure data, and number of lines of text; if the mime type is text, the number of lines of text. Extension fields may also be included; if present, they are: the MD5 hash of the body, body disposition, body language.""" s = [] for part in self.walk(): if part.get_content_charset() is not None: charset = ("charset", part.get_content_charset()) else: charset = None part_s = [part.get_main_type(), part.get_subtype(), charset, part.get('Content-Id'), part.get('Content-Description'), part.get('Content-Transfer-Encoding'), str(len(part.as_string()))] #if part.get_type() == "message/rfc822": # part_s.extend([envelope, body_structure_data, # part.as_string().count("\n")]) #elif part.get_main_type() == "text": if part.get_main_type() == "text": part_s.append(str(part.as_string().count("\n"))) if ext: part_s.extend([md5.new(part.as_string()).digest(), part.get('Content-Disposition'), part.get('Content-Language')]) s.append(part_s) if len(s) == 1: return s[0] return s def body(self): rfc822 = self.as_string() bodyRE = re.compile(r"\r?\n(\r?\n)(.*)", re.DOTALL + re.MULTILINE) bmatch = bodyRE.search(rfc822) return bmatch.group(2) def headers(self): rfc822 = self.as_string() bodyRE = re.compile(r"\r?\n(\r?\n)(.*)", re.DOTALL + re.MULTILINE) bmatch = bodyRE.search(rfc822) return rfc822[:bmatch.start(2)] def on(self, date1, date2): "contained within the date" raise NotImplementedError def before(self, date1, date2): "before the date" raise NotImplementedError def since(self, date1, date2): "within or after the date" raise NotImplementedError def string_contains(self, whole, sub): return whole.find(sub) != -1 def matches(self, criteria): """Return True iff the messages matches the specified IMAP criteria.""" match_tests = {"ALL" : [(True, True)], "ANSWERED" : [(self.answered, True)], "DELETED" : [(self.deleted, True)], "DRAFT" : [(self.draft, True)], "FLAGGED" : [(self.flagged, True)], "NEW" : [(self.recent, True), (self.seen, False)], "RECENT" : [(self.recent, True)], "SEEN" : [(self.seen, True)], "UNANSWERED" : [(self.answered, False)], "UNDELETED" : [(self.deleted, False)], "UNDRAFT" : [(self.draft, False)], "UNFLAGGED" : [(self.flagged, False)], "UNSEEN" : [(self.seen, False)], "OLD" : [(self.recent, False)], } complex_tests = {"BCC" : (self.string_contains, self.get("Bcc")), "SUBJECT" : (self.string_contains, self.get("Subject")), "CC" : (self.string_contains, self.get("Cc")), "BODY" : (self.string_contains, self.body()), "TO" : (self.string_contains, self.get("To")), "TEXT" : (self.string_contains, self.as_string()), "FROM" : (self.string_contains, self.get("From")), "SMALLER" : (operator.lt, len(self.as_string())), "LARGER" : (operator.gt, len(self.as_string())), "BEFORE" : (self.before, self.date), "ON" : (self.on, self.date), "SENTBEFORE" : (self.before, self.get("Date")), "SENTON" : (self.on, self.get("Date")), "SENTSINCE" : (self.since, self.get("Date")), "SINCE" : (self.since, self.date), } result = True test = None header = None header_field = None for c in criteria: if match_tests.has_key(c) and test is None and header is None: for (test, result) in match_tests[c]: result = result and (test == result) elif complex_tests.has_key(c) and test is None and header is None: test = complex_tests[c] elif test is not None and header is None: result = result and test[0](test[1], c) test = None elif c == "HEADER" and test is None: # the only criteria that uses the next _two_ elements header = c elif test is None and header is not None and header_field is None: header_field = c elif header is not None and header_field is not None and test is None: result = result and self.string_contains(self.get(header_field), c) header = None header_field = None return result """ Still to do: Messages with message sequence numbers corresponding to the specified message sequence number set UID Messages with unique identifiers corresponding to the specified unique identifier set. KEYWORD Messages with the specified keyword set. UNKEYWORD Messages that do not have the specified keyword set. NOT Messages that do not match the specified search key. OR Messages that match either search key. """ class IMAPFileMessageFactory(FileCorpus.FileMessageFactory): '''MessageFactory for IMAPFileMessage objects''' def create(self, key, directory): '''Create a message object from a filename in a directory''' return IMAPFileMessage(key, directory) class IMAPMailbox(cred.perspective.Perspective): __implements__ = (IMailbox,) def __init__(self, name, identity_name, id): cred.perspective.Perspective.__init__(self, name, identity_name) self.UID_validity = id self.listeners = [] def getUIDValidity(self): """Return the unique validity identifier for this mailbox.""" return self.UID_validity def addListener(self, listener): """Add a mailbox change listener.""" self.listeners.append(listener) def removeListener(self, listener): """Remove a mailbox change listener.""" self.listeners.remove(listener) class SpambayesMailbox(IMAPMailbox): def __init__(self, name, id, directory): IMAPMailbox.__init__(self, name, "spambayes", id) self.UID_validity = id ensureDir(directory) self.storage = FileCorpus.FileCorpus(IMAPFileMessageFactory(), directory, r"[0123456789]*") # UIDs are required to be strictly ascending. if len(self.storage.keys()) == 0: self.nextUID = 0 else: self.nextUID = long(self.storage.keys()[-1]) + 1 # Calculate initial recent and unseen counts # XXX Note that this will always end up with zero counts # XXX until the flags are persisted. self.unseen_count = 0 self.recent_count = 0 for msg in self.storage: if not msg.seen: self.unseen_count += 1 if msg.recent: self.recent_count += 1 def getUIDNext(self, increase=False): """Return the likely UID for the next message added to this mailbox.""" reply = str(self.nextUID) if increase: self.nextUID += 1 return reply def getUID(self, message): """Return the UID of a message in the mailbox.""" # Note that IMAP messages are 1-based, our messages are 0-based d = self.storage return long(d.keys()[message - 1]) def getFlags(self): """Return the flags defined in this mailbox.""" return ["\\Answered", "\\Flagged", "\\Deleted", "\\Seen", "\\Draft"] def getMessageCount(self): """Return the number of messages in this mailbox.""" return len(self.storage.keys()) def getRecentCount(self): """Return the number of messages with the 'Recent' flag.""" return self.recent_count def getUnseenCount(self): """Return the number of messages with the 'Unseen' flag.""" return self.unseen_count def isWriteable(self): """Get the read/write status of the mailbox.""" return True def destroy(self): """Called before this mailbox is deleted, permanently.""" # Our mailboxes cannot be deleted raise NotImplementedError def getHierarchicalDelimiter(self): """Get the character which delimits namespaces for in this mailbox.""" return '.' def requestStatus(self, names): """Return status information about this mailbox.""" answer = {} for request in names: request = request.upper() if request == "MESSAGES": answer[request] = self.getMessageCount() elif request == "RECENT": answer[request] = self.getRecentCount() elif request == "UIDNEXT": answer[request] = self.getUIDNext() elif request == "UIDVALIDITY": answer[request] = self.getUIDValidity() elif request == "UNSEEN": answer[request] = self.getUnseenCount() return answer def addMessage(self, message, flags=(), date=None): """Add the given message to this mailbox.""" msg = self.storage.makeMessage(self.getUIDNext(True)) msg.date = date msg.setPayload(message.read()) self.storage.addMessage(msg) self.store(MessageSet(long(msg.id), long(msg.id)), flags, 1, True) msg.recent = True msg.store() self.recent_count += 1 self.unseen_count += 1 for listener in self.listeners: listener.newMessages(self.getMessageCount(), self.getRecentCount()) d = defer.Deferred() reactor.callLater(0, d.callback, self.storage.keys().index(msg.id)) return d def expunge(self): """Remove all messages flagged \\Deleted.""" deleted_messages = [] for msg in self.storage: if msg.deleted: if not msg.seen: self.unseen_count -= 1 if msg.recent: self.recent_count -= 1 deleted_messages.append(long(msg.id)) self.storage.removeMessage(msg) if deleted_messages != []: for listener in self.listeners: listener.newMessages(self.getMessageCount(), self.getRecentCount()) return deleted_messages def search(self, query, uid): """Search for messages that meet the given query criteria. @type query: C{list} @param query: The search criteria @rtype: C{list} @return: A list of message sequence numbers or message UIDs which match the search criteria. """ if self.getMessageCount() == 0: return [] all_msgs = MessageSet(long(self.storage.keys()[0]), long(self.storage.keys()[-1])) matches = [] for id, msg in self._messagesIter(all_msgs, uid): for q in query: if msg.matches(q): matches.append(id) break return matches def _messagesIter(self, messages, uid): if uid: messages.last = long(self.storage.keys()[-1]) else: messages.last = self.getMessageCount() for id in messages: if uid: msg = self.storage.get(str(id)) else: msg = self.storage.get(str(self.getUID(id))) if msg is None: # Non-existant message. continue msg.load() yield (id, msg) def fetch(self, messages, uid): """Retrieve one or more messages.""" return self._messagesIter(messages, uid) def store(self, messages, flags, mode, uid): """Set the flags of one or more messages.""" stored_messages = {} for id, msg in self._messagesIter(messages, uid): if mode == 0: msg.clear_flags() value = True elif mode == -1: value = False elif mode == 1: value = True for flag in flags: if flag == '(' or flag == ')': continue if flag == "SEEN" and value == True and msg.seen == False: self.unseen_count -= 1 if flag == "SEEN" and value == False and msg.seen == True: self.unseen_count += 1 msg.set_flag(flag, value) stored_messages[id] = msg.flags() return stored_messages class Trainer(object): """Listens to a given mailbox and trains new messages as spam or ham.""" __implements__ = (IMailboxListener,) def __init__(self, mailbox, asSpam): self.mailbox = mailbox self.asSpam = asSpam def modeChanged(self, writeable): # We don't care pass def flagsChanged(self, newFlags): # We don't care pass def newMessages(self, exists, recent): # We don't get passed the actual message, or the id of # the message, of even the message number. We just get # the total number of new/recent messages. # However, this function should be called _every_ time # that a new message appears, so we should be able to # assume that the last message is the new one. # (We ignore the recent count) if exists is not None: id = self.mailbox.getUID(exists) msg = self.mailbox.storage[str(id)] msg.train(state.bayes, self.asSpam) class SpambayesAccount(MemoryAccount): """Account for Spambayes server.""" def __init__(self, id, ham, spam, unsure): MemoryAccount.__init__(self, id) self.mailboxes = {"SPAM" : spam, "UNSURE" : unsure, "TRAIN_AS_HAM" : ham} def select(self, name, readwrite=1): # 'INBOX' is a special case-insensitive name meaning the # primary mailbox for the user; we interpret this as an alias # for 'spam' if name.upper() == "INBOX": name = "SPAM" return MemoryAccount.select(self, name, readwrite) class SpambayesIMAPServer(IMAP4Server): IDENT = "Spambayes IMAP Server IMAP4rev1 Ready" def __init__(self, user_account): IMAP4Server.__init__(self) self.account = user_account def authenticateLogin(self, user, passwd): """Lookup the account associated with the given parameters.""" if user == options["imapserver", "username"] and \ passwd == options["imapserver", "password"]: return (IAccount, self.account, None) raise cred.error.UnauthorizedLogin() def connectionMade(self): state.activeIMAPSessions += 1 state.totalIMAPSessions += 1 IMAP4Server.connectionMade(self) def connectionLost(self, reason): state.activeIMAPSessions -= 1 IMAP4Server.connectionLost(self, reason) def do_CREATE(self, tag, args): """Creating new folders on the server is not permitted.""" self.sendNegativeResponse(tag, \ "Creation of new folders is not permitted") auth_CREATE = (do_CREATE, IMAP4Server.arg_astring) select_CREATE = auth_CREATE def do_DELETE(self, tag, args): """Deleting folders on the server is not permitted.""" self.sendNegativeResponse(tag, \ "Deletion of folders is not permitted") auth_DELETE = (do_DELETE, IMAP4Server.arg_astring) select_DELETE = auth_DELETE class OneParameterFactory(ServerFactory): """A factory that allows a single parameter to be passed to the created protocol.""" def buildProtocol(self, addr): """Create an instance of a subclass of Protocol, passing a single parameter.""" if self.parameter is not None: p = self.protocol(self.parameter) else: p = self.protocol() p.factory = self return p class MyBayesProxy(POP3ProxyBase): """Proxies between an email client and a POP3 server, redirecting mail to the imap server as necessary. It acts on the following POP3 commands: o RETR: o Adds the judgement header based on the raw headers and body of the message. """ intercept_message = 'From: "Spambayes" \n' \ 'Subject: Spambayes Intercept\n\nA message ' \ 'was intercepted by Spambayes (it scored %s).\n' \ '\nYou may find it in the Spam or Unsure ' \ 'folder.\n\n.\n' def __init__(self, clientSocket, serverName, serverPort, spam, unsure): POP3ProxyBase.__init__(self, clientSocket, serverName, serverPort) self.handlers = {'RETR': self.onRetr} state.totalSessions += 1 state.activeSessions += 1 self.isClosed = False self.spam_folder = spam self.unsure_folder = unsure def send(self, data): """Logs the data to the log file.""" if options["globals", "verbose"]: state.logFile.write(data) state.logFile.flush() try: return POP3ProxyBase.send(self, data) except socket.error: self.close() def recv(self, size): """Logs the data to the log file.""" data = POP3ProxyBase.recv(self, size) if options["globals", "verbose"]: state.logFile.write(data) state.logFile.flush() return data def close(self): # This can be called multiple times by async. if not self.isClosed: self.isClosed = True state.activeSessions -= 1 POP3ProxyBase.close(self) def onTransaction(self, command, args, response): """Takes the raw request and response, and returns the (possibly processed) response to pass back to the email client. """ handler = self.handlers.get(command, self.onUnknown) return handler(command, args, response) def onRetr(self, command, args, response): """Classifies the message. If the result is ham, then simply pass it through. If the result is an unsure or spam, move it to the appropriate IMAP folder.""" # Use '\n\r?\n' to detect the end of the headers in case of # broken emails that don't use the proper line separators. if re.search(r'\n\r?\n', response): # Break off the first line, which will be '+OK'. ok, messageText = response.split('\n', 1) prob = state.bayes.spamprob(tokenize(messageText)) if prob < options["Categorization", "ham_cutoff"]: # Return the +OK and the message with the header added. state.numHams += 1 return ok + "\n" + messageText elif prob > options["Categorization", "spam_cutoff"]: dest_folder = self.spam_folder state.numSpams += 1 else: dest_folder = self.unsure_folder state.numUnsure += 1 msg = StringIO.StringIO(messageText) date = imaplib.Time2Internaldate(time.time())[1:-1] dest_folder.addMessage(msg, (), date) # We have to return something, because the client is expecting # us to. We return a short message indicating that a message # was intercepted. return ok + "\n" + self.intercept_message % (prob,) else: # Must be an error response. return response def onUnknown(self, command, args, response): """Default handler; returns the server's response verbatim.""" return response class MyBayesProxyListener(Dibbler.Listener): """Listens for incoming email client connections and spins off MyBayesProxy objects to serve them. """ def __init__(self, serverName, serverPort, proxyPort, spam, unsure): proxyArgs = (serverName, serverPort, spam, unsure) Dibbler.Listener.__init__(self, proxyPort, MyBayesProxy, proxyArgs) print 'Listener on port %s is proxying %s:%d' % \ (_addressPortStr(proxyPort), serverName, serverPort) class IMAPState(State): def __init__(self): State.__init__(self) # Set up the extra statistics. self.totalIMAPSessions = 0 self.activeIMAPSessions = 0 def buildServerStrings(self): """After the server details have been set up, this creates string versions of the details, for display in the Status panel.""" self.serverPortString = str(self.imap_port) # Also build proxy strings State.buildServerStrings(self) state = IMAPState() # =================================================================== # __main__ driver. # =================================================================== def setup(): # Setup app, boxes, trainers and account proxyListeners = [] app = Application("SpambayesIMAPServer") spam_box = SpambayesMailbox("Spam", 0, options["imapserver", "spam_directory"]) unsure_box = SpambayesMailbox("Unsure", 1, options["imapserver", "unsure_directory"]) ham_train_box = SpambayesMailbox("TrainAsHam", 2, options["imapserver", "ham_directory"]) spam_trainer = Trainer(spam_box, True) ham_trainer = Trainer(ham_train_box, False) spam_box.addListener(spam_trainer) ham_train_box.addListener(ham_trainer) user_account = SpambayesAccount(options["imapserver", "username"], ham_train_box, spam_box, unsure_box) # add IMAP4 server f = OneParameterFactory() f.protocol = SpambayesIMAPServer f.parameter = user_account state.imap_port = options["imapserver", "port"] app.listenTCP(state.imap_port, f) # add POP3 proxy state.createWorkers() for (server, serverPort), proxyPort in zip(state.servers, state.proxyPorts): listener = MyBayesProxyListener(server, serverPort, proxyPort, spam_box, unsure_box) proxyListeners.append(listener) state.buildServerStrings() # add web interface httpServer = UserInterfaceServer(state.uiPort) serverUI = ServerUserInterface(state, _recreateState) httpServer.register(serverUI) return app def run(): # Read the arguments. try: opts, args = getopt.getopt(sys.argv[1:], 'hbd:D:u:') except getopt.error, msg: print >>sys.stderr, str(msg) + '\n\n' + __doc__ sys.exit() launchUI = False for opt, arg in opts: if opt == '-h': print >>sys.stderr, __doc__ sys.exit() elif opt == '-b': launchUI = True elif opt == '-d': # dbm file state.useDB = True options["Storage", "persistent_storage_file"] = arg elif opt == '-D': # pickle file state.useDB = False options["Storage", "persistent_storage_file"] = arg elif opt == '-u': state.uiPort = int(arg) # Let the user know what they are using... print get_version_string("IMAP Server") print "and engine %s.\n" % (get_version_string(),) # setup everything app = setup() # kick things off thread.start_new_thread(Dibbler.run, (launchUI,)) app.run(save=False) if __name__ == "__main__": run() From anadelonbrin at users.sourceforge.net Sun Jul 27 01:51:41 2003 From: anadelonbrin at users.sourceforge.net (Tony Meyer) Date: Sun Jul 27 03:51:44 2003 Subject: [Spambayes-checkins] spambayes/scripts .cvsignore,NONE,1.1 Message-ID: Update of /cvsroot/spambayes/spambayes/scripts In directory sc8-pr-cvs1:/tmp/cvs-serv5323/scripts Added Files: .cvsignore Log Message: Ignore pyc, pyo, db and pik files. --- NEW FILE: .cvsignore --- *.pyc *.pyo *.db *.pik From mhammond at users.sourceforge.net Sun Jul 27 05:15:24 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Sun Jul 27 07:15:30 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000/docs troubleshooting.html, 1.12, 1.13 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000/docs In directory sc8-pr-cvs1:/tmp/cvs-serv4057a Modified Files: troubleshooting.html Log Message: Few tweaks based on user feedback. Index: troubleshooting.html =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/docs/troubleshooting.html,v retrieving revision 1.12 retrieving revision 1.13 diff -C2 -d -r1.12 -r1.13 *** troubleshooting.html 9 Jul 2003 00:33:37 -0000 1.12 --- troubleshooting.html 27 Jul 2003 11:15:22 -0000 1.13 *************** *** 46,52 **** installation type. 
    !
  • If you are running from source code, please re-register the ! addin, as per the README.txt file.
  • !
  • If you are running a binary version, then perform the following steps:
  • --- 46,51 ---- installation type. 
    !
  • If you are running a binary version (ie, you downloaded a single ! installation program), then perform the following steps:
  • *************** *** 86,89 **** --- 85,92 ---- +
      +
    • If you are running from source code, please re-register the + addin, as per the README.txt file.
    • +
    If none of that works, I am stumped!
      *************** *** 130,136 **** removing the file \Documents and Settings\{username}\Application Data\Microsoft\Outlook\outcmd.dat.  ! Keep a copy of the file in case this does something nasty to your ! system (it didn't to ours, and is documented a few places on the web, ! but we make no guarantees).
      --- 133,138 ---- removing the file \Documents and Settings\{username}\Application Data\Microsoft\Outlook\outcmd.dat.  ! Although this is undocumented by Microsoft, we have never heard reports ! of problems - but you may like to make a copy of the file just in case.
      From mhammond at users.sourceforge.net Sun Jul 27 17:46:50 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Sun Jul 27 19:46:54 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 msgstore.py,1.56,1.57 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv17439 Modified Files: msgstore.py Log Message: * Add IsReceiveFolder() * Add support for the test suite (which started failing as our testcase test message was "unsent", and therefore SpamBayes ignored it! * Move some orphaned comments from addin Index: msgstore.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/msgstore.py,v retrieving revision 1.56 retrieving revision 1.57 diff -C2 -d -r1.56 -r1.57 *** msgstore.py 25 Jul 2003 06:40:28 -0000 1.56 --- msgstore.py 27 Jul 2003 23:46:48 -0000 1.57 *************** *** 10,13 **** --- 10,15 ---- True, False = 1, 0 + # Nod to our automated test suite - we *do* want these messages filtered! + test_suite_running = False # Abstract definition - can be moved out when we have more than one sub-class *************** *** 482,485 **** --- 484,493 ---- yield msg + def IsReceiveFolder(self, msg_class = "IPM.Note"): + # Is this folder the nominated "receive folder" for its store? + mapi_store = self.msgstore._GetMessageStore(self.id[0]) + eid, ret_class = mapi_store.GetReceiveFolder(msg_class, 0) + return mapi_store.CompareEntryIDs(eid, self.id[1]) + class MAPIMsgStoreMsg(MsgStoreMsg): # All the properties we must initialize a message with. *************** *** 552,557 **** # * Non-mail items # * Messages that have never been sent (ie, user-composed) return self.msgclass.lower().startswith("ipm.note") and \ ! not self.is_unsent def _GetPotentiallyLargeStringProp(self, prop_id, row): --- 560,579 ---- # * Non-mail items # * Messages that have never been sent (ie, user-composed) + + # Note: While we handle messages that have never been sent, + # we dont handle messages that were sent and moved from the + # Sent Items folder. It would be good not to train on them, + # since they are simply not received email. An article on + # the web said the distinction can't be made with 100% + # certainty, but that a good heuristic is to believe that a + # msg has been received iff at least one of these properties + # has a sensible value: + # PR_RECEIVED_BY_EMAIL_ADDRESS + # PR_RECEIVED_BY_NAME + # PR_RECEIVED_BY_ENTRYID + # PR_TRANSPORT_MESSAGE_HEADERS + return self.msgclass.lower().startswith("ipm.note") and \ ! (not self.is_unsent or test_suite_running) def _GetPotentiallyLargeStringProp(self, prop_id, row): From mhammond at users.sourceforge.net Sun Jul 27 17:47:45 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Sun Jul 27 19:47:48 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 manager.py,1.67,1.68 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv17617 Modified Files: manager.py Log Message: The setting of "verbose" was a little confused. Now only the config file is used. Index: manager.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/manager.py,v retrieving revision 1.67 retrieving revision 1.68 diff -C2 -d -r1.67 -r1.68 *** manager.py 25 Jul 2003 06:40:28 -0000 1.67 --- manager.py 27 Jul 2003 23:47:43 -0000 1.68 *************** *** 190,194 **** # Our main "bayes manager" class BayesManager: ! def __init__(self, config_base="default", outlook=None, verbose=1): self.reported_error_map = {} self.reported_startup_error = False --- 190,194 ---- # Our main "bayes manager" class BayesManager: ! def __init__(self, config_base="default", outlook=None, verbose=0): self.reported_error_map = {} self.reported_startup_error = False *************** *** 716,728 **** _mgr = None ! def GetManager(outlook = None, verbose=1): global _mgr if _mgr is None: if outlook is None: outlook = win32com.client.Dispatch("Outlook.Application") ! _mgr = BayesManager(outlook=outlook, verbose=verbose) ! # If requesting greater verbosity, honour it ! if verbose > _mgr.verbose: ! _mgr.verbose = verbose return _mgr --- 716,725 ---- _mgr = None ! def GetManager(outlook = None): global _mgr if _mgr is None: if outlook is None: outlook = win32com.client.Dispatch("Outlook.Application") ! _mgr = BayesManager(outlook=outlook) return _mgr From mhammond at users.sourceforge.net Sun Jul 27 17:49:34 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Sun Jul 27 19:49:38 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 config.py, 1.16, 1.17 addin.py, 1.78, 1.79 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv17738 Modified Files: config.py addin.py Log Message: Add a new experimental 'timer'. This should prevent the addin from ever missing messages, and should also prevent SpamBayes from upsetting the builtin filters. NOTE: You need a new win32all to enable the timer (but no need to upgrade if you don't want to use it. Index: config.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/config.py,v retrieving revision 1.16 retrieving revision 1.17 diff -C2 -d -r1.16 -r1.17 *** config.py 20 Jul 2003 14:25:42 -0000 1.16 --- config.py 27 Jul 2003 23:49:32 -0000 1.17 *************** *** 108,111 **** --- 108,136 ---- INTEGER, RESTORE), ), + # Experimental options may change, may get removed, and *will* get moved + # should they be kept. + "Experimental" : ( + ("timer_start_delay", "The interval, (in ms) before the timer starts.", 0, + """Once a new item is received in the inbox, SpamBayes will begin + processing messages after the given delay. If a new message arrives + during this period, the timer will be reset and delay will start again.""", + INTEGER, RESTORE), + ("timer_interval", "The interval between subsequent timer checks (in ms)", 1000, + """Once the a new message timer found a new message, how long should + SpamBayes wait before checking for another new message, assuming no + other new messages arrive. Should a new message arrive during this + process, the timer will reset, meaning that timer_start_delay will + elapse before the process begins again.""", + INTEGER, RESTORE), + ("timer_only_receive_folders", + "Should the timer only be used for 'Inbox' type folders", True, + """The point of using a timer is to prevent the SpamBayes filter + getting in the way the builtin Outlook rules. Therefore, is it + generally only necessary to use a timer for folders that have new + items being delivered directly to them. Folders that are not inbox + style folders generally are not subject to builtin filtering, so + generally have no problems filtering messages in 'real time'.""", + BOOLEAN, RESTORE), + ), "Training" : ( (FolderIDOption, Index: addin.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/addin.py,v retrieving revision 1.78 retrieving revision 1.79 diff -C2 -d -r1.78 -r1.79 *** addin.py 26 Jul 2003 00:57:35 -0000 1.78 --- addin.py 27 Jul 2003 23:49:32 -0000 1.79 *************** *** 47,50 **** --- 47,52 ---- import win32gui, win32con, win32clipboard # for button images! + import timer, thread + toolbar_name = "SpamBayes" *************** *** 176,180 **** # I considered checking if the "save spam score" option is enabled - but # even when enabled, this sometimes fails (IMAP, hotmail) ! # Best we ca do not is to assume if it is read, we have seen it. return msgstore_message.GetReadState() --- 178,182 ---- # I considered checking if the "save spam score" option is enabled - but # even when enabled, this sometimes fails (IMAP, hotmail) ! # Best we can do now is to assume if it is read, we have seen it. return msgstore_message.GetReadState() *************** *** 227,256 **** class _BaseItemsEvent: def Init(self, target, application, manager): self.application = application self.manager = manager self.target = target def Close(self): self.application = self.manager = self.target = None - class FolderItemsEvent(_BaseItemsEvent): def OnItemAdd(self, item): - # Note: There's no distinction made here between msgs that have - # been received, and, e.g., msgs that were sent and moved from the - # Sent Items folder. It would be good not to train on the latter, - # since it's simply not received email. An article on the web said - # the distinction can't be made with 100% certainty, but that a good - # heuristic is to believe that a msg has been received iff at least - # one of these properties has a sensible value: - # PR_RECEIVED_BY_EMAIL_ADDRESS - # PR_RECEIVED_BY_NAME - # PR_RECEIVED_BY_ENTRYID - # PR_TRANSPORT_MESSAGE_HEADERS # Callback from Outlook - locale may have changed. locale.setlocale(locale.LC_NUMERIC, "C") # see locale comments above self.manager.LogDebug(2, "OnItemAdd event for folder", self, "with item", item) ! msgstore_message = self.manager.message_store.GetMessage(item) ! if msgstore_message is not None: ! ProcessMessage(msgstore_message, self.manager) # Event fired when item moved into the Spam folder. --- 229,356 ---- class _BaseItemsEvent: def Init(self, target, application, manager): + self.owner_thread_ident = thread.get_ident() # check we arent multi-threaded self.application = application self.manager = manager self.target = target + self.use_timer = False + def ReInit(self): + pass def Close(self): self.application = self.manager = self.target = None + self.close() # the events + + class HamFolderItemsEvent(_BaseItemsEvent): + def Init(self, *args): + _BaseItemsEvent.Init(self, *args) + + start_delay = self.manager.config.experimental.timer_start_delay + interval = self.manager.config.experimental.timer_interval + use_timer = start_delay and interval + if use_timer: + # The user wants to use a timer - see if we should only enable + # the timer for known 'inbox' folders, or for all watched folders. + is_inbox = self.target.IsReceiveFolder() + if not is_inbox and not self.manager.config.experimental.timer_only_receive_folders: + use_timer = False + + if use_timer and not hasattr(timer, "__version__"): + # No binaries will see this. + print "*" * 50 + print "SORRY: You have tried to enable the timer, but you have a" + print "leaky version of the 'timer' module. These leaks prevent" + print "Outlook from shutting down. Please update win32all to post 154" + print "The timer is NOT enabled..." + print "*" * 50 + use_timer = False + + # Good chance someone will assume timer is seconds, not ms. + if use_timer and (start_delay < 500 or interval < 500): + print "*" * 50 + print "The timer is configured to fire way too often " \ + "(delay=%s milliseconds, interval=%s milliseconds)" \ + % (start_delay, interval) + print "This is very high, and is likely to starve Outlook and the " + print "SpamBayes addin. Please adjust your configuration" + print "The timer is NOT enabled..." + print "*" * 50 + use_timer = False + + self.use_timer = use_timer + self.timer_id = None + + def ReInit(self): + # We may have swapped between timer and non-timer. + if self.use_timer: + self._KillTimer() + self.Init(self, self.target, self.application, self.manager) + + def Close(self, *args): + self._KillTimer() + _BaseItemsEvent.Close(self, *args) + def _DoStartTimer(self, delay): + assert thread.get_ident() == self.owner_thread_ident + assert self.timer_id is None, "Shouldn't start a timer when already have one" + # And start a new timer. + assert delay, "No delay means no timer!" + self.timer_id = timer.set_timer(delay, self._TimerFunc) + self.manager.LogDebug(1, "New message timer started - id=%d, delay=%d" % (self.timer_id, delay)) + + def _StartTimer(self): + # First kill any existing timer + self._KillTimer() + # And start a new timer. + delay = self.manager.config.experimental.timer_start_delay + field_name = self.manager.config.general.field_score_name + self.timer_generator = self.target.GetNewUnscoredMessageGenerator(field_name) + self._DoStartTimer(delay) + + def _KillTimer(self): + assert thread.get_ident() == self.owner_thread_ident + if self.timer_id is not None: + self.manager.LogDebug(2, "The timer with id=%d was stopped" % self.timer_id) + timer.kill_timer(self.timer_id) + self.timer_id = None + + def _TimerFunc(self, event, time): + # Kill the timer first + assert thread.get_ident() == self.owner_thread_ident + self._KillTimer() + assert self.timer_generator, "Can't have a timer with no generator" + # Callback from Outlook - locale may have changed. + locale.setlocale(locale.LC_NUMERIC, "C") # see locale comments above + # Find a single to item process + # If we did manage to process one, start a new timer. + # If we didn't, we are done and can wait until some external + # event triggers a new timer. + try: + item = self.timer_generator.next() + except StopIteration: + # No items left in our generator + self.timer_generator = None + self.manager.LogDebug(1, "The new message timer found no new items, so is stopping") + else: + # We have an item to process - do it. + try: + ProcessMessage(item, self.manager) + finally: + # And setup the timer for the next check. + delay = self.manager.config.experimental.timer_interval + self._DoStartTimer(delay) def OnItemAdd(self, item): # Callback from Outlook - locale may have changed. locale.setlocale(locale.LC_NUMERIC, "C") # see locale comments above self.manager.LogDebug(2, "OnItemAdd event for folder", self, "with item", item) ! # Due to the way our "missed message" indicator works, we do ! # a quick check here for "UnRead". If UnRead, we assume it is very ! # new and use our timer. If not unread, we know our missed message ! # generator would miss it, so we process it synchronously. ! if not self.use_timer or not item.UnRead: ! msgstore_message = self.manager.message_store.GetMessage(item) ! if msgstore_message is not None: ! ProcessMessage(msgstore_message, self.manager) ! else: ! self._StartTimer() # Event fired when item moved into the Spam folder. *************** *** 916,927 **** config.watch_folder_ids, config.watch_include_sub): ! num = 0 ! start = clock() ! for message in folder.GetNewUnscoredMessageGenerator(field_name): ! ProcessMessage(message, manager) ! num += 1 ! # See if perf hurts anyone too much. ! print "Processing %d missed spam in folder '%s' took %gms" \ ! % (num, folder.name, (clock()-start)*1000) def FiltersChanged(self): --- 1016,1033 ---- config.watch_folder_ids, config.watch_include_sub): ! event_hook = self._GetHookForFolder(folder) ! if event_hook.use_timer: ! print "Processing missed spam in folder '%s' by starting a timer" \ ! % (folder.name,) ! event_hook._StartTimer() ! else: ! num = 0 ! start = clock() ! for message in folder.GetNewUnscoredMessageGenerator(field_name): ! ProcessMessage(message, manager) ! num += 1 ! # See if perf hurts anyone too much. ! print "Processing %d missed spam in folder '%s' took %gms" \ ! % (num, folder.name, (clock()-start)*1000) def FiltersChanged(self): *************** *** 939,943 **** self._HookFolderEvents(config.watch_folder_ids, config.watch_include_sub, ! FolderItemsEvent) ) # For spam manually moved --- 1045,1049 ---- self._HookFolderEvents(config.watch_folder_ids, config.watch_include_sub, ! HamFolderItemsEvent) ) # For spam manually moved *************** *** 950,956 **** for k in self.folder_hooks.keys(): if not new_hooks.has_key(k): ! self.folder_hooks[k]._obj_.close() self.folder_hooks = new_hooks def _HookFolderEvents(self, folder_ids, include_sub, HandlerClass): new_hooks = {} --- 1056,1067 ---- for k in self.folder_hooks.keys(): if not new_hooks.has_key(k): ! self.folder_hooks[k].Close() self.folder_hooks = new_hooks + def _GetHookForFolder(self, folder): + ret = self.folder_hooks[folder.id] + assert ret.target == folder + return ret + def _HookFolderEvents(self, folder_ids, include_sub, HandlerClass): new_hooks = {} *************** *** 960,964 **** if existing is None or existing.__class__ != HandlerClass: folder = msgstore_folder.GetOutlookItem() ! name = folder.Name.encode("mbcs", "replace") try: new_hook = DispatchWithEvents(folder.Items, HandlerClass) --- 1071,1075 ---- if existing is None or existing.__class__ != HandlerClass: folder = msgstore_folder.GetOutlookItem() ! name = msgstore_folder.name try: new_hook = DispatchWithEvents(folder.Items, HandlerClass) *************** *** 967,971 **** new_hook = None if new_hook is not None: ! new_hook.Init(folder, self.application, self.manager) new_hooks[msgstore_folder.id] = new_hook self.manager.EnsureOutlookFieldsForFolder(msgstore_folder.GetID()) --- 1078,1082 ---- new_hook = None if new_hook is not None: ! new_hook.Init(msgstore_folder, self.application, self.manager) new_hooks[msgstore_folder.id] = new_hook self.manager.EnsureOutlookFieldsForFolder(msgstore_folder.GetID()) *************** *** 973,981 **** else: new_hooks[msgstore_folder.id] = existing return new_hooks def OnDisconnection(self, mode, custom): print "SpamBayes - Disconnecting from Outlook" ! self.folder_hooks = None self.application = None self.explorers_events = None --- 1084,1096 ---- else: new_hooks[msgstore_folder.id] = existing + exiting.ReInit() return new_hooks def OnDisconnection(self, mode, custom): print "SpamBayes - Disconnecting from Outlook" ! if self.folder_hooks: ! for hook in self.folder_hooks.values(): ! hook.Close() ! self.folder_hooks = None self.application = None self.explorers_events = None From mhammond at users.sourceforge.net Sun Jul 27 17:50:01 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Sun Jul 27 19:50:04 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 tester.py,1.9,1.10 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv18006 Modified Files: tester.py Log Message: Test timer based filtering. Index: tester.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/tester.py,v retrieving revision 1.9 retrieving revision 1.10 diff -C2 -d -r1.9 -r1.10 *** tester.py 20 Jul 2003 13:37:00 -0000 1.9 --- tester.py 27 Jul 2003 23:49:59 -0000 1.10 *************** *** 29,33 **** def WaitForFilters(): import pythoncom ! for i in range(100): pythoncom.PumpWaitingMessages() sleep(0.01) --- 29,34 ---- def WaitForFilters(): import pythoncom ! # Must wait longer than normal, so when run with a timer we still work. ! for i in range(500): pythoncom.PumpWaitingMessages() sleep(0.01) *************** *** 320,340 **** driver.CleanAllTestMessages() ! def test(manager = None): # Run the tests - called from our plugin. try: # setup config to save info with the message, and test ! print "Running tests with save_spam_info=True" manager.config.filter.save_spam_info = True run_tests(manager) # do it again with the same config, just to prove we can. ! print "Running them again with save_spam_info=True" run_tests(manager) # and with save_spam_info False. ! print "Running tests with save_spam_info=False" manager.config.filter.save_spam_info = False run_tests(manager) finally: # Always restore configuration to how we started. manager.LoadConfig() if __name__=='__main__': --- 321,354 ---- driver.CleanAllTestMessages() ! def test(manager): # Run the tests - called from our plugin. + import msgstore try: + msgstore.test_suite_running = True # setup config to save info with the message, and test ! print "*" * 10, "Running tests with save_spam_info=True, timer off" ! manager.config.experimental.timer_start_delay = 0 ! manager.config.experimental.timer_interval = 0 manager.config.filter.save_spam_info = True + manager.addin.FiltersChanged() # to ensure correct filtler in place run_tests(manager) # do it again with the same config, just to prove we can. ! print "*" * 10, "Running them again with save_spam_info=True" ! run_tests(manager) ! # enable the timer. ! manager.config.experimental.timer_start_delay = 1000 ! manager.config.experimental.timer_interval = 500 ! manager.addin.FiltersChanged() # to switch to timer based filters. ! print "*" * 10, "Running them again with save_spam_info=True, and timer enabled" run_tests(manager) # and with save_spam_info False. ! print "*" * 10, "Running tests with save_spam_info=False" manager.config.filter.save_spam_info = False run_tests(manager) finally: # Always restore configuration to how we started. + msgstore.test_suite_running = False manager.LoadConfig() + manager.addin.FiltersChanged() # restore original filters. if __name__=='__main__': From mhammond at users.sourceforge.net Sun Jul 27 19:53:40 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Sun Jul 27 21:53:44 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 addin.py,1.79,1.80 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv3357 Modified Files: addin.py Log Message: Oops - check the win32all version *before* we check if receive folder - this also came in the new win32all, so will throw an exception rather than gracefully disabling the timer of win32all is not up to date. Index: addin.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/addin.py,v retrieving revision 1.79 retrieving revision 1.80 diff -C2 -d -r1.79 -r1.80 *** addin.py 27 Jul 2003 23:49:32 -0000 1.79 --- addin.py 28 Jul 2003 01:53:38 -0000 1.80 *************** *** 247,257 **** interval = self.manager.config.experimental.timer_interval use_timer = start_delay and interval - if use_timer: - # The user wants to use a timer - see if we should only enable - # the timer for known 'inbox' folders, or for all watched folders. - is_inbox = self.target.IsReceiveFolder() - if not is_inbox and not self.manager.config.experimental.timer_only_receive_folders: - use_timer = False - if use_timer and not hasattr(timer, "__version__"): # No binaries will see this. --- 247,250 ---- *************** *** 263,266 **** --- 256,266 ---- print "*" * 50 use_timer = False + + if use_timer: + # The user wants to use a timer - see if we should only enable + # the timer for known 'inbox' folders, or for all watched folders. + is_inbox = self.target.IsReceiveFolder() + if not is_inbox and not self.manager.config.experimental.timer_only_receive_folders: + use_timer = False # Good chance someone will assume timer is seconds, not ms. From mhammond at users.sourceforge.net Sun Jul 27 21:18:13 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Sun Jul 27 23:18:16 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000/sandbox mapi_driver.py, 1.2, 1.3 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000/sandbox In directory sc8-pr-cvs1:/tmp/cvs-serv14222 Modified Files: mapi_driver.py Log Message: Silence "expected" errors. Index: mapi_driver.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/sandbox/mapi_driver.py,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** mapi_driver.py 21 Jul 2003 03:14:55 -0000 1.2 --- mapi_driver.py 28 Jul 2003 03:18:11 -0000 1.3 *************** *** 58,65 **** yield store, name, def_store except pythoncom.com_error, details: ! print "Error opening message store" ! print details ! print "Ignoring this store" ! def _FindSubfolder(self, store, folder, find_name): --- 58,67 ---- yield store, name, def_store except pythoncom.com_error, details: ! hr, msg, exc, arg_err = details ! if hr== mapi.MAPI_E_FAILONEPROVIDER: ! # not logged on etc. ! pass ! else: ! print "Error opening message store", details, "- ignoring" def _FindSubfolder(self, store, folder, find_name): From mhammond at users.sourceforge.net Sun Jul 27 21:24:19 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Sun Jul 27 23:24:22 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000/sandbox find_dupe_props.py, NONE, 1.1 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000/sandbox In directory sc8-pr-cvs1:/tmp/cvs-serv14316 Added Files: find_dupe_props.py Log Message: Little tool to find messages with duplicate property values. Useful to find message that SpamBayes will consider duplicate. Example, to messages with the same PR_SEARCH_KEY property in 2 folders: % find_dupe_props.py -f "\Good spam-looing mail" -f Inbox PR_SEARCH_KEY Folder '... mail': 48 items with the property and 0 items without it Folder 'Inbox': 1699 items with the property and 0 items without it Found 2 items with property value '...fK\xb0\x95\xb9\xa7s\xce\x93\xcd' Courtesy notification - 50% of your current month's allowance used Courtesy notification - 50% of your current month's allowance used ... This output shows the folders scanned, and the subjects for all messages with an identical PR_SEARCH_KEY property (which is the property used by SpamBayes to track training data). This shows that 2 items with identical subjects have the same ID - ie, these are copies of the same message. --- NEW FILE: find_dupe_props.py --- from __future__ import generators # Dump every property we can find for a MAPI item import pythoncom import os, sys from win32com.mapi import mapi, mapiutil from win32com.mapi.mapitags import * import mapi_driver def FindDupeProps(driver, mapi_folder, prop_tag, dupe_dict): hr, data = mapi_folder.GetProps( (PR_DISPLAY_NAME_A,), 0) name = data[0][1] try: prop_tag = int(prop_tag) except ValueError: # See if a constant in mapitags. if prop_tag.startswith("PR_") and prop_tag in globals(): prop_tag = globals()[prop_tag] else: props = ( (mapi.PS_PUBLIC_STRINGS, prop_tag), ) ids = mapi_folder.GetIDsFromNames(props, 0) if PROP_ID(ids[0])==0: print "Could not resolve property '%s'" % prop_tag return 1 prop_tag = PROP_TAG( PT_UNSPECIFIED, PROP_ID(ids[0])) num_with_prop = num_without_prop = 0 for item in driver.GetAllItems(mapi_folder): hr, data = item.GetProps( (prop_tag,PR_SUBJECT_A, PR_ENTRYID), 0) if hr==0: (tag_hr, tag_data) = data[0] (subject_hr, subject_data) = data[1] (eid_hr, eid_data) = data[2] dupe_dict.setdefault(tag_data, []).append((eid_data, subject_data)) num_with_prop += 1 else: num_without_prop += 1 print "Folder '%s': %d items with the property and %d items without it" \ % (name, num_with_prop, num_without_prop) def DumpDupes(dupe_dict): for val, items in dupe_dict.items(): if len(items)>1: print "Found %d items with property value %r" % (len(items), val) for (eid, subject) in items: print "", subject def usage(driver): folder_doc = driver.GetFolderNameDoc() msg = """\ Usage: %s [-f foldername] [-f ...] property_name_or_tag -f - Search for the message in the specified folders (default = Inbox) -n - Show top-level folder names and exit Dumps all properties for all messages that match the subject. Subject matching is substring and ignore-case. %s Use the -n option to see all top-level folder names from all stores.""" \ % (os.path.basename(sys.argv[0]),folder_doc) print msg def main(): driver = mapi_driver.MAPIDriver() import getopt try: opts, args = getopt.getopt(sys.argv[1:], "f:n") except getopt.error, e: print e print usage(driver) sys.exit(1) folder_names = [] for opt, opt_val in opts: if opt == "-f": folder_names.append(opt_val) elif opt == "-n": driver.DumpTopLevelFolders() sys.exit(1) else: print "Invalid arg" return if not folder_names: folder_names = ["Inbox"] # Assume this exists! if len(args) != 1: print "You must specify a property tag/name" print usage(driver) sys.exit(1) dupe_dict = {} for folder_name in folder_names: try: folder = driver.FindFolder(folder_name) except ValueError, details: print details sys.exit(1) FindDupeProps(driver, folder, args[0], dupe_dict) DumpDupes(dupe_dict) if __name__=='__main__': main() From montanaro at users.sourceforge.net Mon Jul 28 05:51:38 2003 From: montanaro at users.sourceforge.net (Skip Montanaro) Date: Mon Jul 28 07:51:42 2003 Subject: [Spambayes-checkins] website faq.txt,1.16,1.17 Message-ID: Update of /cvsroot/spambayes/website In directory sc8-pr-cvs1:/tmp/cvs-serv26013 Modified Files: faq.txt Log Message: show how to search the mailing lists' archives using google Index: faq.txt =================================================================== RCS file: /cvsroot/spambayes/website/faq.txt,v retrieving revision 1.16 retrieving revision 1.17 diff -C2 -d -r1.16 -r1.17 *** faq.txt 23 Jul 2003 11:43:29 -0000 1.16 --- faq.txt 28 Jul 2003 11:51:36 -0000 1.17 *************** *** 77,80 **** --- 77,91 ---- developers. + All the mailing lists are managed by Mailman, which uses pipermail to + archive messages. There is no search capability, so your best bet is to use + Google to search for stuff. For example, searching for + + :: + + site:mail.python.org pop3proxy -checkins + + would search for messages which mention pop3proxy but exclude checkin + messages. + .. _Spambayes list: http://mail.python.org/mailman/listinfo/spambayes .. _Spambayes developers list: http://mail.python.org/mailman/listinfo/spambayes-dev From montanaro at users.sourceforge.net Mon Jul 28 06:25:49 2003 From: montanaro at users.sourceforge.net (Skip Montanaro) Date: Mon Jul 28 08:25:52 2003 Subject: [Spambayes-checkins] website faq.txt,1.17,1.18 Message-ID: Update of /cvsroot/spambayes/website In directory sc8-pr-cvs1:/tmp/cvs-serv30902 Modified Files: faq.txt Log Message: add new "known problems" section and q&a about pop3proxy/fetchmail problems. Index: faq.txt =================================================================== RCS file: /cvsroot/spambayes/website/faq.txt,v retrieving revision 1.17 retrieving revision 1.18 diff -C2 -d -r1.17 -r1.18 *** faq.txt 28 Jul 2003 11:51:36 -0000 1.17 --- faq.txt 28 Jul 2003 12:25:46 -0000 1.18 *************** *** 762,765 **** --- 762,775 ---- + Known Problems & Workarounds + ============================ + + Pop3proxy doesn't work with fetchmail. + -------------------------------------- + + This is a known problem. To work around it, use fetchmail's ``fetchall`` + option. + + Development =========== From mhammond at users.sourceforge.net Mon Jul 28 06:40:46 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Mon Jul 28 08:40:50 2003 Subject: [Spambayes-checkins] spambayes/spambayes Version.py,1.8,1.9 Message-ID: Update of /cvsroot/spambayes/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv427 Modified Files: Version.py Log Message: Support fetching the "latest" set of version data from the spambayes web site. Index: Version.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/spambayes/Version.py,v retrieving revision 1.8 retrieving revision 1.9 diff -C2 -d -r1.8 -r1.9 *** Version.py 22 Jul 2003 06:09:03 -0000 1.8 --- Version.py 28 Jul 2003 12:40:44 -0000 1.9 *************** *** 1,3 **** ! """Simple version repository for SpamBayes core, and our main apps""" # This module is part of the spambayes project, which is Copyright 2002-3 --- 1,15 ---- ! #! /usr/bin/env python ! """Simple version repository for SpamBayes core, and our main apps. ! ! Also has the ability to load this version information from a remote location ! (in that case, we actually load a "ConfigParser" version of the file to ! avoid importing code we can't trust.) This allows any app to check if there ! is a later version available. ! ! The makefile process for the website will execute this as a script, which ! will generate the "ConfigParser" version for the web. ! """ ! ! LATEST_VERSION_HOME="http://www.spambayes.org/download/Version.cfg" # This module is part of the spambayes project, which is Copyright 2002-3 *************** *** 26,29 **** --- 38,45 ---- "Full Description Binary": "%(Description)s, Binary version %(BinaryVersion)s (%(Date)s)", + # Note this means we can change the download page later, and old + # versions will still go to the new page. + # We may also like to have a "Release Notes Page" item later? + "Download Page": "http://starship.python.net/crew/mhammond/spambayes" }, "POP3 Proxy" : { *************** *** 60,72 **** } ! def get_version_string(app = None, description_key = "Full Description"): """Get a pretty version string, generally just to log or show in a UI""" if app is None: ! dict = versions else: ! dict = versions["Apps"][app] return dict[description_key] % dict ! def get_version_number(app = None, version_key = "Version"): """Get a version number, as a float. This would primarily be used so some app or extension can determine if we are later than a specific version --- 76,93 ---- } ! def get_version_string(app = None, ! description_key = "Full Description", ! version_dict = None): """Get a pretty version string, generally just to log or show in a UI""" + if version_dict is None: version_dict = versions if app is None: ! dict = version_dict else: ! dict = version_dict["Apps"][app] return dict[description_key] % dict ! def get_version_number(app = None, ! version_key = "Version", ! version_dict = None): """Get a version number, as a float. This would primarily be used so some app or extension can determine if we are later than a specific version *************** *** 74,84 **** Maybe YAGNI. """ if app is None: ! dict = versions else: ! dict = versions["Apps"][app] return dict[version_key] if __name__=='__main__': print "SpamBayes version is:", get_version_string() # Enumerate applications --- 95,163 ---- Maybe YAGNI. """ + if version_dict is None: version_dict = versions if app is None: ! dict = version_dict else: ! dict = version_dict["Apps"][app] return dict[version_key] + # Utilities to check the "latest" version of an app. + # Assumes that a 'config' version of this file exists at the given URL + # No exceptions are caught + import ConfigParser + class MySafeConfigParser(ConfigParser.SafeConfigParser): + def optionxform(self, optionstr): + return optionstr # no lower! + + def fetch_latest_dict(url=LATEST_VERSION_HOME): + import ConfigParser, urllib2 + stream = urllib2.urlopen(url) + cfg = MySafeConfigParser() + cfg.readfp(stream) + ret_dict = {} + apps_dict = ret_dict["Apps"] = {} + for sect in cfg.sections(): + if sect=="SpamBayes": + target_dict = ret_dict + else: + target_dict = apps_dict.setdefault(sect, {}) + for opt in cfg.options(sect): + val = cfg.get(sect, opt) + # some butchering + try: + val = float(val) + except ValueError: + pass + target_dict[opt] = val + return ret_dict + + # Utilities for generating a 'config' version of this file. + # The output of this should exist at the URL above. + def _make_cfg_section(stream, key, this_dict): + stream.write("[%s]\n" % key) + for name, val in this_dict.items(): + if type(val)==type(''): + val_str = repr(val)[1:-1] + elif type(val)==type(0.0): + val_str = str(val) + elif type(val)==type({}): + val_str = None # sub-dict + else: + print "Skipping unknown value type: %r" % val + val_str = None + if val_str is not None: + stream.write("%s:%s\n" % (name, val_str)) + stream.write("\n") + + def make_cfg(stream): + _make_cfg_section(stream, "SpamBayes", versions) + for appname in versions["Apps"]: + _make_cfg_section(stream, appname, versions["Apps"][appname]) + if __name__=='__main__': + import sys + if '-g' in sys.argv: + make_cfg(sys.stdout) + sys.exit(0) print "SpamBayes version is:", get_version_string() # Enumerate applications *************** *** 87,88 **** --- 166,185 ---- for app in versions["Apps"]: print "%s: %s" % (app, get_version_string(app)) + + print + print "Fetching the lastest version information..." + try: + latest_dict = fetch_latest_dict() + except: + print "FAILED to fetch the latest version" + import traceback + traceback.print_exc() + sys.exit(1) + + print + print "SpamBayes version is:", get_version_string(version_dict=latest_dict) + # Enumerate applications + print + print "Application versions:" + for app in latest_dict["Apps"]: + print "%s: %s" % (app, get_version_string(app, version_dict=latest_dict)) From mhammond at users.sourceforge.net Mon Jul 28 06:58:44 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Mon Jul 28 08:58:47 2003 Subject: [Spambayes-checkins] website Makefile,1.5,1.6 Message-ID: Update of /cvsroot/spambayes/website In directory sc8-pr-cvs1:/tmp/cvs-serv2985 Modified Files: Makefile Log Message: This is supposed to get a Version.cfg on the main Spambayes web site, but I can't make it work. See spambayes/Version.py for details. Index: Makefile =================================================================== RCS file: /cvsroot/spambayes/website/Makefile,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** Makefile 23 Jul 2003 15:32:55 -0000 1.5 --- Makefile 28 Jul 2003 12:58:42 -0000 1.6 *************** *** 1,4 **** # this def'n must occur before the include! ! EXTRA_TARGETS = reply.txt faq.html default.css include scripts/make.rules --- 1,4 ---- # this def'n must occur before the include! ! EXTRA_TARGETS = reply.txt faq.html default.css download/Version.cfg include scripts/make.rules *************** *** 20,21 **** --- 20,24 ---- faq.html : faq.ht ./scripts/ht2html/ht2html.py -f -s SpamBayesFAQGenerator -r . ./faq.ht + + download/Version.cfg: ../spambayes/Version.py + ../spambayes/Version.py -g > download/Version.cfg From mhammond at users.sourceforge.net Mon Jul 28 07:02:05 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Mon Jul 28 09:02:13 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 addin.py,1.80,1.81 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv3908 Modified Files: addin.py Log Message: Variation on Skip's "Check latest version" Index: addin.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/addin.py,v retrieving revision 1.80 retrieving revision 1.81 diff -C2 -d -r1.80 -r1.81 *** addin.py 28 Jul 2003 01:53:38 -0000 1.80 --- addin.py 28 Jul 2003 13:02:03 -0000 1.81 *************** *** 476,479 **** --- 476,525 ---- new_msg.Display() + def CheckLatestVersion(manager): + from spambayes.Version import get_version_string, get_version_number, fetch_latest_dict + if hasattr(sys, "frozen"): + version_number_key = "BinaryVersion" + version_string_key = "Full Description Binary" + else: + version_number_key = "Version" + version_string_key = "Full Description" + + app_name = "Outlook" + cur_ver_string = get_version_string(app_name, version_string_key) + cur_ver_num = get_version_number(app_name, version_number_key) + + try: + win32ui.DoWaitCursor(1) + latest = fetch_latest_dict() + win32ui.DoWaitCursor(0) + latest_ver_string = get_version_string(app_name, version_string_key, + version_dict=latest) + latest_ver_num = get_version_number(app_name, version_number_key, + version_dict=latest) + except: + print "Error checking the latest version" + traceback.print_exc() + manager.ReportError( + "There was an error checking for the latest version\r\n" + "For specific details on the error, please see the SpamBayes log" + "\r\n\r\nPlease check your internet connection, or try again later" + ) + return + + print "Current version is %s, latest is %s." % (cur_ver_num, latest_ver_num) + if latest_ver_num > cur_ver_num: + url = get_version_string(app_name, "Download Page", version_dict=latest) + msg = "You are running %s\r\n\r\nThe latest available version is %s" \ + "\r\n\r\nThe download page for the latest version is\r\n%s" \ + "\r\n\r\nWould you like to visit this page now?" \ + % (cur_ver_string, latest_ver_string, url) + rc = win32ui.MessageBox(msg, "SpamBayes", win32con.MB_YESNO) + if rc == win32con.IDYES: + print "Opening browser page", url + os.startfile(url) + else: + win32ui.MessageBox("You are already running the latest version", + "SpamBayes") + # A hook for whatever tests we have setup def Tester(manager): *************** *** 709,712 **** --- 755,765 ---- Visible=True, Tag = "SpamBayesCommand.Clues") + self._AddControl(popup, + constants.msoControlButton, + ButtonEvent, (CheckLatestVersion, self.manager,), + Caption="Check for new version", + Enabled=True, + Visible=True, + Tag = "SpamBayesCommand.CheckVersion") # If we are running from Python sources, enable a few extra items if not hasattr(sys, "frozen"): From mhammond at users.sourceforge.net Mon Jul 28 08:06:01 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Mon Jul 28 10:06:03 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000/installer spambayes_addin.iss, 1.5, 1.6 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000/installer In directory sc8-pr-cvs1:/tmp/cvs-serv14003 Modified Files: spambayes_addin.iss Log Message: Ready for the next build, and check that Outlook isn't running at install time. Index: spambayes_addin.iss =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/installer/spambayes_addin.iss,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** spambayes_addin.iss 22 Jul 2003 06:25:16 -0000 1.5 --- spambayes_addin.iss 28 Jul 2003 14:05:59 -0000 1.6 *************** *** 5,10 **** [Setup] AppName=Spambayes Outlook Addin ! AppVerName=Spambayes Outlook Addin 0.5 ! AppVersion=0.5 DefaultDirName={pf}\Spambayes Outlook Addin DefaultGroupName=Spambayes Outlook Addin --- 5,10 ---- [Setup] AppName=Spambayes Outlook Addin ! AppVerName=Spambayes Outlook Addin 0.6 ! AppVersion=0.6 DefaultDirName={pf}\Spambayes Outlook Addin DefaultGroupName=Spambayes Outlook Addin *************** *** 23,36 **** function InitializeSetup(): Boolean; begin ! Result := true; ! if not RegKeyExists( HKCU, 'Software\Microsoft\Office\Outlook') then ! begin ! Result := MsgBox( ! 'Outlook appears to not be installed.' + #13 + #13 + ! 'This addin only works with Microsoft Outlook 2000 and later - it' + #13 + ! 'does not work with Outlook express.' + #13 + #13 + ! 'If you know that Outlook is installed, you may with to continue.' + #13 + #13 + ! 'Continue with installation?', ! mbConfirmation, MB_YESNO) = idYes; end; end; --- 23,45 ---- function InitializeSetup(): Boolean; begin ! Result := true; ! if not RegKeyExists( HKCU, 'Software\Microsoft\Office\Outlook') then begin ! Result := MsgBox( ! 'Outlook appears to not be installed.' + #13 + #13 + ! 'This addin only works with Microsoft Outlook 2000 and later - it' + #13 + ! 'does not work with Outlook express.' + #13 + #13 + ! 'If you know that Outlook is installed, you may with to continue.' + #13 + #13 + ! 'Continue with installation?', ! mbConfirmation, MB_YESNO) = idYes; ! end; ! while Result do begin ! if not CheckForMutexes('_outlook_mutex_') then ! break; ! ! Result := MsgBox( ! 'You must close Outlook before SpamBayes can be installed.' + #13 + #13 + ! 'Please close all Outlook Windows and click Retry' + #13 + ! 'or click Cancel to exit the installation.', ! mbConfirmation, MB_RETRYCANCEL) = idRetry; end; end; From montanaro at users.sourceforge.net Mon Jul 28 08:16:24 2003 From: montanaro at users.sourceforge.net (Skip Montanaro) Date: Mon Jul 28 10:16:26 2003 Subject: [Spambayes-checkins] website/download Makefile,NONE,1.1 Message-ID: Update of /cvsroot/spambayes/website/download In directory sc8-pr-cvs1:/tmp/cvs-serv15522 Added Files: Makefile Log Message: new file --- NEW FILE: Makefile --- include ../scripts/make.rules ROOT_DIR = .. ROOT_OFFSET = download From montanaro at users.sourceforge.net Mon Jul 28 08:17:19 2003 From: montanaro at users.sourceforge.net (Skip Montanaro) Date: Mon Jul 28 10:17:24 2003 Subject: [Spambayes-checkins] website/download Version.cfg,NONE,1.1 Message-ID: Update of /cvsroot/spambayes/website/download In directory sc8-pr-cvs1:/tmp/cvs-serv15685 Added Files: Version.cfg Log Message: new (generated) file --- NEW FILE: Version.cfg --- [SpamBayes] Date:July 2003 Full Description:%(Description)s, version %(Version)s (%(Date)s) Version:0.2 Description:SpamBayes Beta2 [SMTP Proxy] Date:May 2003 Full Description:%(Description)s, version %(Version)s (%(Date)s) Version:0.01 Description:SpamBayes SMTP Proxy Alpha1 [POP3 Proxy] Description:SpamBayes POP3 Proxy Beta1 InterfaceDescription:SpamBayes POP3 Proxy Web Interface Alpha2 Full Description:%(Description)s, version %(Version)s (%(Date)s),\nusing %(InterfaceDescription)s, version %(InterfaceVersion)s Version:0.1 Date:May 2003 InterfaceVersion:0.02 [IMAP Filter] Description:SpamBayes IMAP Filter Alpha1 InterfaceDescription:SpamBayes IMAP Filter Web Interface Alpha1 Full Description:%(Description)s, version %(Version)s (%(Date)s),\nusing %(InterfaceDescription)s, version %(InterfaceVersion)s Version:0.01 Date:May 2003 InterfaceVersion:0.01 [Outlook] BinaryVersion:0.5 Download Page:http://starship.python.net/crew/mhammond/spambayes Description:SpamBayes Outlook Addin (beta) Full Description:%(Description)s, version %(Version)s (%(Date)s) Version:0.4 Date:July 2003 Full Description Binary:%(Description)s, Binary version %(BinaryVersion)s (%(Date)s) [Lotus Notes Filter] Date:March 2003 Full Description:%(Description)s, version %(Version)s (%(Date)s) Version:0.01 Description:SpamBayes Lotus Notes Filter Alpha1 [Hammie] Date:January 2003 Full Description:%(Description)s, version %(Version)s (%(Date)s) Version:0.1 Description:SpamBayes command line tool (Hammie) Beta1 From montanaro at users.sourceforge.net Mon Jul 28 08:18:40 2003 From: montanaro at users.sourceforge.net (Skip Montanaro) Date: Mon Jul 28 10:18:48 2003 Subject: [Spambayes-checkins] website Makefile,1.6,1.7 Message-ID: Update of /cvsroot/spambayes/website In directory sc8-pr-cvs1:/tmp/cvs-serv15896 Modified Files: Makefile Log Message: generate download/Version.cfg install target for the download directory Index: Makefile =================================================================== RCS file: /cvsroot/spambayes/website/Makefile,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -d -r1.6 -r1.7 *** Makefile 28 Jul 2003 12:58:42 -0000 1.6 --- Makefile 28 Jul 2003 14:18:38 -0000 1.7 *************** *** 4,8 **** include scripts/make.rules ROOT_DIR = . ! ROOT_OFFSET = . $(TARGETS): links.h --- 4,8 ---- include scripts/make.rules ROOT_DIR = . ! ROOT_OFFSET = . $(TARGETS): links.h *************** *** 22,24 **** download/Version.cfg: ../spambayes/Version.py ! ../spambayes/Version.py -g > download/Version.cfg --- 22,28 ---- download/Version.cfg: ../spambayes/Version.py ! python ../spambayes/Version.py -g > download/Version.cfg ! ! local_install: ! cd download ; $(MAKE) install ! From richiehindle at users.sourceforge.net Mon Jul 28 14:13:57 2003 From: richiehindle at users.sourceforge.net (Richie Hindle) Date: Mon Jul 28 16:14:00 2003 Subject: [Spambayes-checkins] spambayes pop3proxy.py,1.88,1.89 Message-ID: Update of /cvsroot/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv17601 Modified Files: pop3proxy.py Log Message: Made the pop3proxy work with fetchmail, which uses "TOP N 99999999" instead of "RETR N" to retrieve messages. When proxying a single-message LIST command, add the header-size fudge factor to the message size rather than the message number (must have been a Friday afternoon...) Index: pop3proxy.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/pop3proxy.py,v retrieving revision 1.88 retrieving revision 1.89 diff -C2 -d -r1.88 -r1.89 *** pop3proxy.py 19 Jul 2003 09:15:00 -0000 1.88 --- pop3proxy.py 28 Jul 2003 20:13:55 -0000 1.89 *************** *** 172,176 **** self.set_terminator('\r\n') self.command = '' # The POP3 command being processed... ! self.args = '' # ...and its arguments self.isClosing = False # Has the server closed the socket? self.seenAllHeaders = False # For the current RETR or TOP --- 172,176 ---- self.set_terminator('\r\n') self.command = '' # The POP3 command being processed... ! self.args = [] # ...and its arguments self.isClosing = False # Has the server closed the socket? self.seenAllHeaders = False # For the current RETR or TOP *************** *** 254,261 **** if self.request.strip() == '': # Someone just hit the Enter key. ! self.command = self.args = '' else: # A proper command. ! splitCommand = self.request.strip().split(None, 1) self.command = splitCommand[0].upper() self.args = splitCommand[1:] --- 254,262 ---- if self.request.strip() == '': # Someone just hit the Enter key. ! self.command = '' ! self.args = [] else: # A proper command. ! splitCommand = self.request.strip().split() self.command = splitCommand[0].upper() self.args = splitCommand[1:] *************** *** 284,288 **** # Reset. self.command = '' ! self.args = '' self.isClosing = False self.seenAllHeaders = False --- 285,289 ---- # Reset. self.command = '' ! self.args = [] self.isClosing = False self.seenAllHeaders = False *************** *** 396,400 **** outputLines = [lines[0]] for line in lines[1:]: ! match = re.search('^(\d+)\s+(\d+)', line) if match: number = int(match.group(1)) --- 397,401 ---- outputLines = [lines[0]] for line in lines[1:]: ! match = re.search(r'^(\d+)\s+(\d+)', line) if match: number = int(match.group(1)) *************** *** 405,412 **** else: # Single line. ! match = re.search('^\+OK\s+(\d+)(.*)\r\n', response) if match: ! size = int(match.group(1)) + HEADER_SIZE_FUDGE_FACTOR ! return "+OK %d%s\r\n" % (size, match.group(2)) else: return response --- 406,415 ---- else: # Single line. ! match = re.search(r'^\+OK\s+(\d+)\s+(\d+)(.*)\r\n', response) if match: ! messageNumber = match.group(1) ! size = int(match.group(2)) + HEADER_SIZE_FUDGE_FACTOR ! trailer = match.group(3) ! return "+OK %s %s%s\r\n" % (messageNumber, size, trailer) else: return response *************** *** 437,441 **** msg.addSBHeaders(prob, clues) ! if command == 'RETR': cls = msg.GetClassification() if cls == options["Hammie", "header_ham_string"]: --- 440,448 ---- msg.addSBHeaders(prob, clues) ! # Check for "RETR" or "TOP N 99999999" - fetchmail without ! # the 'fetchall' option uses the latter to retrieve messages. ! if (command == 'RETR' or ! (command == 'TOP' and ! len(args) == 2 and args[1] == '99999999')): cls = msg.GetClassification() if cls == options["Hammie", "header_ham_string"]: From richiehindle at users.sourceforge.net Mon Jul 28 14:19:54 2003 From: richiehindle at users.sourceforge.net (Richie Hindle) Date: Mon Jul 28 16:19:57 2003 Subject: [Spambayes-checkins] website faq.txt,1.18,1.19 Message-ID: Update of /cvsroot/spambayes/website In directory sc8-pr-cvs1:/tmp/cvs-serv20305 Modified Files: faq.txt Log Message: The pop3proxy now works with fetchmail - FAQ updated. Index: faq.txt =================================================================== RCS file: /cvsroot/spambayes/website/faq.txt,v retrieving revision 1.18 retrieving revision 1.19 diff -C2 -d -r1.18 -r1.19 *** faq.txt 28 Jul 2003 12:25:46 -0000 1.18 --- faq.txt 28 Jul 2003 20:19:52 -0000 1.19 *************** *** 768,773 **** -------------------------------------- ! This is a known problem. To work around it, use fetchmail's ``fetchall`` ! option. --- 768,773 ---- -------------------------------------- ! This is a known problem in releases up to and including 1.0a4, fixed in CVS ! on 28th July 2003. To work around it, use fetchmail's ``fetchall`` option. From mhammond at users.sourceforge.net Mon Jul 28 18:34:52 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Mon Jul 28 20:34:54 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 msgstore.py,1.57,1.58 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv6514 Modified Files: msgstore.py Log Message: Change the way we detect 'unsent' items - this way catches both unsent items, and copies of sent items. The latter is important when you filter folders other than the inbox, and you have outlook to keep copies of sent items in the current folder rather than in "Sent Items". Previously, these items were trained on, inadequate headers and all. Note that mails sent by you and actually received back *are* still filtered. (If we go the "timer" approach, the it will be far more necessary to watch folders that are the target of Outlook's builtin rules) Index: msgstore.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/msgstore.py,v retrieving revision 1.57 retrieving revision 1.58 diff -C2 -d -r1.57 -r1.58 *** msgstore.py 27 Jul 2003 23:46:48 -0000 1.57 --- msgstore.py 29 Jul 2003 00:34:50 -0000 1.58 *************** *** 497,501 **** PR_PARENT_ENTRYID, # folder ID PR_MESSAGE_CLASS_A, # 'IPM.Note' etc ! PR_MESSAGE_FLAGS, #unsent, from_me ) --- 497,501 ---- PR_PARENT_ENTRYID, # folder ID PR_MESSAGE_CLASS_A, # 'IPM.Note' etc ! PR_RECEIVED_BY_ENTRYID, # who received it ) *************** *** 510,514 **** tag, parent_eid = prop_row[3] tag, msgclass = prop_row[4] ! tag, flags = prop_row[5] self.id = store_eid, eid --- 510,514 ---- tag, parent_eid = prop_row[3] tag, msgclass = prop_row[4] ! recby_tag, recby = prop_row[5] self.id = store_eid, eid *************** *** 522,526 **** # Thus, searchkey is our long-lived message key. self.searchkey = searchkey ! self.is_unsent = flags & MSGFLAG_UNSENT self.dirty = False --- 522,537 ---- # Thus, searchkey is our long-lived message key. self.searchkey = searchkey ! # To check if a message has ever been received, we check the ! # PR_RECEIVED_BY_ENTRYID flag. Tim wrote in an old comment that ! # An article on the web said the distinction can't be made with 100% ! # certainty, but that a good heuristic is to believe that a ! # msg has been received iff at least one of these properties ! # has a sensible value: RECEIVED_BY_EMAIL_ADDRESS, RECEIVED_BY_NAME, ! # RECEIVED_BY_ENTRYID PR_TRANSPORT_MESSAGE_HEADERS ! # But MarkH can't find it, and believes and tests that ! # PR_RECEIVED_BY_ENTRYID is all we need. ! # This also means we don't need to check the 'unsent' flag - unsent ! # messages never have the PR_RECEIVED_ properties either. ! self.was_received = PROP_TYPE(recby_tag) == PT_BINARY self.dirty = False *************** *** 559,579 **** # We don't attempt to filter: # * Non-mail items ! # * Messages that have never been sent (ie, user-composed) ! ! # Note: While we handle messages that have never been sent, ! # we dont handle messages that were sent and moved from the ! # Sent Items folder. It would be good not to train on them, ! # since they are simply not received email. An article on ! # the web said the distinction can't be made with 100% ! # certainty, but that a good heuristic is to believe that a ! # msg has been received iff at least one of these properties ! # has a sensible value: ! # PR_RECEIVED_BY_EMAIL_ADDRESS ! # PR_RECEIVED_BY_NAME ! # PR_RECEIVED_BY_ENTRYID ! # PR_TRANSPORT_MESSAGE_HEADERS ! return self.msgclass.lower().startswith("ipm.note") and \ ! (not self.is_unsent or test_suite_running) def _GetPotentiallyLargeStringProp(self, prop_id, row): --- 570,579 ---- # We don't attempt to filter: # * Non-mail items ! # * Messages that weren't actually received - this generally means user ! # composed messages yet to be sent, or copies of "sent items". ! # It does *not* exclude messages that were user composed, but still ! # actually received by the user (ie, when you mail yourself) return self.msgclass.lower().startswith("ipm.note") and \ ! (self.was_received or test_suite_running) def _GetPotentiallyLargeStringProp(self, prop_id, row): From mhammond at users.sourceforge.net Mon Jul 28 18:35:26 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Mon Jul 28 20:35:29 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000/sandbox dump_props.py, 1.8, 1.9 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000/sandbox In directory sc8-pr-cvs1:/tmp/cvs-serv6942/sandbox Modified Files: dump_props.py Log Message: Sort the property tags - much easier when comparing 2 messages. Index: dump_props.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/sandbox/dump_props.py,v retrieving revision 1.8 retrieving revision 1.9 diff -C2 -d -r1.8 -r1.9 *** dump_props.py 23 Jul 2003 06:12:21 -0000 1.8 --- dump_props.py 29 Jul 2003 00:35:24 -0000 1.9 *************** *** 44,48 **** def DumpItemProps(item, shorten, get_large_props): ! for prop_name, prop_tag, prop_val in GetAllProperties(item): if get_large_props and \ PROP_TYPE(prop_tag)==PT_ERROR and \ --- 44,50 ---- def DumpItemProps(item, shorten, get_large_props): ! all_props = GetAllProperties(item) ! all_props.sort() # sort by first tuple item, which is name :) ! for prop_name, prop_tag, prop_val in all_props: if get_large_props and \ PROP_TYPE(prop_tag)==PT_ERROR and \ *************** *** 70,73 **** --- 72,77 ---- attach = item.OpenAttach(attach_num, None, mapi.MAPI_DEFERRED_ERRORS) DumpItemProps(attach, shorten, get_large) + print + print def usage(driver): From mhammond at users.sourceforge.net Mon Jul 28 18:38:49 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Mon Jul 28 20:38:52 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 addin.py,1.81,1.82 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv7048 Modified Files: addin.py Log Message: Few tweaks to the logging code (Outlook UI events are reported at level 3, and more useful logging of the timers.) The timer now relies also on "HaveSeenMessage()" along with the msgstore generator. The msgstore generator assumes that we have saved spam scores, which meant that if we didn't save scores, we would continually re-try the same old unread messages each time a new one arrived. Now, if these msgs have been trained on, they are skipped, meaning we get to the new messages quicker. Index: addin.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/addin.py,v retrieving revision 1.81 retrieving revision 1.82 diff -C2 -d -r1.81 -r1.82 *** addin.py 28 Jul 2003 13:02:03 -0000 1.81 --- addin.py 29 Jul 2003 00:38:47 -0000 1.82 *************** *** 184,190 **** # outlook one def ProcessMessage(msgstore_message, manager): ! manager.LogDebug(2, "ProcessMessage starting for", msgstore_message) if not msgstore_message.IsFilterCandidate(): ! manager.LogDebug(1, "Skipping message '%s' - we don't filter ones like that!") return --- 184,192 ---- # outlook one def ProcessMessage(msgstore_message, manager): ! manager.LogDebug(2, "ProcessMessage starting for message '%s'" \ ! % msgstore_message.subject) if not msgstore_message.IsFilterCandidate(): ! manager.LogDebug(1, "Skipping message '%s' - we don't filter ones like that!" \ ! % msgstore_message.subject) return *************** *** 261,265 **** # the timer for known 'inbox' folders, or for all watched folders. is_inbox = self.target.IsReceiveFolder() ! if not is_inbox and not self.manager.config.experimental.timer_only_receive_folders: use_timer = False --- 263,267 ---- # the timer for known 'inbox' folders, or for all watched folders. is_inbox = self.target.IsReceiveFolder() ! if not is_inbox and self.manager.config.experimental.timer_only_receive_folders: use_timer = False *************** *** 308,313 **** assert thread.get_ident() == self.owner_thread_ident if self.timer_id is not None: - self.manager.LogDebug(2, "The timer with id=%d was stopped" % self.timer_id) timer.kill_timer(self.timer_id) self.timer_id = None --- 310,315 ---- assert thread.get_ident() == self.owner_thread_ident if self.timer_id is not None: timer.kill_timer(self.timer_id) + self.manager.LogDebug(2, "The timer with id=%d was stopped" % self.timer_id) self.timer_id = None *************** *** 315,318 **** --- 317,321 ---- # Kill the timer first assert thread.get_ident() == self.owner_thread_ident + self.manager.LogDebug(1, "The timer with id=%s fired" % self.timer_id) self._KillTimer() assert self.timer_generator, "Can't have a timer with no generator" *************** *** 324,328 **** # event triggers a new timer. try: ! item = self.timer_generator.next() except StopIteration: # No items left in our generator --- 327,340 ---- # event triggers a new timer. try: ! # Zoom over items I have already seen. This is so when the spam ! # score it not saved, we do not continually look at the same old ! # unread messages (assuming they have been trained) before getting ! # to the new ones. ! # If the Spam score *is* saved, the generator should only return ! # ones that HaveSeen() returns False for, so therefore isn't a hit. ! while 1: ! item = self.timer_generator.next() ! if not HaveSeenMessage(item, self.manager): ! break except StopIteration: # No items left in our generator *************** *** 342,346 **** locale.setlocale(locale.LC_NUMERIC, "C") # see locale comments above self.manager.LogDebug(2, "OnItemAdd event for folder", self, ! "with item", item) # Due to the way our "missed message" indicator works, we do # a quick check here for "UnRead". If UnRead, we assume it is very --- 354,358 ---- locale.setlocale(locale.LC_NUMERIC, "C") # see locale comments above self.manager.LogDebug(2, "OnItemAdd event for folder", self, ! "with item", item.Subject.encode("mbcs", "ignore")) # Due to the way our "missed message" indicator works, we do # a quick check here for "UnRead". If UnRead, we assume it is very *************** *** 362,366 **** # then it should be trained as such. self.manager.LogDebug(2, "OnItemAdd event for SPAM folder", self, ! "with item", item) if not self.manager.config.training.train_manual_spam: return --- 374,378 ---- # then it should be trained as such. self.manager.LogDebug(2, "OnItemAdd event for SPAM folder", self, ! "with item", item.Subject.encode("mbcs", "ignore")) if not self.manager.config.training.train_manual_spam: return *************** *** 873,877 **** # The Outlook event handlers def OnActivate(self): ! self.manager.LogDebug(2, "OnActivate", self) # See comments for OnNewExplorer below. # *sigh* - OnActivate seems too early too for Outlook 2000, --- 885,889 ---- # The Outlook event handlers def OnActivate(self): ! self.manager.LogDebug(3, "OnActivate", self) # See comments for OnNewExplorer below. # *sigh* - OnActivate seems too early too for Outlook 2000, *************** *** 883,887 **** def OnSelectionChange(self): ! self.manager.LogDebug(2, "OnSelectionChange", self) # See comments for OnNewExplorer below. if not self.have_setup_ui: --- 895,899 ---- def OnSelectionChange(self): ! self.manager.LogDebug(3, "OnSelectionChange", self) # See comments for OnNewExplorer below. if not self.have_setup_ui: *************** *** 891,895 **** def OnClose(self): ! self.manager.LogDebug(2, "OnClose", self) self.explorers_collection._DoDeadExplorer(self) self.explorers_collection = None --- 903,907 ---- def OnClose(self): ! self.manager.LogDebug(3, "OnClose", self) self.explorers_collection._DoDeadExplorer(self) self.explorers_collection = None *************** *** 898,905 **** def OnBeforeFolderSwitch(self, new_folder, cancel): ! self.manager.LogDebug(2, "OnBeforeFolderSwitch", self) def OnFolderSwitch(self): ! self.manager.LogDebug(2, "OnFolderSwitch", self) # Yet another worm-around for our event timing woes. This may # be the first event ever seen for this explorer if, eg, --- 910,917 ---- def OnBeforeFolderSwitch(self, new_folder, cancel): ! self.manager.LogDebug(3, "OnBeforeFolderSwitch", self) def OnFolderSwitch(self): ! self.manager.LogDebug(3, "OnFolderSwitch", self) # Yet another worm-around for our event timing woes. This may # be the first event ever seen for this explorer if, eg, *************** *** 941,948 **** def OnBeforeViewSwitch(self, new_view, cancel): ! self.manager.LogDebug(2, "OnBeforeViewSwitch", self) def OnViewSwitch(self): ! self.manager.LogDebug(2, "OnViewSwitch", self) if not self.have_setup_ui: self.SetupUI() --- 953,960 ---- def OnBeforeViewSwitch(self, new_view, cancel): ! self.manager.LogDebug(3, "OnBeforeViewSwitch", self) def OnViewSwitch(self): ! self.manager.LogDebug(3, "OnViewSwitch", self) if not self.have_setup_ui: self.SetupUI() From mhammond at users.sourceforge.net Mon Jul 28 18:47:38 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Mon Jul 28 20:47:41 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 addin.py,1.82,1.83 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv9208 Modified Files: addin.py Log Message: Tweak the message when the user has >= the latest version Index: addin.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/addin.py,v retrieving revision 1.82 retrieving revision 1.83 diff -C2 -d -r1.82 -r1.83 *** addin.py 29 Jul 2003 00:38:47 -0000 1.82 --- addin.py 29 Jul 2003 00:47:36 -0000 1.83 *************** *** 531,536 **** os.startfile(url) else: ! win32ui.MessageBox("You are already running the latest version", ! "SpamBayes") # A hook for whatever tests we have setup --- 531,537 ---- os.startfile(url) else: ! msg = "The latest available version is %s\r\n\r\n" \ ! "You already have the latest version." % latest_ver_string ! win32ui.MessageBox(msg, "SpamBayes") # A hook for whatever tests we have setup From mhammond at users.sourceforge.net Mon Jul 28 19:16:30 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Mon Jul 28 21:16:33 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000/docs configuration.html, 1.6, 1.7 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000/docs In directory sc8-pr-cvs1:/tmp/cvs-serv13272 Modified Files: configuration.html Log Message: Add info about the timer. Index: configuration.html =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/docs/configuration.html,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -d -r1.6 -r1.7 *** configuration.html 22 Jul 2003 06:03:42 -0000 1.6 --- configuration.html 29 Jul 2003 01:16:28 -0000 1.7 *************** *** 208,211 **** --- 208,303 ----
      +

      Experimental Configuration Options

      + There are a special class of configuration options, which the SpamBayes + developers have classified experimental.  By default, all + experimental features will be disabled.  If you enable any + experimental features, you do so at your own risk - these features are + experimental for a reason (but they will generally work OK assuming + they are listed here)
      +
      + All experimental options are in the special [Experimental] section of your + configuration file. Be aware that these experimental features may + change, or be removed + completely in later versions.  If the feature is kept for later + versions, the configuration options will + be moved out of the + [Experimental] section into a + more appropriate one, so you will need + to change these options later. + The following options are supported in this version
      + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Option Name
      +
      Valid Values
      +
      Default
      +
      Comments
      +
      timer_start_delayNumber0Enables the use of a timer to + process messages rather than processing as they arrive.  This has + been designed to avoid problems where the plugin conflicts with + Outlook's builtin rules, causing a number of symptoms; either Outlook + rules not firing, or strange 'unread' states on the messages.  If + this value is zero, the timer is disabled, otherwise it specifies the + delay (in milliseconds) + between a new item being received in the Inbox, and SpamBayes starting + to process the items.  If another new message arrives during this + period, the timer will be reset, and the delay will start again.  + This prevents SpamBayes from becoming overwhelmed when Outlook itself + is being overwhelmed with new messages - SpamBayes will patiently wait + until the flood has stopped, and begin sorting out the Spam.
      + A reasonable starting point for this option would be 2000 (ie, every 2 + seconds), but the optimal value will vary depending on the speed of + your machine, network connection and mail server.
      +
      timer_interval
      +
      integer
      +
      1000
      +
      Once the new message timer has + actually started, how long (in milliseconds) + should it wait before checking each new message.  If a new message + arrives during this process, the entire timer process is restarted, + meaning that timer_start_delay + (above) will elapse before the process begins again.
      +
      timer_only_receive_folders
      +
      True, False
      +
      True
      +
      If you have specified that a + timer be used, this option controls if the timer is used only for + special 'Inbox' type folders (True), or for all watched folders (False).
      + The point of using a timer is to prevent the SpamBayes filter getting + in the way the builtin Outlook rules.  Therefore, is it generally + only necessary to use a timer for folders that have new items being + delivered directly to them by the server - typically, your + 'Inbox'.  Folders that are not inbox style folders generally are + not subject to builtin filtering, so generally have no problems + filtering messages in 'real time'.
      +
      +
      +

      Multiple Configuration Files

      There is rudimentary support for multiple configuration files.  From mhammond at users.sourceforge.net Mon Jul 28 19:18:21 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Mon Jul 28 21:18:24 2003 Subject: [Spambayes-checkins] spambayes/spambayes Version.py,1.9,1.10 Message-ID: Update of /cvsroot/spambayes/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv13526 Modified Files: Version.py Log Message: New Outlook binary coming. Index: Version.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/spambayes/Version.py,v retrieving revision 1.9 retrieving revision 1.10 diff -C2 -d -r1.9 -r1.10 *** Version.py 28 Jul 2003 12:40:44 -0000 1.9 --- Version.py 29 Jul 2003 01:18:19 -0000 1.10 *************** *** 31,38 **** }, "Outlook" : { ! "Version": 0.4, ! "BinaryVersion": 0.5, "Description": "SpamBayes Outlook Addin (beta)", ! "Date": "July 2003", "Full Description": "%(Description)s, version %(Version)s (%(Date)s)", "Full Description Binary": --- 31,38 ---- }, "Outlook" : { ! "Version": 0.6, ! "BinaryVersion": 0.6, "Description": "SpamBayes Outlook Addin (beta)", ! "Date": "July 29, 2003", "Full Description": "%(Description)s, version %(Version)s (%(Date)s)", "Full Description Binary": From mhammond at users.sourceforge.net Mon Jul 28 19:19:00 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Mon Jul 28 21:19:02 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000/installer crank.py, NONE, 1.1 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000/installer In directory sc8-pr-cvs1:/tmp/cvs-serv13713 Added Files: crank.py Log Message: Crank it baby, crank it --- NEW FILE: crank.py --- # turn the crank import os, sys, shutil from compileall import compile_dir def main(): installer_dir=os.environ.get("installer") if installer_dir is None: print "Please set INSTALLER to point to the McMillan installer path" return 1 this_dir = os.path.dirname(__file__) if os.path.exists(os.path.join(this_dir, "buildspambayes_addin")): shutil.rmtree(os.path.join(this_dir, "buildspambayes_addin")) if os.path.exists(os.path.join(this_dir, "dist")): shutil.rmtree(os.path.join(this_dir, "dist")) rc = os.system("%s %s/Build.py %s/spambayes_addin.spec" % (sys.executable, installer_dir, this_dir)) if rc: print "Installer build FAILED" return 1 genpy = os.path.join(this_dir, "dist", "support", "gen_py") # compile_all the gen_path if not compile_dir(genpy, ddir="win32com/gen_py", quiet=1): print "FAILED to build the gencache directory" return 1 # remove the .py files def _remover(arg, dirname, filenames): for name in filenames: if os.path.splitext(name)[1]=='.py': os.remove(os.path.join(dirname, name)) os.path.walk(genpy, _remover, None) if not os.path.isfile(os.path.join(genpy, "dicts.dat")): print "EEEK - no gencache .dat file!" return 1 # crank out the installer. import win32api iss_file = os.path.join(this_dir, "spambayes_addin.iss") handle, compiler = win32api.FindExecutable(iss_file) rc = os.system('"%s" /cc %s' % (compiler, iss_file)) if rc: print "FAILED to build the final executable" return 1 return 0 if __name__=='__main__': main() From mhammond at users.sourceforge.net Mon Jul 28 19:24:36 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Mon Jul 28 21:24:39 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 config.py,1.17,1.18 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv14855 Modified Files: config.py Log Message: Typo in the doc string. Index: config.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/config.py,v retrieving revision 1.17 retrieving revision 1.18 diff -C2 -d -r1.17 -r1.18 *** config.py 27 Jul 2003 23:49:32 -0000 1.17 --- config.py 29 Jul 2003 01:24:34 -0000 1.18 *************** *** 117,121 **** INTEGER, RESTORE), ("timer_interval", "The interval between subsequent timer checks (in ms)", 1000, ! """Once the a new message timer found a new message, how long should SpamBayes wait before checking for another new message, assuming no other new messages arrive. Should a new message arrive during this --- 117,121 ---- INTEGER, RESTORE), ("timer_interval", "The interval between subsequent timer checks (in ms)", 1000, ! """Once the new message timer finds a new message, how long should SpamBayes wait before checking for another new message, assuming no other new messages arrive. Should a new message arrive during this From anthonybaxter at users.sourceforge.net Mon Jul 28 19:48:05 2003 From: anthonybaxter at users.sourceforge.net (Anthony Baxter) Date: Mon Jul 28 21:48:08 2003 Subject: [Spambayes-checkins] website unix.ht,1.2,1.3 Message-ID: Update of /cvsroot/spambayes/website In directory sc8-pr-cvs1:/tmp/cvs-serv18873 Modified Files: unix.ht Log Message: exmh training menu Index: unix.ht =================================================================== RCS file: /cvsroot/spambayes/website/unix.ht,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** unix.ht 22 May 2003 02:42:47 -0000 1.2 --- unix.ht 29 Jul 2003 01:48:02 -0000 1.3 *************** *** 47,49 ****
    1. If you're a Unix weenie using a Mac OS X system, this page is probably more appropriate than the Mac page. !
    \ No newline at end of file --- 47,97 ----
  • If you're a Unix weenie using a Mac OS X system, this page is probably more appropriate than the Mac page. ! ! !

    exmh

    ! !

    The following short guide will help you set up a new message menu on ! exmh - this adds a menu containing "Train as Spam" and "Train as Ham" ! options.

    ! !
      !
    1. First of all, create the directory ~/.tk/exmh if you ! haven't already done so. Put the following file (I call mine spambayes.tcl) ! in there:
    2. !
      ! proc SB_SpamTrain { } {
      !     global exmh msg mhProfile 
      !     Ftoc_Iterate line {
      !         set msgid [ Ftoc_MsgNumber $line ]
      !         eval {MhExec hammie.py -d -s $mhProfile(path)/$exmh(folder)/$msgid } 
      !     }
      ! }
      ! 
      ! proc SB_HamTrain { } {
      !     global exmh msg mhProfile 
      !     Ftoc_Iterate line {
      !         set msgid [ Ftoc_MsgNumber $line ]
      !         eval {MhExec hammie.py -d -g $mhProfile(path)/$exmh(folder)/$msgid } 
      !     }
      ! }
      ! 
      ! !
    3. Then run 'wish' or 'tclsh', and enter the following command:
    4. !
      ! auto_mkindex ~/.tk/exmh *.tcl
      ! 
      ! !
    5. Next, we hook up the commands that we just created. Shut down your exmh ! and edit ~/.exmh/exmh-defaults. Add the following entries:
    6. !
      ! *Mops.umenulist: spam
      ! *Mops.spam.text: S-B
      ! *Mops.spam.m.entrylist: trainspam trainham 
      ! *Mops.spam.m.l_trainspam: Train as Spam
      ! *Mops.spam.m.c_trainspam: SB_SpamTrain
      ! *Mops.spam.m.l_trainham: Train as Ham
      ! *Mops.spam.m.c_trainham: SB_HamTrain
      ! 
      ! !
    7. Restart exmh, and you're done.
    8. !
    From mhammond at users.sourceforge.net Mon Jul 28 19:54:36 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Mon Jul 28 21:54:40 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 about.html,1.15,1.16 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv20094 Modified Files: about.html Log Message: Add a couple of clarifications based on user feedback, and some typos. Index: about.html =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/about.html,v retrieving revision 1.15 retrieving revision 1.16 diff -C2 -d -r1.15 -r1.16 *** about.html 8 Jul 2003 10:54:28 -0000 1.15 --- about.html 29 Jul 2003 01:54:34 -0000 1.16 *************** *** 133,137 **** of good messages we train on.  Don't worry too much about missing one or two spam - the system is likely to find them for you as we ! rescore your existing email.
  • Configure and Train SpamBayes
    Now we have our folders setup with some initial training data, we can --- 133,144 ---- of good messages we train on.  Don't worry too much about missing one or two spam - the system is likely to find them for you as we ! rescore your existing email.
    ! If your Inbox is so full of Spam you don't know where to start, you may ! like to create a temporary folder for the purposes of training your ! good messages.  Copy some examples of your good messages to this ! new folder (roughly the same number as Spam you are training on is ! best) and nominate this temporary folder instead of your Inbox.  ! Once trained, you can dispose of this folder.
    !
  • Configure and Train SpamBayes
    Now we have our folders setup with some initial training data, we can *************** *** 141,146 **** the right.
  • Select Train Now, and the training dialog, also shown to ! the right will appear.  The Inbox will be the default for good ! messages, so you need to select your new Spam folder as the source of junk messages.  Ensure that Score messages after training is selected, so we can see how effective --- 148,153 ---- the right.
  • Select Train Now, and the training dialog, also shown to ! the right will appear.  You will need to select your Inbox as the ! folder for good messages, and your new Spam folder as the source of junk messages.  Ensure that Score messages after training is selected, so we can see how effective *************** *** 148,153 ****
  • Click on the Train Now button, and a progress indicator ! will be displayed as your messages are trained, and another progress ! indicator as they are scored.  Close the training window to return to the SpamBayes window.
  • --- 155,160 ----
  • Click on the Train Now button, and a progress indicator ! will be displayed as your messages are trained and scored.  When ! finished, close the training window to return to the SpamBayes window.
  • *************** *** 248,252 **** own filtering rules.

    Configuring the plugin for filtering

    ! Once the system is trained an configured, you are ready to enable the filtering capabilities.  From the SpamBayes manager, select Filters.  From this dialog you --- 255,259 ---- own filtering rules.

    Configuring the plugin for filtering

    ! Once the system is trained and configured, you are ready to enable the filtering capabilities.  From the SpamBayes manager, select Filters.  From this dialog you From montanaro at users.sourceforge.net Mon Jul 28 20:05:36 2003 From: montanaro at users.sourceforge.net (Skip Montanaro) Date: Mon Jul 28 22:05:38 2003 Subject: [Spambayes-checkins] spambayes/spambayes Version.py,1.10,1.11 Message-ID: Update of /cvsroot/spambayes/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv22328 Modified Files: Version.py Log Message: isolate __main__ stuff into a main() function Index: Version.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/spambayes/Version.py,v retrieving revision 1.10 retrieving revision 1.11 diff -C2 -d -r1.10 -r1.11 *** Version.py 29 Jul 2003 01:18:19 -0000 1.10 --- Version.py 29 Jul 2003 02:05:34 -0000 1.11 *************** *** 155,161 **** _make_cfg_section(stream, appname, versions["Apps"][appname]) ! if __name__=='__main__': ! import sys ! if '-g' in sys.argv: make_cfg(sys.stdout) sys.exit(0) --- 155,160 ---- _make_cfg_section(stream, appname, versions["Apps"][appname]) ! def main(args): ! if '-g' in args: make_cfg(sys.stdout) sys.exit(0) *************** *** 184,185 **** --- 183,188 ---- for app in latest_dict["Apps"]: print "%s: %s" % (app, get_version_string(app, version_dict=latest_dict)) + + if __name__=='__main__': + import sys + main(sys.argv) From montanaro at users.sourceforge.net Mon Jul 28 20:07:16 2003 From: montanaro at users.sourceforge.net (Skip Montanaro) Date: Mon Jul 28 22:07:18 2003 Subject: [Spambayes-checkins] website Makefile,1.7,1.8 Message-ID: Update of /cvsroot/spambayes/website In directory sc8-pr-cvs1:/tmp/cvs-serv22571 Modified Files: Makefile Log Message: add magic to allow spambayes and website modules to unrelated directory-wise Index: Makefile =================================================================== RCS file: /cvsroot/spambayes/website/Makefile,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -d -r1.7 -r1.8 *** Makefile 28 Jul 2003 14:18:38 -0000 1.7 --- Makefile 29 Jul 2003 02:07:14 -0000 1.8 *************** *** 6,9 **** --- 6,15 ---- ROOT_OFFSET = . + VERSION_PY = $(shell python -c 'import os;\ + from spambayes import Version;\ + f = Version.__file__;\ + print os.path.splitext(f)[0]+".py";\ + ') + $(TARGETS): links.h *************** *** 21,26 **** ./scripts/ht2html/ht2html.py -f -s SpamBayesFAQGenerator -r . ./faq.ht ! download/Version.cfg: ../spambayes/Version.py ! python ../spambayes/Version.py -g > download/Version.cfg local_install: --- 27,32 ---- ./scripts/ht2html/ht2html.py -f -s SpamBayesFAQGenerator -r . ./faq.ht ! download/Version.cfg: $(VERSION_PY) ! python $(VERSION_PY) -g > download/Version.cfg local_install: From mhammond at users.sourceforge.net Mon Jul 28 20:08:41 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Mon Jul 28 22:08:44 2003 Subject: [Spambayes-checkins] website/download Version.cfg,1.1,1.2 Message-ID: Update of /cvsroot/spambayes/website/download In directory sc8-pr-cvs1:/tmp/cvs-serv22794/download Modified Files: Version.cfg Log Message: Version 6 of the Outlook binary. Index: Version.cfg =================================================================== RCS file: /cvsroot/spambayes/website/download/Version.cfg,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** Version.cfg 28 Jul 2003 14:17:17 -0000 1.1 --- Version.cfg 29 Jul 2003 02:08:39 -0000 1.2 *************** *** 28,37 **** [Outlook] ! BinaryVersion:0.5 Download Page:http://starship.python.net/crew/mhammond/spambayes Description:SpamBayes Outlook Addin (beta) Full Description:%(Description)s, version %(Version)s (%(Date)s) ! Version:0.4 ! Date:July 2003 Full Description Binary:%(Description)s, Binary version %(BinaryVersion)s (%(Date)s) --- 28,37 ---- [Outlook] ! BinaryVersion:0.6 Download Page:http://starship.python.net/crew/mhammond/spambayes Description:SpamBayes Outlook Addin (beta) Full Description:%(Description)s, version %(Version)s (%(Date)s) ! Version:0.6 ! Date:July 29, 2003 Full Description Binary:%(Description)s, Binary version %(BinaryVersion)s (%(Date)s) From mhammond at users.sourceforge.net Mon Jul 28 20:08:41 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Mon Jul 28 22:08:48 2003 Subject: [Spambayes-checkins] website applications.ht, 1.15, 1.16 download.ht, 1.12, 1.13 windows.ht, 1.22, 1.23 Message-ID: Update of /cvsroot/spambayes/website In directory sc8-pr-cvs1:/tmp/cvs-serv22794 Modified Files: applications.ht download.ht windows.ht Log Message: Version 6 of the Outlook binary. Index: applications.ht =================================================================== RCS file: /cvsroot/spambayes/website/applications.ht,v retrieving revision 1.15 retrieving revision 1.16 diff -C2 -d -r1.15 -r1.16 *** applications.ht 22 Jul 2003 06:36:02 -0000 1.15 --- applications.ht 29 Jul 2003 02:08:39 -0000 1.16 *************** *** 27,33 ****

    Availability

    !

    Mark has packaged together an installer for the plugin. You can download it from his website. ! This is currently at version 005.

    Download the alpha4 release.

    Alternatively, you can use CVS to get the code - go to the CVS page on the project's sourceforge site for more.

    --- 27,33 ----

    Availability

    !

    Mark has packaged together an installer for the plugin. You can download it from his website. ! This is currently at version 006.

    Download the alpha4 release.

    Alternatively, you can use CVS to get the code - go to the CVS page on the project's sourceforge site for more.

    Index: download.ht =================================================================== RCS file: /cvsroot/spambayes/website/download.ht,v retrieving revision 1.12 retrieving revision 1.13 diff -C2 -d -r1.12 -r1.13 *** download.ht 22 Jul 2003 06:36:02 -0000 1.12 --- download.ht 29 Jul 2003 02:08:39 -0000 1.13 *************** *** 23,29 ****

    Binary Releases

    Outlook Plugin

    !

    Mark has packaged together an installer for the plugin. You can download it from his website. ! This is currently at version 005.

    Other

    --- 23,29 ----

    Binary Releases

    Outlook Plugin

    !

    Mark has packaged together an installer for the plugin. You can download it from his website. ! This is currently at version 006.

    Other

    Index: windows.ht =================================================================== RCS file: /cvsroot/spambayes/website/windows.ht,v retrieving revision 1.22 retrieving revision 1.23 diff -C2 -d -r1.22 -r1.23 *** windows.ht 23 Jul 2003 15:35:30 -0000 1.22 --- windows.ht 29 Jul 2003 02:08:39 -0000 1.23 *************** *** 9,16 ****

    If you are using Outlook 2000 or Outlook XP (not Outlook Express) you should be able to simply download and run the Outlook plug-in installer. A separate Python installation is not necessary.

    !

    Note that all users who installed version 002 of the plugin are recommended to upgrade to the 005 release.

    The Outlook add-in was developed mostly using Outlook 2000 on Windows --- 9,16 ----

    If you are using Outlook 2000 or Outlook XP (not Outlook Express) you should be able to simply download and run the Outlook plug-in installer. A separate Python installation is not necessary.

    !

    Note that all users who installed version 002 of the plugin are recommended to upgrade to the 006 release.

    The Outlook add-in was developed mostly using Outlook 2000 on Windows From montanaro at users.sourceforge.net Mon Jul 28 20:18:00 2003 From: montanaro at users.sourceforge.net (Skip Montanaro) Date: Mon Jul 28 22:18:03 2003 Subject: [Spambayes-checkins] website reply.txt,1.5,1.6 Message-ID: Update of /cvsroot/spambayes/website In directory sc8-pr-cvs1:/tmp/cvs-serv24492 Modified Files: reply.txt Log Message: add a reference to 006 Index: reply.txt =================================================================== RCS file: /cvsroot/spambayes/website/reply.txt,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** reply.txt 6 Jul 2003 02:36:34 -0000 1.5 --- reply.txt 29 Jul 2003 02:17:58 -0000 1.6 *************** *** 30,36 **** There were problems installing the Outlook plug-in on some combinations of ! Windows and Outlook for early versions of the plug-in. Version 003 seems ! to install properly with all combinations of Windows and Outlook which have ! been tried so far. More information about Spambayes and Windows can be found at --- 30,37 ---- There were problems installing the Outlook plug-in on some combinations of ! Windows and Outlook for early versions of the plug-in. Version 003 seems to ! install properly with all combinations of Windows and Outlook which have ! been tried so far. As of 2003-07-28, the most recent version is 006. If ! you are trying to install or run an earlier version, you should upgrade. More information about Spambayes and Windows can be found at From mhammond at users.sourceforge.net Mon Jul 28 20:59:27 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Mon Jul 28 22:59:30 2003 Subject: [Spambayes-checkins] spambayes/spambayes Version.py,1.11,1.12 Message-ID: Update of /cvsroot/spambayes/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv30657 Modified Files: Version.py Log Message: Indicate the generated output is generated :) Mainly work for Python 2.2, but don't trust its config parser for remote data. Index: Version.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/spambayes/Version.py,v retrieving revision 1.11 retrieving revision 1.12 diff -C2 -d -r1.11 -r1.12 *** Version.py 29 Jul 2003 02:05:34 -0000 1.11 --- Version.py 29 Jul 2003 02:59:25 -0000 1.12 *************** *** 105,115 **** # Assumes that a 'config' version of this file exists at the given URL # No exceptions are caught ! import ConfigParser ! class MySafeConfigParser(ConfigParser.SafeConfigParser): ! def optionxform(self, optionstr): ! return optionstr # no lower! def fetch_latest_dict(url=LATEST_VERSION_HOME): ! import ConfigParser, urllib2 stream = urllib2.urlopen(url) cfg = MySafeConfigParser() --- 105,122 ---- # Assumes that a 'config' version of this file exists at the given URL # No exceptions are caught ! try: ! import ConfigParser ! class MySafeConfigParser(ConfigParser.SafeConfigParser): ! def optionxform(self, optionstr): ! return optionstr # no lower! ! except AttributeError: # No SafeConfigParser! ! MySafeConfigParser = None def fetch_latest_dict(url=LATEST_VERSION_HOME): ! if MySafeConfigParser is None: ! raise RuntimeError, \ ! "Sorry, but only Python 2.3 can trust remote config files" ! ! import urllib2 stream = urllib2.urlopen(url) cfg = MySafeConfigParser() *************** *** 151,154 **** --- 158,163 ---- def make_cfg(stream): + stream.write("# This file is generated from spambayes/Version.py" \ + " - do not edit\n") _make_cfg_section(stream, "SpamBayes", versions) for appname in versions["Apps"]: From richiehindle at users.sourceforge.net Mon Jul 28 23:46:49 2003 From: richiehindle at users.sourceforge.net (Richie Hindle) Date: Tue Jul 29 01:46:52 2003 Subject: [Spambayes-checkins] spambayes CHANGELOG.txt,1.7,1.8 Message-ID: Update of /cvsroot/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv21339 Modified Files: CHANGELOG.txt Log Message: Updated with all my post-1.0a4 edits (better late than never). Index: CHANGELOG.txt =================================================================== RCS file: /cvsroot/spambayes/spambayes/CHANGELOG.txt,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -d -r1.7 -r1.8 *** CHANGELOG.txt 7 Jul 2003 00:09:27 -0000 1.7 --- CHANGELOG.txt 29 Jul 2003 05:46:47 -0000 1.8 *************** *** 1,2 **** --- 1,12 ---- + (Next Release) + ============== + Richie Hindle 28/07/2003 Made the pop3proxy work with fetchmail. + Richie Hindle 22/07/2003 You can once again specify local addresses as well as ports for the pop3proxy to listen on (was broken in 1.0a3 and 1.0a4). + Richie Hindle 19/07/2003 pop3proxy: Print a traceback as well as adding an X-Spambayes-Exception header when there's an exception raised while processing a message. + Richie Hindle 18/07/2003 pop3proxy: "ASCII decoding error" problem fixed. + Richie Hindle 07/07/2003 Added no_cache_bulk_ham option: suppresses caching of 'Precedence: bulk' ham, to stop mailing list traffic swamping the web UI's training page. + Richie Hindle 07/07/2003 Prevent the "Show clues" links on the web UI's training page from word-wrapping and making all the table rows two lines high. + + Alpha Release 4 =============== From anadelonbrin at users.sourceforge.net Tue Jul 29 00:32:50 2003 From: anadelonbrin at users.sourceforge.net (Tony Meyer) Date: Tue Jul 29 02:32:53 2003 Subject: [Spambayes-checkins] spambayes/spambayes Options.py, 1.59, 1.60 Version.py, 1.12, 1.13 Message-ID: Update of /cvsroot/spambayes/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv28220/spambayes Modified Files: Options.py Version.py Log Message: Add options to store information about a HTTP proxy. This can be used by the version checker, plus anything else that wants to do HTTP (like the urlslurper stuff that was tested a while back). Note that storing passwords is awkward because we store them in clear text and this might bother the users ;). If it does and we care about them, then we need to provide password prompts at the time of use. Also upgrade the version checker so that it uses this information so those stuck behind proxies (like me!) can check for the latest version. Index: Options.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/spambayes/Options.py,v retrieving revision 1.59 retrieving revision 1.60 diff -C2 -d -r1.59 -r1.60 *** Options.py 24 Jul 2003 21:31:24 -0000 1.59 --- Options.py 29 Jul 2003 06:32:48 -0000 1.60 *************** *** 921,924 **** --- 921,940 ---- platform.""", ("best", "db3hash", "dbhash", "gdbm", "dumbdbm"), RESTORE), + + ("proxy_username", "HTTP Proxy Username", "", + """The username to give to the HTTP proxy when required. If a + username is not necessary, simply leave blank.""", + r"[\w]+", DO_NOT_RESTORE), + ("proxy_password", "HTTP Proxy Password", "", + """The password to give to the HTTP proxy when required. This is + stored in clear text in your configuration file, so if that bothers + you then don't do this. You'll need to use a proxy that doesn't need + authentication, or do without any SpamBayes HTTP activity.""", + r"[\w]+", DO_NOT_RESTORE), + ("proxy_server", "HTTP Proxy Server", "", + """If a spambayes application needs to use HTTP, it will try to do so + through this proxy server. The port defaults to 8080, or can be + entered with the server:port form.""", + SERVER, DO_NOT_RESTORE), ), } Index: Version.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/spambayes/Version.py,v retrieving revision 1.12 retrieving revision 1.13 diff -C2 -d -r1.12 -r1.13 *** Version.py 29 Jul 2003 02:59:25 -0000 1.12 --- Version.py 29 Jul 2003 06:32:48 -0000 1.13 *************** *** 119,122 **** --- 119,137 ---- import urllib2 + from spambayes.Options import options + server = options["globals", "proxy_server"] + if server != "": + if ':' in server: + server, port = server.split(':', 1) + else: + port = 8080 + username = options["globals", "proxy_username"] + password = options["globals", "proxy_password"] + proxy_support = urllib2.ProxyHandler({"http" : + "http://%s:%s@%s:%d" % \ + (username, password, server, + port)}) + opener = urllib2.build_opener(proxy_support, urllib2.HTTPHandler) + urllib2.install_opener(opener) stream = urllib2.urlopen(url) cfg = MySafeConfigParser() From anadelonbrin at users.sourceforge.net Tue Jul 29 01:39:13 2003 From: anadelonbrin at users.sourceforge.net (Tony Meyer) Date: Tue Jul 29 03:39:18 2003 Subject: [Spambayes-checkins] website/download .cvsignore,NONE,1.1 Message-ID: Update of /cvsroot/spambayes/website/download In directory sc8-pr-cvs1:/tmp/cvs-serv8260/download Added Files: .cvsignore Log Message: Ignore our automatically generated version file. --- NEW FILE: .cvsignore --- *.html Version.cfg From anadelonbrin at users.sourceforge.net Tue Jul 29 01:45:11 2003 From: anadelonbrin at users.sourceforge.net (Tony Meyer) Date: Tue Jul 29 03:45:16 2003 Subject: [Spambayes-checkins] website/download Version.cfg,1.2,NONE Message-ID: Update of /cvsroot/spambayes/website/download In directory sc8-pr-cvs1:/tmp/cvs-serv9049/download Removed Files: Version.cfg Log Message: This file is automatically generated, like the .html files and faq.ht, so we shouldn't have it here. --- Version.cfg DELETED --- From anadelonbrin at users.sourceforge.net Tue Jul 29 01:46:06 2003 From: anadelonbrin at users.sourceforge.net (Tony Meyer) Date: Tue Jul 29 03:46:09 2003 Subject: [Spambayes-checkins] website faq.txt,1.19,1.20 Message-ID: Update of /cvsroot/spambayes/website In directory sc8-pr-cvs1:/tmp/cvs-serv9153 Modified Files: faq.txt Log Message: Add info about dumbdbm pointing out that it is never the right choice and that support for it will be dropped at some point. Index: faq.txt =================================================================== RCS file: /cvsroot/spambayes/website/faq.txt,v retrieving revision 1.19 retrieving revision 1.20 diff -C2 -d -r1.19 -r1.20 *** faq.txt 28 Jul 2003 20:19:52 -0000 1.19 --- faq.txt 29 Jul 2003 07:46:04 -0000 1.20 *************** *** 771,774 **** --- 771,790 ---- on 28th July 2003. To work around it, use fetchmail's ``fetchall`` option. + My database keeps getting corrupted and I get trackbacks with "dumbdbm" in them. + -------------------------------------------------------------------------------- + + 'dumbdbm' is the default database system - the one that gets fallen back on + when nothing else is available. It is not usually a good choice, and in + SpamBayes' case, always the wrong one. Some versions of dumbdbm have a bug + that will cause database corruption, but you shouldn't be using it anyway, + as it is very inefficient. Instead, either use a pickle or install `pybsddb`_ + (bsddb3) and use that instead. Support for dumbdbm will be dropped in a + future release. + + Note that none of this applies to the Outlook plug-in, which avoids it + on your behalf. + + .. _pybsddb: http://pybsddb.sourceforge.net/ + Development From anadelonbrin at users.sourceforge.net Tue Jul 29 02:12:12 2003 From: anadelonbrin at users.sourceforge.net (Tony Meyer) Date: Tue Jul 29 04:12:16 2003 Subject: [Spambayes-checkins] spambayes POP3PROXY.txt,1.3,1.4 Message-ID: Update of /cvsroot/spambayes/spambayes In directory sc8-pr-cvs1:/tmp/cvs-serv13289 Modified Files: POP3PROXY.txt Log Message: Add information about using different ports in Eudora on Windows from a post on the list from Ed Rubinsky. Index: POP3PROXY.txt =================================================================== RCS file: /cvsroot/spambayes/spambayes/POP3PROXY.txt,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** POP3PROXY.txt 5 Jun 2003 22:57:40 -0000 1.3 --- POP3PROXY.txt 29 Jul 2003 08:12:10 -0000 1.4 *************** *** 2,5 **** --- 2,55 ---- ================================================== + Setting Eudora to use different ports under Windows + --------------------------------------------------- + Eudora can be configured to support multiple pop and smtp servers + on different localhost ports - at least on Windows. You just can't do it + from the Tools->Options menu. Eudora reads an ini file, + eudora.ini, at startup. The format of this file is documented in the help + files. Open Help-Topics, click on index and search on eudora.ini. + + Under W2K (at least) eudora.ini is either in the eudora install directory + or in the user's settings directory depending on how you installed Eudora + (probably C:\Documents and Settings\userid\Application + Data\Qualcomm\Eudora\eudora.ini) + + This is how to configure Eudora 5.1 and Spambayes under Windows. Caution: + make two copies of eudora.ini - eudora.orig and eudora.new, for example. + Edit eudora.new. Close Eudora and copy the edited eudora.new to eudora.ini + and then re-start eudora. If you need to go back to your original settings + until you get it working with Spambayes, just close Eudora, copy + eudora.orig to eudora.ini and restart Eudora. + + Configure pop3proxy for each of Eudora's personality's pop servers, + specifying a separate port for each. I used 1110, 1120, 1130 and 1140 for + the four personalities I have in Eudora. Do the same for smtpproxy - again + I used 1115, 1125, 1135 and 1145. + + To configure Eudora: + Close Eudora. + In eudora.new (or whatever you called it) find the section + starting with [Settings]. This contains settings for the dominant personality. + Find the line beggining POPAccount. The last part of the account + name starting with '@' is the server. Change it to @localhost. + Find the lines beggining SMTPServer and POPServer. They will have + the server names defined for your dominant personality. + Change both server names to localhost + Add the following two lines. Use whatever ports you assigned to + pop3proxy and smtpproxy for the dominant personality. + POPPort=1110 + SMTPPort=1115 + + Setting for other personalities are kept in sections begging with + [Persona-personality_name]. For each personality make the same changes as + you made for the dominant personality, substituting the proper port numbers. + + Copy eudora.new to eudora.ini and re-start Eudora. In the password dialog + for each personality you should see localhost where you used to see the + actual server name. You should see the X-Spambayes headers which you can + filter on. In the web interface (localhost:8880) clicking in the Review + messages link should show all message processed by Spambayes. + + For MacOS 9 ----------- From anadelonbrin at users.sourceforge.net Tue Jul 29 02:36:17 2003 From: anadelonbrin at users.sourceforge.net (Tony Meyer) Date: Tue Jul 29 04:36:21 2003 Subject: [Spambayes-checkins] website server_side.ht, NONE, 1.1 faq.txt, 1.20, 1.21 Message-ID: Update of /cvsroot/spambayes/website In directory sc8-pr-cvs1:/tmp/cvs-serv17429 Modified Files: faq.txt Added Files: server_side.ht Log Message: Add notes from people that have integrated spambayes into a server-side solution, and a link from the relevant FAQ question to this. (I suppose it could be linked from somewhere else, too, but I'm not sure where). --- NEW FILE: server_side.ht --- Title: SpamBayes: Server side solutions Author-Email: spambayes@python.org Author: spambayes

    SpamBayes server-side

    This page includes notes from users that have successfully managed to get SpamBayes working server-side.

    postfix notes from Jonathan St-Andre

    SpamBayes has been installed on one of our MX (running postfix) and is filtering all inbound emails for the whole company (~1000 employees, ~35000 incoming emails daily). The server is a dual PIII 933MHz with 512MB of memory and the load is pretty low (it's almost overkill).

    According to the feedback I received from our users, it seems that it tags approximately 90% (for some it goes up to 95%) of the spam correctly. The rest of the spam is tagged as unsure. No false positives. The filter hasn't received too much spam training either, yet. Efficiency has been improving slowly, as we keep training it.

    Here's a quick howto:

    1. Create the DB by training with a mailbox of ham and a mailbox of spam. I put the DB in /var/spambayes/hammie.db (as a DBM store).
    2. In master.cf, the smtp line has been changed for the following two lines:
      smtp      inet  n       -       n       -       -       smtpd
        -o content_filter=spambayes:
      
      and the following two lines were added at the end of the file:
      spambayes unix  -       n       n       -       -       pipe
        user=nobody argv=/usr/local/bin/hammiewrapper.sh $sender $recipient
      
    3. Here's what the hammiewrapper.sh file looks like:
      #!/bin/sh
      /usr/bin/hammiefilter.py -d /var/spambayes/hammie.db -f | /usr/sbin/sendmail -f $*
      
    Index: faq.txt =================================================================== RCS file: /cvsroot/spambayes/website/faq.txt,v retrieving revision 1.20 retrieving revision 1.21 diff -C2 -d -r1.20 -r1.21 *** faq.txt 29 Jul 2003 07:46:04 -0000 1.20 --- faq.txt 29 Jul 2003 08:36:15 -0000 1.21 *************** *** 819,824 **** you really have to have individual databases for each user. Either way, you should be able to modify spambayes easily enough to fit into your setup. ! Please let the list know if you do have success in this area, and we'll ! update this answer. --- 819,827 ---- you really have to have individual databases for each user. Either way, you should be able to modify spambayes easily enough to fit into your setup. ! Some people have in fact done this and have been kind enough to donate `notes ! about how they have gone about it`_. If you also do this but in some other ! way, please let us know so that we can add to the information. ! ! .. _notes about how they have gone about it: server_side.html From mhammond at users.sourceforge.net Tue Jul 29 05:08:50 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Tue Jul 29 07:08:53 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 msgstore.py,1.58,1.59 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv10964 Modified Files: msgstore.py Log Message: Fix [ 779049 ] email.Errors.HeaderParseError: Continuation line seen ... Move the code that butchers the "Content-Type" so that it is used in the face of more email exceptions. Index: msgstore.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/msgstore.py,v retrieving revision 1.58 retrieving revision 1.59 diff -C2 -d -r1.58 -r1.59 *** msgstore.py 29 Jul 2003 00:34:50 -0000 1.58 --- msgstore.py 29 Jul 2003 11:08:47 -0000 1.59 *************** *** 744,762 **** msg = email.message_from_string(text + "\n\n") except email.Errors.BoundaryError: ! # But even this doesn't get *everything*. We can still see: ! # "multipart message with no defined boundary" ! # so now it is time to turn into a butcher - hack out ! # the Content-Type header, so we see it as plain text. ! butcher_pos = text.lower().find("\ncontent-type: ") ! if butcher_pos < 0: ! # This error just just gunna get caught below anyway ! raise RuntimeError( ! "email package croaked with boundary error, but " ! "there appears to be no 'Content-Type' header") ! # Put it back together, skipping the original "\n" but ! # leaving the header leaving "\nSpamBayes-Content-Type: " ! butchered = text[:butcher_pos] + "\nSpamBayes-" + \ ! text[butcher_pos+1:] + "\n\n" ! msg = email.message_from_string(butchered) except: print "FAILED to create email.message from: ", `text` --- 744,768 ---- msg = email.message_from_string(text + "\n\n") except email.Errors.BoundaryError: ! msg = None ! except email.Errors.HeaderParseError: ! # This exception can come from parsing the header *or* the ! # body of a mime message. ! msg = None ! # But even this doesn't get *everything*. We can still see: ! # "multipart message with no defined boundary" or the ! # HeaderParseError above. Time to get brutal - hack out ! # the Content-Type header, so we see it as plain text. ! if msg is None: ! butcher_pos = text.lower().find("\ncontent-type: ") ! if butcher_pos < 0: ! # This error just just gunna get caught below anyway ! raise RuntimeError( ! "email package croaked with a MIME related error, but " ! "there appears to be no 'Content-Type' header") ! # Put it back together, skipping the original "\n" but ! # leaving the header leaving "\nSpamBayes-Content-Type: " ! butchered = text[:butcher_pos] + "\nSpamBayes-" + \ ! text[butcher_pos+1:] + "\n\n" ! msg = email.message_from_string(butchered) except: print "FAILED to create email.message from: ", `text` From montanaro at users.sourceforge.net Tue Jul 29 08:33:35 2003 From: montanaro at users.sourceforge.net (Skip Montanaro) Date: Tue Jul 29 10:33:40 2003 Subject: [Spambayes-checkins] website index.ht,1.16,1.17 Message-ID: Update of /cvsroot/spambayes/website In directory sc8-pr-cvs1:/tmp/cvs-serv16141 Modified Files: index.ht Log Message: add a little blurb about client-side vs server-side use and identify the main applications which are part of the SB distribution Index: index.ht =================================================================== RCS file: /cvsroot/spambayes/website/index.ht,v retrieving revision 1.16 retrieving revision 1.17 diff -C2 -d -r1.16 -r1.17 *** index.ht 7 Jul 2003 04:16:41 -0000 1.16 --- index.ht 29 Jul 2003 14:33:32 -0000 1.17 *************** *** 10,13 **** --- 10,14 ---- InfoWorld article, and Jon Udell's blog.

    +

    What is SpamBayes?

    *************** *** 15,19 **** project is working on developing a Bayesian anti-spam filter, initially based on the work of ! Paul Graham. The major difference between this and other, similar projects --- 16,20 ---- project is working on developing a Bayesian anti-spam filter, initially based on the work of ! Paul Graham. The major difference between this and other, similar projects *************** *** 26,29 **** --- 27,72 ---- This is documented on the background page.

    + +

    SpamBayes is not a single application. The core code is a message + classifier, however there are several applications available as part of the + SpamBayes project which use the classifier in specific contexts. For the + most part, the current crop of applications all operate on the client side + of things, however, a number of people have experimented with using + SpamBayes on mail servers to classify incoming mail for multiple users. The + table below outlines the main applications which are part of the SpamBayes + distribution.

    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ApplicationDescription
    Outlook PluginA plugin for Microsoft Outlook which tightly integrates classification + and training into the Outlook interface
    Pop3proxyA mail filter which sits between the user's POP3 server(s) and the + user's mail client and presents a web-based training interface
    ImapfilterA mail filter similar to pop3proxy but which talks the IMAP + protocol
    HammiefilterA simple mail filter suitable for embedding in a procmail + environment
    +

    That's great, but what's SpamBayes?

    From anadelonbrin at users.sourceforge.net Tue Jul 29 17:25:33 2003 From: anadelonbrin at users.sourceforge.net (Tony Meyer) Date: Tue Jul 29 19:25:37 2003 Subject: [Spambayes-checkins] spambayes/utilities which_database.py, NONE, 1.1 Message-ID: Update of /cvsroot/spambayes/spambayes/utilities In directory sc8-pr-cvs1:/tmp/cvs-serv4304/utilities Added Files: which_database.py Log Message: A utility script to let the user know which database systems are available for spambayes to use, and which one the database specified in the options file is using. Based on a script contributed to the mailing list from Remi Ricard. (Note that gdbm is not tested for...someone should probably add this). --- NEW FILE: which_database.py --- #!/usr/bin/env python """which_database This little script checks which database is used to save your data, and also prints out information about which database systems are available. It will check whichever database you have setup to use in the [Storage] persistent_storage_file option. Note that you will end up with extra files after running this utility that may be safely deleted: o dumbdb.dir o dumbdb.dat o dumbdb.bak o bsddb3 o dbhash """ __author__ = "Remi Ricard " __credits__ = "Skip Montanaro, all the Spambayes folk." import os import sys sys.path.insert(-1, os.getcwd()) sys.path.insert(-1, os.path.dirname(os.getcwd())) from spambayes.Options import options import dumbdbm import dbhash import whichdb import bsddb3 def main(): print "Pickle is available." db = dumbdbm.open("dumbdb", "c") db["1"] = "1" db.close() str = whichdb.whichdb("dumbdb") if str: print "Dumbdbm is available." else: print "Dumbdbm is not available." db = dbhash.open("dbhash", "c") db["1"] = "1" db.close() str = whichdb.whichdb("dbhash") if str == "dbhash": print "Dbhash is available." else: print "Dbhash is not available." db = bsddb3.hashopen("bsddb3", "c") db["1"] = "1" db.close() str = whichdb.whichdb("bsddb3") if str == "dbhash": print "Bsddb3 is available." else: print "Bsddb3 is not available." print hammie = options["Storage", "persistent_storage_file"] use_dbm = options["Storage", "persistent_use_database"] if not use_dbm: print "Your storage %s is a: pickle" % (hammie,) return str = whichdb.whichdb(hammie) if str == "dbhash": # could be dbhash or bsddb3 try: db = dbhash.open(hammie, "c") except: print "Your storage %s is a: bsddb3" % (hammie,) return print "Your storage %s is a: %s" % (hammie, str) if __name__ == "__main__": main() From mhammond at users.sourceforge.net Tue Jul 29 21:18:02 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Tue Jul 29 23:18:09 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 addin.py,1.83,1.84 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv10853 Modified Files: addin.py Log Message: Reload the test module before running test suite. Index: addin.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/addin.py,v retrieving revision 1.83 retrieving revision 1.84 diff -C2 -d -r1.83 -r1.84 *** addin.py 29 Jul 2003 00:47:36 -0000 1.83 --- addin.py 30 Jul 2003 03:17:59 -0000 1.84 *************** *** 537,541 **** # A hook for whatever tests we have setup def Tester(manager): ! import tester, traceback try: print "Executing automated tests..." --- 537,544 ---- # A hook for whatever tests we have setup def Tester(manager): ! import tester ! # This is only used in source-code versions - so we may as well reload ! # the test suite to save shutting down Outlook each time we tweak it. ! reload(tester) try: print "Executing automated tests..." From mhammond at users.sourceforge.net Tue Jul 29 21:20:16 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Tue Jul 29 23:20:19 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 msgstore.py,1.59,1.60 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv11124 Modified Files: msgstore.py Log Message: We *do* need to check PR_TRANSPORT_HEADERS to determine if a message is filterable. So we do. Don't bother "demand fetching" the subject. Index: msgstore.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/msgstore.py,v retrieving revision 1.59 retrieving revision 1.60 diff -C2 -d -r1.59 -r1.60 *** msgstore.py 29 Jul 2003 11:08:47 -0000 1.59 --- msgstore.py 30 Jul 2003 03:20:13 -0000 1.60 *************** *** 498,501 **** --- 498,503 ---- PR_MESSAGE_CLASS_A, # 'IPM.Note' etc PR_RECEIVED_BY_ENTRYID, # who received it + PR_SUBJECT_A, + PR_TRANSPORT_MESSAGE_HEADERS_A, ) *************** *** 511,519 **** tag, msgclass = prop_row[4] recby_tag, recby = prop_row[5] self.id = store_eid, eid self.folder_id = store_eid, parent_eid self.msgclass = msgclass ! self.subject = None # Search key is the only reliable thing after a move/copy operation # only problem is that it can potentially be changed - however, the --- 513,533 ---- tag, msgclass = prop_row[4] recby_tag, recby = prop_row[5] + tag, subject = prop_row[6] + headers_tag, headers = prop_row[7] self.id = store_eid, eid self.folder_id = store_eid, parent_eid self.msgclass = msgclass ! self.subject = subject ! if PROP_TYPE(headers_tag)==PT_STRING8: ! self.headers = headers ! has_headers = True ! else: ! # headers probably too big for simple property fetch - this is ! # the case if we got back MAPI_E_NOT_ENOUGH_MEMORY ! # (but don't bother fetching the header yet) ! has_headers = PROP_TYPE(headers_tag)==PT_ERROR and \ ! headers==mapi.MAPI_E_NOT_ENOUGH_MEMORY ! self.headers = None # Search key is the only reliable thing after a move/copy operation # only problem is that it can potentially be changed - however, the *************** *** 530,537 **** # RECEIVED_BY_ENTRYID PR_TRANSPORT_MESSAGE_HEADERS # But MarkH can't find it, and believes and tests that ! # PR_RECEIVED_BY_ENTRYID is all we need. ! # This also means we don't need to check the 'unsent' flag - unsent ! # messages never have the PR_RECEIVED_ properties either. ! self.was_received = PROP_TYPE(recby_tag) == PT_BINARY self.dirty = False --- 544,551 ---- # RECEIVED_BY_ENTRYID PR_TRANSPORT_MESSAGE_HEADERS # But MarkH can't find it, and believes and tests that ! # PR_RECEIVED_BY_ENTRYID is all we need (but has since discovered a ! # couple of messages without any PR_RECEIVED_BY properties - but *with* ! # PR_TRANSPORT_MESSAGE_HEADERS - *sigh*) ! self.was_received = PROP_TYPE(recby_tag) == PT_BINARY or has_headers self.dirty = False *************** *** 558,563 **** def GetSubject(self): - if self.subject is None: - self.subject = self.GetField(PR_SUBJECT_A,) return self.subject --- 572,575 ---- *************** *** 589,601 **** self._EnsureObject() ! prop_ids = (PR_TRANSPORT_MESSAGE_HEADERS_A, ! PR_BODY_A, MYPR_BODY_HTML_A, PR_HASATTACH) hr, data = self.mapi_object.GetProps(prop_ids,0) ! headers = self._GetPotentiallyLargeStringProp(prop_ids[0], data[0]) ! body = self._GetPotentiallyLargeStringProp(prop_ids[1], data[1]) ! html = self._GetPotentiallyLargeStringProp(prop_ids[2], data[2]) ! has_attach = data[3][1] # Some Outlooks deliver a strange notion of headers, including --- 601,617 ---- self._EnsureObject() ! if self.headers is None: # they were too large when created! ! prop_ids = (PR_TRANSPORT_MESSAGE_HEADERS_A,) ! hr, data = self.mapi_object.GetProps(prop_ids,0) ! self.headers = self._GetPotentiallyLargeStringProp(prop_ids[0], data[0]) ! headers = self.headers ! ! prop_ids = (PR_BODY_A, MYPR_BODY_HTML_A, PR_HASATTACH) hr, data = self.mapi_object.GetProps(prop_ids,0) ! body = self._GetPotentiallyLargeStringProp(prop_ids[0], data[0]) ! html = self._GetPotentiallyLargeStringProp(prop_ids[1], data[1]) ! has_attach = data[2][1] # Some Outlooks deliver a strange notion of headers, including From mhammond at users.sourceforge.net Tue Jul 29 21:21:23 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Tue Jul 29 23:21:26 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 tester.py,1.10,1.11 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv11509 Modified Files: tester.py Log Message: Re-org things a little, and run over all our folder reporting suspicious messages we are deciding not to filter that maybe we should. Index: tester.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/tester.py,v retrieving revision 1.10 retrieving revision 1.11 diff -C2 -d -r1.10 -r1.11 *** tester.py 27 Jul 2003 23:49:59 -0000 1.10 --- tester.py 30 Jul 2003 03:21:21 -0000 1.11 *************** *** 321,349 **** driver.CleanAllTestMessages() ! def test(manager): ! # Run the tests - called from our plugin. import msgstore try: msgstore.test_suite_running = True ! # setup config to save info with the message, and test ! print "*" * 10, "Running tests with save_spam_info=True, timer off" ! manager.config.experimental.timer_start_delay = 0 ! manager.config.experimental.timer_interval = 0 ! manager.config.filter.save_spam_info = True ! manager.addin.FiltersChanged() # to ensure correct filtler in place ! run_tests(manager) ! # do it again with the same config, just to prove we can. ! print "*" * 10, "Running them again with save_spam_info=True" ! run_tests(manager) ! # enable the timer. ! manager.config.experimental.timer_start_delay = 1000 ! manager.config.experimental.timer_interval = 500 ! manager.addin.FiltersChanged() # to switch to timer based filters. ! print "*" * 10, "Running them again with save_spam_info=True, and timer enabled" ! run_tests(manager) ! # and with save_spam_info False. ! print "*" * 10, "Running tests with save_spam_info=False" ! manager.config.filter.save_spam_info = False ! run_tests(manager) finally: # Always restore configuration to how we started. --- 321,384 ---- driver.CleanAllTestMessages() ! def run_filter_tests(manager): ! # setup config to save info with the message, and test ! print "*" * 10, "Running tests with save_spam_info=True, timer off" ! manager.config.experimental.timer_start_delay = 0 ! manager.config.experimental.timer_interval = 0 ! manager.config.filter.save_spam_info = True ! manager.addin.FiltersChanged() # to ensure correct filtler in place ! run_tests(manager) ! # do it again with the same config, just to prove we can. ! print "*" * 10, "Running them again with save_spam_info=True" ! run_tests(manager) ! # enable the timer. ! manager.config.experimental.timer_start_delay = 1000 ! manager.config.experimental.timer_interval = 500 ! manager.addin.FiltersChanged() # to switch to timer based filters. ! print "*" * 10, "Running them again with save_spam_info=True, and timer enabled" ! run_tests(manager) ! # and with save_spam_info False. ! print "*" * 10, "Running tests with save_spam_info=False" ! manager.config.filter.save_spam_info = False ! run_tests(manager) ! print "*" * 10, "Filtering tests completed successfully." ! ! def run_nonfilter_tests(manager): ! # And now some other 'sanity' checks. ! # Check messages we are unable to score. ! # Must enable the filtering code for this test import msgstore + msgstore.test_suite_running = False try: + num_found = num_looked = 0 + for folder_ids, include_sub in [ + (manager.config.filter.watch_folder_ids, manager.config.filter.watch_include_sub), + ([manager.config.filter.spam_folder_id], False), + ]: + for folder in manager.message_store.GetFolderGenerator(folder_ids, include_sub): + for message in folder.GetMessageGenerator(False): + # If not ipm.note, then no point reporting - but any + # ipm.note messages we don't want to filter should be + # reported. + num_looked += 1 + if not message.IsFilterCandidate() and \ + message.msgclass.lower().startswith("ipm.note"): + if num_found == 0: + print "*" * 80 + print "WARNING: We found the following messages in your folders that would not be filtered by the addin" + print "If any of these messages should be filtered, we have a bug!" + num_found += 1 + print " %s/%s" % (folder.name, message.subject) + print "Checked %d items, %d non-filterable items found" % (num_looked, num_found) + finally: msgstore.test_suite_running = True ! ! def test(manager): ! import msgstore, win32ui ! win32ui.DoWaitCursor(1) ! try: # restore the plugin config at exit. ! msgstore.test_suite_running = True ! run_filter_tests(manager) ! run_nonfilter_tests(manager) finally: # Always restore configuration to how we started. *************** *** 351,354 **** --- 386,390 ---- manager.LoadConfig() manager.addin.FiltersChanged() # restore original filters. + win32ui.DoWaitCursor(0) if __name__=='__main__': From mhammond at users.sourceforge.net Tue Jul 29 21:22:53 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Tue Jul 29 23:22:56 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 manager.py,1.68,1.69 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv11693 Modified Files: manager.py Log Message: ReportError should only attempt to print a traceback when there is actually an exception. Index: manager.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/manager.py,v retrieving revision 1.68 retrieving revision 1.69 diff -C2 -d -r1.68 -r1.69 *** manager.py 27 Jul 2003 23:47:43 -0000 1.68 --- manager.py 30 Jul 2003 03:22:51 -0000 1.69 *************** *** 105,109 **** import traceback print "ERROR:", repr(message) ! traceback.print_exc() if title is None: title = "SpamBayes Anti-Spam plugin" --- 105,110 ---- import traceback print "ERROR:", repr(message) ! if sys.exc_info()[0] is not None: ! traceback.print_exc() if title is None: title = "SpamBayes Anti-Spam plugin" From mhammond at users.sourceforge.net Tue Jul 29 21:31:18 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Wed Jul 30 00:41:33 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000/dialogs FilterDialog.py, 1.19, 1.20 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000/dialogs In directory sc8-pr-cvs1:/tmp/cvs-serv13135 Modified Files: FilterDialog.py Log Message: Avoid passing a float to C functions that take an int (the slider pos) Index: FilterDialog.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/dialogs/FilterDialog.py,v retrieving revision 1.19 retrieving revision 1.20 diff -C2 -d -r1.19 -r1.20 *** FilterDialog.py 18 Jul 2003 06:25:48 -0000 1.19 --- FilterDialog.py 30 Jul 2003 03:31:11 -0000 1.20 *************** *** 231,235 **** edit = self.GetDlgItem(idc_edit) try: ! val = float(edit.GetWindowText()) except ValueError: return --- 231,237 ---- edit = self.GetDlgItem(idc_edit) try: ! # Get as float so we dont fail should the .0 be there, but ! # then convert to int as the slider only works with ints ! val = int(float(edit.GetWindowText())) except ValueError: return From anadelonbrin at users.sourceforge.net Wed Jul 30 17:21:17 2003 From: anadelonbrin at users.sourceforge.net (Tony Meyer) Date: Wed Jul 30 19:21:21 2003 Subject: [Spambayes-checkins] website faq.txt,1.21,1.22 Message-ID: Update of /cvsroot/spambayes/website In directory sc8-pr-cvs1:/tmp/cvs-serv25128 Modified Files: faq.txt Log Message: Add a FAQ about how people can help if they don't know how to program. (I'm actually getting this as a FAQ! it's great!). Index: faq.txt =================================================================== RCS file: /cvsroot/spambayes/website/faq.txt,v retrieving revision 1.21 retrieving revision 1.22 diff -C2 -d -r1.21 -r1.22 *** faq.txt 29 Jul 2003 08:36:15 -0000 1.21 --- faq.txt 30 Jul 2003 23:21:15 -0000 1.22 *************** *** 743,746 **** --- 743,777 ---- + I'm not a programmer, but want to help out - what can I do? + ----------------------------------------------------------- + + Fantastic! There are four main ways to contribute (including programming): + + * Coding (i.e. submitting patches or new code) + * Documenting (including the website) + * Testing (the application, plus using our extensive testing setup to test + options) + * Support (helping others out, through the mailing list and/or the sf bug + report system) + + Sadly, not much is done in the way of testing these days. Hopefully this + will change, though, and if you're interested it's definately an option. + Check out the README for information about how to get started. This is the + way to go if you have a new idea, too - even if you convince someone else to + develop it, we'll expect you to put in time to test its effectiveness. + + Support is always helpful - especially since it can often save the developers + from answering questions, which leaves more time to add features/remove bugs. + + Which leaves documentation - this is always in need of work. Take a look at + what there is and see what you can improve, or ask on the list for advice + about which files need updating most urgently. If you want to contribute + to this, the easiest thing is to work on a current copy of the documentation + (unless it's a new piece) and then submit it to the list or via the + sourceforge patch system. One of the developers will go over it and check + it in (although please be patient - sometimes it may take a while for them + to have the time to go through it). + + Is there anything else I should know? ------------------------------------- *************** *** 771,777 **** on 28th July 2003. To work around it, use fetchmail's ``fetchall`` option. ! My database keeps getting corrupted and I get trackbacks with "dumbdbm" in them. ! -------------------------------------------------------------------------------- 'dumbdbm' is the default database system - the one that gets fallen back on when nothing else is available. It is not usually a good choice, and in --- 802,809 ---- on 28th July 2003. To work around it, use fetchmail's ``fetchall`` option. ! My database keeps getting corrupted. ! ------------------------------------ + You may be using the 'dumbdbm' system for your database. 'dumbdbm' is the default database system - the one that gets fallen back on when nothing else is available. It is not usually a good choice, and in *************** *** 779,788 **** that will cause database corruption, but you shouldn't be using it anyway, as it is very inefficient. Instead, either use a pickle or install `pybsddb`_ ! (bsddb3) and use that instead. Support for dumbdbm will be dropped in a ! future release. Note that none of this applies to the Outlook plug-in, which avoids it on your behalf. .. _pybsddb: http://pybsddb.sourceforge.net/ --- 811,825 ---- that will cause database corruption, but you shouldn't be using it anyway, as it is very inefficient. Instead, either use a pickle or install `pybsddb`_ ! (bsddb3) and use that instead. If you are not sure which database systems ! you have available, and/or which one you are currently using, there is a ! script in the utilities folder called `which_database.py`_ that will display ! this information (Windows users should run it from a command prompt). + Support for dumbdbm will be dropped in a future release. + Note that none of this applies to the Outlook plug-in, which avoids it on your behalf. + .. _which_database.py: http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/*checkout*/spambayes/spambayes/utilities/which_database.py?rev=HEAD&content-type=text/plain .. _pybsddb: http://pybsddb.sourceforge.net/ From mhammond at users.sourceforge.net Thu Jul 31 02:27:53 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Thu Jul 31 04:28:12 2003 Subject: [Spambayes-checkins] website Makefile,1.8,1.9 Message-ID: Update of /cvsroot/spambayes/website In directory sc8-pr-cvs1:/tmp/cvs-serv27432 Modified Files: Makefile Log Message: Don't stream html.py output through sed etc, as on Windows at least, this prevents the failure of html.py from aborting the build. Instead we generate to a temp file, which does cause a fatal error. Index: Makefile =================================================================== RCS file: /cvsroot/spambayes/website/Makefile,v retrieving revision 1.8 retrieving revision 1.9 diff -C2 -d -r1.8 -r1.9 *** Makefile 29 Jul 2003 02:07:14 -0000 1.8 --- Makefile 31 Jul 2003 08:27:51 -0000 1.9 *************** *** 18,26 **** DUHTML = html.py faq.ht : faq.txt echo "Title: SpamBayes FAQ" > faq.ht echo "Author-Email: SpamBayes@python.org" >> faq.ht echo "Author: SpamBayes" >> faq.ht echo "" >> faq.ht ! $(DUHTML) faq.txt | sed -e '1,//d' -e '/<\/body>/,$$d' >> faq.ht faq.html : faq.ht --- 18,28 ---- DUHTML = html.py faq.ht : faq.txt + $(DUHTML) faq.txt > faq.body.tmp echo "Title: SpamBayes FAQ" > faq.ht echo "Author-Email: SpamBayes@python.org" >> faq.ht echo "Author: SpamBayes" >> faq.ht echo "" >> faq.ht ! cat faq.body.tmp | sed -e '1,//d' -e '/<\/body>/,$$d' >> faq.ht ! rm faq.body.tmp faq.html : faq.ht From mhammond at users.sourceforge.net Thu Jul 31 04:08:23 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Thu Jul 31 06:08:26 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 addin.py,1.84,1.85 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv12517 Modified Files: addin.py Log Message: Try to not imply that the version number we are displaying is the local version. I really should just display *both* versions! Index: addin.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/addin.py,v retrieving revision 1.84 retrieving revision 1.85 diff -C2 -d -r1.84 -r1.85 *** addin.py 30 Jul 2003 03:17:59 -0000 1.84 --- addin.py 31 Jul 2003 10:08:20 -0000 1.85 *************** *** 532,536 **** else: msg = "The latest available version is %s\r\n\r\n" \ ! "You already have the latest version." % latest_ver_string win32ui.MessageBox(msg, "SpamBayes") --- 532,536 ---- else: msg = "The latest available version is %s\r\n\r\n" \ ! "No later version is available." % latest_ver_string win32ui.MessageBox(msg, "SpamBayes") From mhammond at users.sourceforge.net Thu Jul 31 06:28:50 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Thu Jul 31 08:28:54 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 about.html,1.16,1.17 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv4060 Modified Files: about.html Log Message: Add a link to the FAQ. Index: about.html =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/about.html,v retrieving revision 1.16 retrieving revision 1.17 diff -C2 -d -r1.16 -r1.17 *** about.html 29 Jul 2003 01:54:34 -0000 1.16 --- about.html 31 Jul 2003 12:28:48 -0000 1.17 *************** *** 49,53 **** see the configuration guide.  If you have any problems, please see the troubleshooting guide.

    Using the plugin

    --- 49,56 ---- see the configuration guide.  If you have any problems, please see the troubleshooting guide.  You ! may also like to browse the Outlook ! section of the online SpamBayes Frequently Asked Questions (FAQ).

    Using the plugin

    From mhammond at users.sourceforge.net Thu Jul 31 06:30:03 2003 From: mhammond at users.sourceforge.net (Mark Hammond) Date: Thu Jul 31 08:30:10 2003 Subject: [Spambayes-checkins] spambayes/Outlook2000 msgstore.py, 1.60, 1.61 filter.py, 1.27, 1.28 Message-ID: Update of /cvsroot/spambayes/spambayes/Outlook2000 In directory sc8-pr-cvs1:/tmp/cvs-serv4180 Modified Files: msgstore.py filter.py Log Message: Fix [ 780801 ] IMAP Still Failing - GetField() returns None on MAPI error (no idea why it does, but I'm not sure I care) and stupid error in exception handler. Index: msgstore.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/msgstore.py,v retrieving revision 1.60 retrieving revision 1.61 diff -C2 -d -r1.60 -r1.61 *** msgstore.py 30 Jul 2003 03:20:13 -0000 1.60 --- msgstore.py 31 Jul 2003 12:30:00 -0000 1.61 *************** *** 830,834 **** self.dirty = True ! def GetField(self, prop): self._EnsureObject() if type(prop) != type(0): --- 830,834 ---- self.dirty = True ! def GetField(self, prop, raise_errors = False): self._EnsureObject() if type(prop) != type(0): *************** *** 838,849 **** return None prop = PROP_TAG( PT_UNSPECIFIED, PROP_ID(prop)) ! hr, props = self.mapi_object.GetProps((prop,), 0) ! ((tag, val), ) = props ! if PROP_TYPE(tag) == PT_ERROR: ! if val == mapi.MAPI_E_NOT_ENOUGH_MEMORY: ! # Too big for simple properties - get via a stream ! return self._GetPropFromStream(prop) return None - return val def GetReadState(self): --- 838,854 ---- return None prop = PROP_TAG( PT_UNSPECIFIED, PROP_ID(prop)) ! try: ! hr, props = self.mapi_object.GetProps((prop,), 0) ! ((tag, val), ) = props ! if PROP_TYPE(tag) == PT_ERROR: ! if val == mapi.MAPI_E_NOT_ENOUGH_MEMORY: ! # Too big for simple properties - get via a stream ! return self._GetPropFromStream(prop) ! return None ! return val ! except: ! if raise_errors: ! raise return None def GetReadState(self): Index: filter.py =================================================================== RCS file: /cvsroot/spambayes/spambayes/Outlook2000/filter.py,v retrieving revision 1.27 retrieving revision 1.28 diff -C2 -d -r1.27 -r1.28 *** filter.py 20 Jul 2003 13:37:00 -0000 1.27 --- filter.py 31 Jul 2003 12:30:00 -0000 1.28 *************** *** 43,47 **** msg.RememberMessageCurrentFolder() msg.Save() ! except pythoncom.com_error, (hr, msg, exc, arg_err): # This seems to happen for IMAP mails (0x800cccd3) # and also for hotmail messages (0x8004dff7) --- 43,47 ---- msg.RememberMessageCurrentFolder() msg.Save() ! except pythoncom.com_error, (hr, exc_msg, exc, arg_err): # This seems to happen for IMAP mails (0x800cccd3) # and also for hotmail messages (0x8004dff7) *************** *** 50,54 **** if hr not in known_failure_codes: print "Unexpected MAPI error saving the spam score for", msg ! print hr, msg, exc else: # So we can see if it still happens :) --- 50,54 ---- if hr not in known_failure_codes: print "Unexpected MAPI error saving the spam score for", msg ! print hr, exc_msg, exc else: # So we can see if it still happens :)