📄 manager.py
字号:
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""" return profile_name 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.GetProfileName() self.config_filename = os.path.join(self.data_directory, profile_name + ".ini") self.never_configured = not os.path.exists(self.config_filename) # Now load it up self._MergeConfigFile(self.config_filename) # Set global verbosity from the options file. self.verbose = self.config.general.verbose if self.verbose: self.LogDebug(self.verbose, "System verbosity set to", self.verbose) # Do any migrations - first the old pickle into the new format. self.MigrateOldPickle() # Then any options we change (particularly any 'experimental' ones we # consider important) import config config.MigrateOptions(self.options) 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" pickle_filename = os.path.join(self.data_directory, "default_configuration.pck") try: f = open(pickle_filename, 'rb') except IOError: self.LogDebug(1, "No old pickle file to migrate") return print "Migrating old pickle '%s'" % pickle_filename try: 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" \ "It is likely that you will need to re-configure\r\n" \ "SpamBayes before it will function correctly.") self.ReportError(msg) # But we can't abort yet - we really should still try and # delete it, as we aren't gunna work next time in this case! old_config = None finally: f.close() if old_config is not None: for section, items in old_config.__dict__.items(): print " migrating section '%s'" % (section,) # exactly one value wasn't in a section - now in "general" dict = getattr(items, "__dict__", None) if dict is None: dict = {section: items} section = "general" for name, value in dict.items(): sect = getattr(self.config, section) setattr(sect, name, value) # Save the config, then delete the pickle so future attempts to # migrate will fail. We save first, so failure here means next # attempt should still find the pickle. self.LogDebug(1, "pickle migration doing initial configuration save") try: self.LogDebug(1, "pickle migration removing '%s'" % pickle_filename) os.remove(pickle_filename) except os.error: msg = _("There was an error migrating and removing your old\r\n" \ "SpamBayes configuration file. Configuration changes\r\n" \ "you make are unlikely to be reflected next\r\n" \ "time you start Outlook. Please try rebooting.") self.ReportError(msg) def GetClassifier(self): """Return the classifier we're using.""" return self.classifier_data.bayes 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") # Update our runtime verbosity from the options. self.verbose = self.config.general.verbose 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) def Save(self): # No longer save the config here - do it explicitly when changing it # (prevents lots of extra pickle writes, for no good reason. Other # alternative is a dirty flag for config - this is simpler) if self.classifier_data.dirty: self.classifier_data.Save() else: self.LogDebug(1, "Bayes database is not dirty - not writing") def Close(self): global _mgr self._KillNotifyTimer() self.classifier_data.Close() self.config = self.options = None if self.message_store is not None: self.message_store.Close() self.message_store = None self.outlook = None self.addin = None # If we are the global manager, reset that if _mgr is self: _mgr = None def score(self, msg, evidence=False): """Score a msg. If optional arg evidence is specified and true, the result is a two-tuple score, clues where clues is a list of the (word, spamprob(word)) pairs that went into determining the score. Else just the score is returned. """ email = msg.GetEmailPackageObject() try: return self.classifier_data.bayes.spamprob(bayes_tokenize(email), evidence) except AssertionError: # See bug 706520 assert fails in classifier # For now, just tell the user. msg = _("It appears your SpamBayes training database is corrupt.\r\n\r\n" \ "We are working on solving this, but unfortunately you\r\n" \ "must re-train the system via the SpamBayes manager.") self.ReportErrorOnce(msg) # and disable the addin, as we are hosed! self.config.filter.enabled = False raise def GetDisabledReason(self): # Gets the reason why the plugin can not be enabled. # If return is None, then it can be enabled (and indeed may be!) # Otherwise return is the string reason config = self.config.filter ok_to_enable = operator.truth(config.watch_folder_ids) if not ok_to_enable: return _("You must define folders to watch for new messages. " \ "Select the 'Filtering' tab to define these folders.") ok_to_enable = operator.truth(config.spam_folder_id) if not ok_to_enable: return _("You must define the folder to receive your certain spam. " \ "Select the 'Filtering' tab to define this folder.") # Check that the user hasn't selected the same folder as both # 'Spam' or 'Unsure', and 'Watch' - this would confuse us greatly. ms = self.message_store unsure_folder = None # unsure need not be specified. if config.unsure_folder_id: try: unsure_folder = ms.GetFolder(config.unsure_folder_id) except ms.MsgStoreException, details: return _("The unsure folder is invalid: %s") % (details,) try: spam_folder = ms.GetFolder(config.spam_folder_id) except ms.MsgStoreException, details: return _("The spam folder is invalid: %s") % (details,) if ok_to_enable: for folder in ms.GetFolderGenerator(config.watch_folder_ids, config.watch_include_sub): bad_folder_type = None if unsure_folder is not None and unsure_folder == folder: bad_folder_type = _("unsure") bad_folder_name = unsure_folder.GetFQName() if spam_folder == folder: bad_folder_type = _("spam") bad_folder_name = spam_folder.GetFQName() if bad_folder_type is not None: return _("You can not specify folder '%s' as both the " \ "%s folder, and as being watched.") \ % (bad_folder_name, bad_folder_type) return None def ShowManager(self): import dialogs dialogs.ShowDialog(0, self, self.config, "IDD_MANAGER") # And re-save now, just incase Outlook dies on the way down. self.SaveConfig() # And update the cutoff values in bayes_options (which the # stats use) to our thresholds. bayes_options["Categorization", "spam_cutoff"] = \ self.config.filter.spam_threshold \ / 100.0 bayes_options["Categorization", "ham_cutoff"] = \ self.config.filter.unsure_threshold \ / 100.0 # And tell the addin that our filters may have changed. if self.addin is not None: self.addin.FiltersChanged() def ShowFilterNow(self): import dialogs dialogs.ShowDialog(0, self, self.config, "IDD_FILTER_NOW") # And re-save now, just incase Outlook dies on the way down. self.SaveConfig() def ShowHtml(self,url): """Displays the main SpamBayes documentation in your Web browser""" import sys, os, urllib if urllib.splittype(url)[0] is None: # just a file spec if hasattr(sys, "frozen"): # New binary is in ../docs/outlook relative to executable. fname = os.path.join(os.path.dirname(sys.argv[0]), "../docs/outlook", url) if not os.path.isfile(fname): # Still support same directory as to the executable. fname = os.path.join(os.path.dirname(sys.argv[0]), url) else: # (ie, main Outlook2000) dir fname = os.path.join(os.path.dirname(__file__), url) fname = os.path.abspath(fname) if not os.path.isfile(fname): self.ReportError("Can't find "+url) return url = fname # else assume it is valid! from dialogs import SetWaitCursor SetWaitCursor(1) os.startfile(url) SetWaitCursor(0) def HandleNotification(self, disposition): if self.config.notification.notify_sound_enabled: if disposition == "Yes": self.received_spam += 1 elif disposition == "No": self.received_ham += 1 else: self.received_unsure += 1 self._StartNotifyTimer() def _StartNotifyTimer(self): # First kill any existing timer self._KillNotifyTimer() # And start a new timer. delay = self.config.notification.notify_accumulate_delay self._DoStartNotifyTimer(delay) def _DoStartNotifyTimer(self, delay): assert thread.get_ident() == self.owner_thread_ident assert self.notify_timer_id is None, "Shouldn't start a timer when already have one" assert isinstance(delay, types.FloatType), "Timer values are float seconds" # And start a new timer. assert delay, "No delay means no timer!" delay = int(delay*1000) # convert to ms. self.notify_timer_id = timer.set_timer(delay, self._NotifyTimerFunc) self.LogDebug(1, "Notify timer started - id=%d, delay=%d" % (self.notify_timer_id, delay)) def _KillNotifyTimer(self): assert thread.get_ident() == self.owner_thread_ident if self.notify_timer_id is not None: timer.kill_timer(self.notify_timer_id) self.LogDebug(2, "The notify timer with id=%d was stopped" % self.notify_timer_id) self.notify_timer_id = None def _NotifyTimerFunc(self, event, time): # Kill the timer first assert thread.get_ident() == self.owner_thread_ident self.LogDebug(1, "The notify timer with id=%s fired" % self.notify_timer_id) self._KillNotifyTimer() import winsound config = self.config.notification sound_opts = winsound.SND_FILENAME | winsound.SND_ASYNC | winsound.SND_NOSTOP | winsound.SND_NODEFAULT self.LogDebug(3, "Notify received ham=%d, unsure=%d, spam=%d" % (self.received_ham, self.received_unsure, self.received_spam)) if self.received_ham > 0 and len(config.notify_ham_sound) > 0: self.LogDebug(3, "Playing ham sound '%s'" % config.notify_ham_sound) winsound.PlaySound(config.notify_ham_sound, sound_opts) elif self.received_unsure > 0 and len(config.notify_unsure_sound) > 0: self.LogDebug(3, "Playing unsure sound '%s'" % config.notify_unsure_sound) winsound.PlaySound(config.notify_unsure_sound, sound_opts) elif self.received_spam > 0 and len(config.notify_spam_sound) > 0: self.LogDebug(3, "Playing spam sound '%s'" % config.notify_spam_sound) winsound.PlaySound(config.notify_spam_sound, sound_opts) # Reset received counts to zero after notify. self.received_ham = self.received_unsure = self.received_spam = 0_mgr = Nonedef GetManager(outlook = None): global _mgr if _mgr is None: if outlook is None: outlook = win32com.client.Dispatch("Outlook.Application") _mgr = BayesManager(outlook=outlook) return _mgrdef ShowManager(mgr): mgr.ShowManager()def main(verbose_level = 1): mgr = GetManager() mgr.verbose = max(mgr.verbose, verbose_level) ShowManager(mgr) mgr.Save() mgr.Close() return 0def usage(): print "Usage: manager [-v ...]" sys.exit(1)if __name__=='__main__': verbose = 1 import getopt opts, args = getopt.getopt(sys.argv[1:], "v") if args: usage() for opt, val in opts: if opt=="-v": verbose += 1 else: usage() sys.exit(main(verbose))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -