diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/mailman/Utils.py | 6 | ||||
| -rw-r--r-- | src/mailman/app/moderator.py | 5 | ||||
| -rw-r--r-- | src/mailman/app/registrar.py | 2 | ||||
| -rw-r--r-- | src/mailman/bin/master.py | 16 | ||||
| -rw-r--r-- | src/mailman/chains/hold.py | 6 | ||||
| -rw-r--r-- | src/mailman/commands/cli_control.py | 5 | ||||
| -rw-r--r-- | src/mailman/commands/cli_lists.py | 5 | ||||
| -rw-r--r-- | src/mailman/commands/docs/create.txt | 3 | ||||
| -rw-r--r-- | src/mailman/config/config.py | 13 | ||||
| -rw-r--r-- | src/mailman/config/configure.zcml | 5 | ||||
| -rw-r--r-- | src/mailman/core/constants.py | 4 | ||||
| -rw-r--r-- | src/mailman/core/initialize.py | 6 | ||||
| -rw-r--r-- | src/mailman/docs/languages.txt | 33 | ||||
| -rw-r--r-- | src/mailman/docs/message.txt | 3 | ||||
| -rw-r--r-- | src/mailman/docs/users.txt | 3 | ||||
| -rw-r--r-- | src/mailman/interfaces/languages.py | 3 | ||||
| -rw-r--r-- | src/mailman/languages/manager.py | 4 | ||||
| -rw-r--r-- | src/mailman/model/domain.py | 16 | ||||
| -rw-r--r-- | src/mailman/model/mailinglist.py | 3 | ||||
| -rw-r--r-- | src/mailman/model/preferences.py | 4 | ||||
| -rw-r--r-- | src/mailman/pipeline/acknowledge.py | 7 | ||||
| -rw-r--r-- | src/mailman/queue/__init__.py | 19 | ||||
| -rw-r--r-- | src/mailman/queue/command.py | 10 |
23 files changed, 124 insertions, 57 deletions
diff --git a/src/mailman/Utils.py b/src/mailman/Utils.py index bde703cf4..2ea22cee4 100644 --- a/src/mailman/Utils.py +++ b/src/mailman/Utils.py @@ -44,6 +44,7 @@ from email.errors import HeaderParseError from email.header import decode_header, make_header from lazr.config import as_boolean from string import ascii_letters, digits, whitespace +from zope.component import getUtility import mailman.templates @@ -51,6 +52,7 @@ from mailman import passwords from mailman.config import config from mailman.core import errors from mailman.core.i18n import _ +from mailman.interfaces.languages import ILanguageManager from mailman.utilities.string import expand @@ -406,7 +408,7 @@ def findtext(templatefile, raw_dict=None, raw=False, lang=None, mlist=None): else: template = fp.read() fp.close() - charset = config.languages[lang].charset + charset = getUtility(ILanguageManager)[lang].charset template = unicode(template, charset, 'replace') text = template if raw_dict is not None: @@ -431,7 +433,7 @@ def uncanonstr(s, lang=None): if lang is None: charset = 'us-ascii' else: - charset = config.languages[lang].charset + charset = getUtility(ILanguageManager)[lang].charset # See if the string contains characters only in the desired character # set. If so, return it unchanged, except for coercing it to a byte # string. diff --git a/src/mailman/app/moderator.py b/src/mailman/app/moderator.py index 3151e91c8..e29213f3f 100644 --- a/src/mailman/app/moderator.py +++ b/src/mailman/app/moderator.py @@ -44,6 +44,7 @@ from mailman.core import errors from mailman.core.i18n import _ from mailman.email.message import UserNotification from mailman.interfaces.action import Action +from mailman.interfaces.languages import ILanguageManager from mailman.interfaces.member import AlreadySubscribedError, DeliveryMode from mailman.interfaces.messages import IMessageStore from mailman.interfaces.requests import IRequests, RequestType @@ -237,14 +238,14 @@ def handle_subscription(mlist, id, action, comment=None): _refuse(mlist, _('Subscription request'), data['address'], comment or _('[No reason given]'), - lang=config.languages[data['language']]) + lang=getUtility(ILanguageManager)[data['language']]) elif action is Action.accept: key, data = requestdb.get_request(id) enum_value = data['delivery_mode'].split('.')[-1] delivery_mode = DeliveryMode(enum_value) address = data['address'] realname = data['realname'] - language = config.languages[data['language']] + language = getUtility(ILanguageManager)[data['language']] password = data['password'] try: add_member(mlist, address, realname, password, diff --git a/src/mailman/app/registrar.py b/src/mailman/app/registrar.py index c24376494..1a7a985c6 100644 --- a/src/mailman/app/registrar.py +++ b/src/mailman/app/registrar.py @@ -83,7 +83,7 @@ class Registrar: # Send a verification email to the address. text = _(resource_string('mailman.templates.en', 'verify.txt')) msg = UserNotification(address, confirm_address, subject, text) - msg.send(mlist=None) + msg.send(mlist=mlist) return token def confirm(self, token): diff --git a/src/mailman/bin/master.py b/src/mailman/bin/master.py index 5ce003690..a6091e834 100644 --- a/src/mailman/bin/master.py +++ b/src/mailman/bin/master.py @@ -194,14 +194,15 @@ def acquire_lock(force): if status == WatcherState.conflict: # Hostname matches and process exists. message = _("""\ -The master queue runner lock could not be acquired because it appears as -though another master is already running.""") +The master queue runner lock could not be acquired because it +appears as though another master is already running.""") elif status == WatcherState.stale_lock: # Hostname matches but the process does not exist. program = sys.argv[0] message = _("""\ -The master queue runner lock could not be acquired. It appears as though -there is a stale master lock. Try re-running $program with the -s flag.""") +The master queue runner lock could not be acquired. It appears +as though there is a stale master lock. Try re-running $program +with the -s flag.""") else: # Hostname doesn't even match. assert status == WatcherState.host_mismatch, ( @@ -209,9 +210,10 @@ there is a stale master lock. Try re-running $program with the -s flag.""") # pylint: disable-msg=W0612 hostname, pid, tempfile = get_lock_data() message = _("""\ -The master qrunner lock could not be acquired, because it appears as if some -process on some other host may have acquired it. We can't test for stale -locks across host boundaries, so you'll have to clean this up manually. +The master qrunner lock could not be acquired, because it appears +as if some process on some other host may have acquired it. We +can't test for stale locks across host boundaries, so you'll have +to clean this up manually. Lock file: $config.LOCK_FILE Lock host: $hostname diff --git a/src/mailman/chains/hold.py b/src/mailman/chains/hold.py index 32e2ce0b3..2726535d1 100644 --- a/src/mailman/chains/hold.py +++ b/src/mailman/chains/hold.py @@ -41,6 +41,7 @@ from mailman.config import config from mailman.core.i18n import _ from mailman.email.message import UserNotification from mailman.interfaces.autorespond import IAutoResponseSet, Response +from mailman.interfaces.languages import ILanguageManager from mailman.interfaces.pending import IPendable, IPendings from mailman.interfaces.usermanager import IUserManager @@ -189,8 +190,9 @@ class HoldChain(TerminalChainBase): text = maketext('postheld.txt', substitutions, lang=send_language_code, mlist=mlist) adminaddr = mlist.bounces_address - nmsg = UserNotification(msg.sender, adminaddr, subject, text, - config.languages[send_language_code]) + nmsg = UserNotification( + msg.sender, adminaddr, subject, text, + getUtility(ILanguageManager)[send_language_code]) nmsg.send(mlist) # Now the message for the list moderators. This one should appear to # come from <list>-owner since we really don't need to do bounce diff --git a/src/mailman/commands/cli_control.py b/src/mailman/commands/cli_control.py index e2c450b71..f484b196c 100644 --- a/src/mailman/commands/cli_control.py +++ b/src/mailman/commands/cli_control.py @@ -30,6 +30,7 @@ __all__ = [ import os import sys +import errno import signal import logging @@ -137,10 +138,10 @@ def kill_watcher(sig): try: os.kill(pid, sig) except OSError as error: - if e.errno != errno.ESRCH: + if error.errno != errno.ESRCH: raise print >> sys.stderr, _('No child with pid: $pid') - print >> sys.stderr, e + print >> sys.stderr, error print >> sys.stderr, _('Stale pid file removed.') os.unlink(config.PIDFILE) diff --git a/src/mailman/commands/cli_lists.py b/src/mailman/commands/cli_lists.py index d3833c2b0..93749c45a 100644 --- a/src/mailman/commands/cli_lists.py +++ b/src/mailman/commands/cli_lists.py @@ -40,6 +40,7 @@ from mailman.email.message import UserNotification from mailman.interfaces.command import ICLISubCommand from mailman.interfaces.domain import ( BadDomainSpecificationError, IDomainManager) +from mailman.interfaces.languages import ILanguageManager from mailman.interfaces.listmanager import IListManager, ListAlreadyExistsError @@ -174,7 +175,7 @@ class Create: if args.language is not None else system_preferences.preferred_language.code) # Make sure that the selected language code is known. - if language_code not in config.languages.codes: + if language_code not in getUtility(ILanguageManager).codes: self.parser.error(_('Invalid language code: $language_code')) return assert len(args.listname) == 1, ( @@ -199,7 +200,7 @@ class Create: # Find the language associated with the code, then set the mailing # list's preferred language to that. The changes then must be # committed to the database. - mlist.preferred_language = config.languages[language_code] + mlist.preferred_language = getUtility(ILanguageManager)[language_code] config.db.commit() # Do the notification. if not args.quiet: diff --git a/src/mailman/commands/docs/create.txt b/src/mailman/commands/docs/create.txt index 9c2331418..7c7b43805 100644 --- a/src/mailman/commands/docs/create.txt +++ b/src/mailman/commands/docs/create.txt @@ -116,7 +116,8 @@ The language must be known to Mailman. >>> command.process(args) Invalid language code: ee - >>> config.languages.add('ee', 'iso-8859-1', 'Freedonian') + >>> from mailman.interfaces.languages import ILanguageManager + >>> getUtility(ILanguageManager).add('ee', 'iso-8859-1', 'Freedonian') >>> args.quiet = False >>> args.listname = ['test3@example.com'] diff --git a/src/mailman/config/config.py b/src/mailman/config/config.py index c64eb3ef5..11b2d78b6 100644 --- a/src/mailman/config/config.py +++ b/src/mailman/config/config.py @@ -32,11 +32,12 @@ import logging from lazr.config import ConfigSchema, as_boolean from pkg_resources import resource_stream +from zope.component import getUtility from zope.interface import Interface, implements from mailman import version from mailman.core import errors -from mailman.languages.manager import LanguageManager +from mailman.interfaces.languages import ILanguageManager from mailman.styles.manager import StyleManager from mailman.utilities.filesystem import makedirs from mailman.utilities.modules import call_name @@ -58,7 +59,6 @@ class Configuration: def __init__(self): self.switchboards = {} - self.languages = LanguageManager() self.style_manager = StyleManager() self.QFILE_SCHEMA_VERSION = version.QFILE_SCHEMA_VERSION self._config = None @@ -73,7 +73,7 @@ class Configuration: def _clear(self): """Clear the cached configuration variables.""" self.switchboards.clear() - self.languages = LanguageManager() + getUtility(ILanguageManager).clear() def __getattr__(self, name): """Delegate to the configuration object.""" @@ -143,13 +143,16 @@ class Configuration: Switchboard.initialize() # Set up all the languages. languages = self._config.getByCategory('language', []) + language_manager = getUtility(ILanguageManager) for language in languages: if language.enabled: code = language.name.split('.')[1] - self.languages.add( + language_manager.add( code, language.charset, language.description) # The default language must always be available. - assert self._config.mailman.default_language in self.languages + assert self._config.mailman.default_language in language_manager, ( + 'System default language code not defined: %s' % + self._config.mailman.default_language) self.ensure_directories_exist() self.style_manager.populate() # Set the default system language. diff --git a/src/mailman/config/configure.zcml b/src/mailman/config/configure.zcml index 807698f16..378feebf9 100644 --- a/src/mailman/config/configure.zcml +++ b/src/mailman/config/configure.zcml @@ -28,6 +28,11 @@ /> <utility + factory="mailman.languages.manager.LanguageManager" + provides="mailman.interfaces.languages.ILanguageManager" + /> + + <utility factory="mailman.model.listmanager.ListManager" provides="mailman.interfaces.listmanager.IListManager" /> diff --git a/src/mailman/core/constants.py b/src/mailman/core/constants.py index 1701c93f7..5eac8f0d6 100644 --- a/src/mailman/core/constants.py +++ b/src/mailman/core/constants.py @@ -25,9 +25,11 @@ __all__ = [ ] +from zope.component import getUtility from zope.interface import implements from mailman.config import config +from mailman.interfaces.languages import ILanguageManager from mailman.interfaces.member import DeliveryMode, DeliveryStatus from mailman.interfaces.preferences import IPreferences @@ -52,7 +54,7 @@ class SystemDefaultPreferences: @property def preferred_language(self): """Return the system preferred language.""" - return config.languages['en'] + return getUtility(ILanguageManager)[config.mailman.default_language] diff --git a/src/mailman/core/initialize.py b/src/mailman/core/initialize.py index 707bb3f66..5da2209fd 100644 --- a/src/mailman/core/initialize.py +++ b/src/mailman/core/initialize.py @@ -58,6 +58,7 @@ from mailman.utilities.modules import call_name def initialize_1(config_path=None, propagate_logs=None): """First initialization step. + * Zope component architecture * The configuration system * Run-time directories * The logging subsystem @@ -68,6 +69,8 @@ def initialize_1(config_path=None, propagate_logs=None): :param propagate_logs: Should the log output propagate to stderr? :type propagate_logs: boolean or None """ + zcml = resource_string('mailman.config', 'configure.zcml') + xmlconfig.string(zcml) # By default, set the umask so that only owner and group can read and # write our files. Specifically we must have g+rw and we probably want # o-rwx although I think in most cases it doesn't hurt if other can read @@ -120,11 +123,8 @@ def initialize_2(debug=False): def initialize_3(): """Third initialization step. - * Zope component architecture * Post-hook """ - zcml = resource_string('mailman.config', 'configure.zcml') - xmlconfig.string(zcml) # Run the post-hook if there is one. config = mailman.config.config if config.mailman.post_hook: diff --git a/src/mailman/docs/languages.txt b/src/mailman/docs/languages.txt index 77b51cbeb..a724a0510 100644 --- a/src/mailman/docs/languages.txt +++ b/src/mailman/docs/languages.txt @@ -1,3 +1,4 @@ +========= Languages ========= @@ -6,12 +7,16 @@ languages at run time, as well as enabling those languages for use in a running Mailman instance. >>> from mailman.interfaces.languages import ILanguageManager - >>> from mailman.languages.manager import LanguageManager + >>> from zope.component import getUtility >>> from zope.interface.verify import verifyObject - >>> mgr = LanguageManager() + + >>> mgr = getUtility(ILanguageManager) >>> verifyObject(ILanguageManager, mgr) True + # The language manager component comes pre-populated; clear it out. + >>> mgr.clear() + A language manager keeps track of the languages it knows about. >>> list(mgr.codes) @@ -21,7 +26,7 @@ A language manager keeps track of the languages it knows about. Adding languages ----------------- +================ Adding a new language requires three pieces of information, the 2-character language code, the English description of the language, and the character set @@ -43,7 +48,7 @@ And you can get information for all known languages. Other iterations ----------------- +================ You can iterate over all the known language codes. @@ -83,3 +88,23 @@ You can get a particular language by its code. None >>> print mgr.get('xx', 'missing') missing + + +Clearing the known languages +============================ + +The language manager can forget about all the language codes it knows about. + + >>> 'en' in mgr + True + + # Make a copy of the language manager's dictionary, so we can restore it + # after the test. Currently the test layer doesn't manage this. + >>> saved = mgr._languages.copy() + + >>> mgr.clear() + >>> 'en' in mgr + False + + # Restore the data. + >>> mgr._languages = saved diff --git a/src/mailman/docs/message.txt b/src/mailman/docs/message.txt index 84b0eaf3e..41607ff44 100644 --- a/src/mailman/docs/message.txt +++ b/src/mailman/docs/message.txt @@ -1,3 +1,4 @@ +======== Messages ======== @@ -6,7 +7,7 @@ email.message.Message class, but providing additional useful methods. User notifications ------------------- +================== When Mailman needs to send a message to a user, it creates a UserNotification instance, and then calls the .send() method on this object. This method diff --git a/src/mailman/docs/users.txt b/src/mailman/docs/users.txt index 73e4f3b77..bb0301772 100644 --- a/src/mailman/docs/users.txt +++ b/src/mailman/docs/users.txt @@ -135,7 +135,8 @@ Users have preferences, but these preferences have no default settings. Some of these preferences are booleans and they can be set to True or False. - >>> config.languages.add('it', 'iso-8859-1', 'Italian') + >>> from mailman.interfaces.languages import ILanguageManager + >>> getUtility(ILanguageManager).add('it', 'iso-8859-1', 'Italian') >>> from mailman.core.constants import DeliveryMode >>> prefs = user_1.preferences diff --git a/src/mailman/interfaces/languages.py b/src/mailman/interfaces/languages.py index 7be5fca7b..18e93ea81 100644 --- a/src/mailman/interfaces/languages.py +++ b/src/mailman/interfaces/languages.py @@ -93,3 +93,6 @@ class ILanguageManager(Interface): :return: A flag indicating whether the language code is known or not. :rtype: bool """ + + def clear(): + """Remove all language code mappings.""" diff --git a/src/mailman/languages/manager.py b/src/mailman/languages/manager.py index 96c00d09f..03978da4e 100644 --- a/src/mailman/languages/manager.py +++ b/src/mailman/languages/manager.py @@ -68,3 +68,7 @@ class LanguageManager: def __contains__(self, code): """See `ILanguageManager`.""" return code in self._languages + + def clear(self): + """See `ILanguageManager`.""" + self._languages.clear() diff --git a/src/mailman/model/domain.py b/src/mailman/model/domain.py index 06aef62cf..a30c9c581 100644 --- a/src/mailman/model/domain.py +++ b/src/mailman/model/domain.py @@ -106,10 +106,6 @@ class DomainManager: implements(IDomainManager) - def __init__(self): - """Create a domain manager.""" - self.store = config.db.store - def add(self, email_host, description=None, base_url=None, @@ -121,17 +117,17 @@ class DomainManager: raise BadDomainSpecificationError( 'Duplicate email host: %s' % email_host) domain = Domain(email_host, description, base_url, contact_address) - self.store.add(domain) + config.db.store.add(domain) return domain def remove(self, email_host): domain = self[email_host] - self.store.remove(domain) + config.db.store.remove(domain) return domain def get(self, email_host, default=None): """See `IDomainManager`.""" - domains = self.store.find(Domain, email_host=email_host) + domains = config.db.store.find(Domain, email_host=email_host) if domains.count() < 1: return default assert domains.count() == 1, ( @@ -147,13 +143,13 @@ class DomainManager: return domain def __len__(self): - return self.store.find(Domain).count() + return config.db.store.find(Domain).count() def __iter__(self): """See `IDomainManager`.""" - for domain in self.store.find(Domain): + for domain in config.db.store.find(Domain): yield domain def __contains__(self, email_host): """See `IDomainManager`.""" - return self.store.find(Domain, email_host=email_host).count() > 0 + return config.db.store.find(Domain, email_host=email_host).count() > 0 diff --git a/src/mailman/model/mailinglist.py b/src/mailman/model/mailinglist.py index 77da90b09..25880bebc 100644 --- a/src/mailman/model/mailinglist.py +++ b/src/mailman/model/mailinglist.py @@ -39,6 +39,7 @@ from mailman.config import config from mailman.database.model import Model from mailman.database.types import Enum from mailman.interfaces.domain import IDomainManager +from mailman.interfaces.languages import ILanguageManager from mailman.interfaces.mailinglist import ( IAcceptableAlias, IAcceptableAliasSet, IMailingList, Personalization) from mailman.interfaces.mime import FilterType @@ -288,7 +289,7 @@ class MailingList(Model): @property def preferred_language(self): """See `IMailingList`.""" - return config.languages[self._preferred_language] + return getUtility(ILanguageManager)[self._preferred_language] @preferred_language.setter def preferred_language(self, language): diff --git a/src/mailman/model/preferences.py b/src/mailman/model/preferences.py index 31f9ce280..550568e96 100644 --- a/src/mailman/model/preferences.py +++ b/src/mailman/model/preferences.py @@ -26,11 +26,13 @@ __all__ = [ from storm.locals import * +from zope.component import getUtility from zope.interface import implements from mailman.config import config from mailman.database.model import Model from mailman.database.types import Enum +from mailman.interfaces.languages import ILanguageManager from mailman.interfaces.preferences import IPreferences @@ -54,7 +56,7 @@ class Preferences(Model): def preferred_language(self): if self._preferred_language is None: return None - return config.languages[self._preferred_language] + return getUtility(ILanguageManager)[self._preferred_language] @preferred_language.setter def preferred_language(self, language): diff --git a/src/mailman/pipeline/acknowledge.py b/src/mailman/pipeline/acknowledge.py index 2d0efd808..5ef7f18d5 100644 --- a/src/mailman/pipeline/acknowledge.py +++ b/src/mailman/pipeline/acknowledge.py @@ -28,6 +28,7 @@ __all__ = [ ] +from zope.component import getUtility from zope.interface import implements from mailman import Utils @@ -35,6 +36,7 @@ from mailman.config import config from mailman.core.i18n import _ from mailman.email.message import Message, UserNotification from mailman.interfaces.handler import IHandler +from mailman.interfaces.languages import ILanguageManager @@ -61,10 +63,11 @@ class Acknowledge: original_subject = msgdata.get( 'origsubj', msg.get('subject', _('(no subject)'))) # Get the user's preferred language. - language = (config.languages[msgdata['lang']] + language_manager = getUtility(ILanguageManager) + language = (language_manager[msgdata['lang']] if 'lang' in msgdata else member.preferred_language) - charset = config.languages[language.code].charset + charset = language_manager[language.code].charset # Now get the acknowledgement template. realname = mlist.real_name text = Utils.maketext( diff --git a/src/mailman/queue/__init__.py b/src/mailman/queue/__init__.py index a6d930c9d..4d9053ac3 100644 --- a/src/mailman/queue/__init__.py +++ b/src/mailman/queue/__init__.py @@ -53,6 +53,7 @@ from zope.interface import implements from mailman.config import config from mailman.core.i18n import _ from mailman.email.message import Message +from mailman.interfaces.languages import ILanguageManager from mailman.interfaces.listmanager import IListManager from mailman.interfaces.runner import IRunner from mailman.interfaces.switchboard import ISwitchboard @@ -421,11 +422,16 @@ class Runner: # them out of our sight. # # Find out which mailing list this message is destined for. - listname = unicode(msgdata.get('listname')) - mlist = getUtility(IListManager).get(listname) + missing = object() + listname = msgdata.get('listname', missing) + mlist = (None + if listname is missing + else getUtility(IListManager).get(unicode(listname))) if mlist is None: - elog.error('Dequeuing message destined for missing list: %s', - listname) + elog.error( + '%s runner "%s" shunting message for missing list: %s', + msg['message-id'], self.name, + ('n/a' if listname is missing else listname)) config.switchboards['shunt'].enqueue(msg, msgdata) return # Now process this message. We also want to set up the language @@ -434,7 +440,10 @@ class Runner: # will be the list's preferred language. However, we must take # special care to reset the defaults, otherwise subsequent messages # may be translated incorrectly. - if msg.sender: + if mlist is None: + language_manager = getUtility(ILanguageManager) + language = language_manager[config.mailman.default_language] + elif msg.sender: member = mlist.members.get_member(msg.sender) language = (member.preferred_language if member is not None diff --git a/src/mailman/queue/command.py b/src/mailman/queue/command.py index d5ce708b1..401730e73 100644 --- a/src/mailman/queue/command.py +++ b/src/mailman/queue/command.py @@ -32,15 +32,17 @@ import re import logging from StringIO import StringIO -from email.Errors import HeaderParseError -from email.Header import decode_header, make_header -from email.Iterators import typed_subpart_iterator +from email.errors import HeaderParseError +from email.header import decode_header, make_header +from email.iterators import typed_subpart_iterator +from zope.component import getUtility from zope.interface import implements from mailman.config import config from mailman.core.i18n import _ from mailman.email.message import Message, UserNotification from mailman.interfaces.command import ContinueProcessing, IEmailResults +from mailman.interfaces.languages import ILanguageManager from mailman.queue import Runner @@ -198,7 +200,7 @@ class CommandRunner(Runner): # Send a reply, but do not attach the original message. This is a # compromise because the original message is often helpful in tracking # down problems, but it's also a vector for backscatter spam. - language = config.languages[msgdata['lang']] + language = getUtility(ILanguageManager)[msgdata['lang']] reply = UserNotification(msg.sender, mlist.bounces_address, _('The results of your email commands'), lang=language) |
