📄 sb_pop3dnd.py
字号:
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 = 1 else: self.nextUID = long(self.storage.keys()[-1]) + 1 # Calculate initial recent and unseen counts 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, msg): """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()[msg - 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, content, flags=(), date=None): """Add the given message to this mailbox.""" msg = self.storage.makeMessage(self.getUIDNext(True), content.read()) msg.date = date 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: if not self.storage.keys(): return 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 # Load the message, if necessary if hasattr(msg, "load"): 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 or (): # flags might be None 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_messagesclass SpambayesInbox(SpambayesMailbox): """A special mailbox that holds status messages from SpamBayes.""" def __init__(self, id, state): IMAPMailbox.__init__(self, "INBOX", "spambayes", id) self.mdb = state.mdb self.UID_validity = id self.nextUID = 1 self.unseen_count = 0 self.recent_count = 0 self.storage = {} self.createMessages() self.stats = state.stats def buildStatusMessage(self, body=False, headers=False): """Build a message containing the current status message. If body is True, then return the body; if headers is True return the headers. If both are true, then return both (and insert a newline between them). """ msg = [] if headers: msg.append("Subject: SpamBayes Status") msg.append('From: "SpamBayes" <no-reply@spambayes.invalid>') if body: msg.append('\r\n') if body: state.buildStatusStrings() msg.append("POP3 proxy running on %s, proxying to %s." % \ (state.proxyPortsString, state.serversString)) msg.append("Active POP3 conversations: %s." % \ (state.activeSessions,)) msg.append("POP3 conversations this session: %s." % \ (state.totalSessions,)) msg.append("IMAP server running on %s." % \ (state.serverPortString,)) msg.append("Active IMAP4 conversations: %s." % \ (state.activeIMAPSessions,)) msg.append("IMAP4 conversations this session: %s." % \ (state.totalIMAPSessions,)) msg.append("Emails classified this session: %s spam, %s ham, " "%s unsure." % (state.numSpams, state.numHams, state.numUnsure)) msg.append("Total emails trained: Spam: %s Ham: %s" % \ (state.bayes.nspam, state.bayes.nham)) msg.append(state.warning or "SpamBayes is operating correctly.\r\n") return "\r\n".join(msg) def buildStatisticsMessage(self, body=False, headers=False): """Build a mesasge containing the current statistics. If body is True, then return the body; if headers is True return the headers. If both are true, then return both (and insert a newline between them). """ msg = [] if headers: msg.append("Subject: SpamBayes Statistics") msg.append('From: "SpamBayes" <no-reply@spambayes.invalid') if body: msg.append('\r\n') if body: msg.extend(self.stats.GetStats(use_html=False)) return "\r\n".join(msg) def createMessages(self): """Create the special messages that live in this mailbox.""" state.buildStatusStrings() state.buildServerStrings() about = 'Subject: About SpamBayes / POP3DND\r\n' \ 'From: "SpamBayes" <no-reply@spambayes.invalid>\r\n\r\n' \ '%s\r\nSee <http://spambayes.org>.\r\n' % (__doc__,) date = imaplib.Time2Internaldate(time.time())[1:-1] msg = email.message_from_string(about, _class=IMAPMessage) msg.date = date self.addMessage(msg) msg = DynamicIMAPMessage(self.buildStatusMessage, self.mdb) self.addMessage(msg) msg = DynamicIMAPMessage(self.buildStatisticsMessage, self.mdb) self.addMessage(msg) # XXX Add other messages here, for example # XXX help and other documentation. def isWriteable(self): """Get the read/write status of the mailbox.""" return False def addMessage(self, msg, flags=(), date=None): """Add the given message to this mailbox.""" msg.id = self.getUIDNext(True) self.storage[msg.id] = msg d = defer.Deferred() reactor.callLater(0, d.callback, self.storage.keys().index(msg.id)) return d def expunge(self): """Remove all messages flagged \\Deleted.""" # Mailbox is read-only. return [] def store(self, messages, flags, mode, uid): """Set the flags of one or more messages.""" # Mailbox is read-only. return {}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, or 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, train_spam, inbox): MemoryAccount.__init__(self, id) self.mailboxes = {"SPAM" : spam, "UNSURE" : unsure, "TRAIN_AS_HAM" : ham, "TRAIN_AS_SPAM" : train_spam, "INBOX" : inbox} def select(self, name, readwrite=1): # 'INBOX' is a special case-insensitive name meaning the # primary mailbox for the user; for our purposes this contains # special messages from SpamBayes. return MemoryAccount.select(self, name, readwrite)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -