1 # Copyright (C) 2006-2008 by the Free Software Foundation, Inc.
3 # This file is part of GNU Mailman.
5 # GNU Mailman is free software: you can redistribute it and/or modify it under
6 # the terms of the GNU General Public License as published by the Free
7 # Software Foundation, either version 3 of the License, or (at your option)
10 # GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
11 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 # You should have received a copy of the GNU General Public License along with
16 # GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
18 """Configuration file loading and management."""
31 from StringIO
import StringIO
32 from lazr
.config
import ConfigSchema
, as_boolean
33 from pkg_resources
import resource_string
35 from mailman
import Defaults
36 from mailman
import version
37 from mailman
.core
import errors
38 from mailman
.domain
import Domain
39 from mailman
.languages
import LanguageManager
46 class Configuration(object):
47 """The core global configuration object."""
50 self
.domains
= {} # email host -> IDomain
52 self
.qrunner_shortcuts
= {}
53 self
.switchboards
= {}
54 self
.languages
= LanguageManager()
55 self
.QFILE_SCHEMA_VERSION
= version
.QFILE_SCHEMA_VERSION
57 # Create various registries.
66 """Clear the cached configuration variables."""
67 # First, stop all registered qrunners.
68 for runner
in self
.qrunners
.values():
71 self
.switchboards
.clear()
73 self
.qrunner_shortcuts
.clear()
74 self
.languages
= LanguageManager()
76 def __getattr__(self
, name
):
77 """Delegate to the configuration object."""
78 return getattr(self
._config
, name
)
80 def load(self
, filename
=None):
81 """Load the configuration from the schema and config files."""
82 schema_string
= resource_string('mailman.config', 'schema.cfg')
83 schema
= ConfigSchema('schema.cfg', StringIO(schema_string
))
84 # If a configuration file was given, load it now too. First, load the
85 # absolute minimum default configuration, then if a configuration
86 # filename was given by the user, push it.
87 config_string
= resource_string('mailman.config', 'mailman.cfg')
88 self
._config
= schema
.loadFile(StringIO(config_string
), 'mailman.cfg')
89 if filename
is not None:
90 with
open(filename
) as user_config
:
91 self
._config
.push(user_config
.read())
94 def push(self
, config_name
, config_string
):
95 """Push a new configuration onto the stack."""
97 self
._config
.push(config_name
, config_string
)
100 def pop(self
, config_name
):
101 """Pop a configuration from the stack."""
103 self
._config
.pop(config_name
)
106 def _post_process(self
):
107 """Perform post-processing after loading the configuration files."""
108 # Set up the domains.
109 domains
= self
._config
.getByCategory('domain', [])
110 for section
in domains
:
111 domain
= Domain(section
.email_host
, section
.base_url
,
112 section
.description
, section
.contact_address
)
113 if domain
.email_host
in self
.domains
:
114 raise errors
.BadDomainSpecificationError(
115 'Duplicate email host: %s' % domain
.email_host
)
116 # Make sure there's only one mapping for the url_host
117 if domain
.url_host
in self
.domains
.values():
118 raise errors
.BadDomainSpecificationError(
119 'Duplicate url host: %s' % domain
.url_host
)
120 # We'll do the reverse mappings on-demand. There shouldn't be too
121 # many virtual hosts that it will really matter that much.
122 self
.domains
[domain
.email_host
] = domain
123 # Set up directories.
124 self
.BIN_DIR
= os
.path
.abspath(os
.path
.dirname(sys
.argv
[0]))
125 self
.VAR_DIR
= var_dir
= self
._config
.mailman
.var_dir
126 # Now that we've loaded all the configuration files we're going to
127 # load, set up some useful directories.
129 self
.LIST_DATA_DIR
= join(var_dir
, 'lists')
130 self
.LOG_DIR
= join(var_dir
, 'logs')
131 self
.LOCK_DIR
= lockdir
= join(var_dir
, 'locks')
132 self
.DATA_DIR
= datadir
= join(var_dir
, 'data')
133 self
.ETC_DIR
= etcdir
= join(var_dir
, 'etc')
134 self
.SPAM_DIR
= join(var_dir
, 'spam')
135 self
.EXT_DIR
= join(var_dir
, 'ext')
136 self
.QUEUE_DIR
= join(var_dir
, 'qfiles')
137 self
.MESSAGES_DIR
= join(var_dir
, 'messages')
138 self
.PUBLIC_ARCHIVE_FILE_DIR
= join(var_dir
, 'archives', 'public')
139 self
.PRIVATE_ARCHIVE_FILE_DIR
= join(var_dir
, 'archives', 'private')
141 self
.PIDFILE
= join(datadir
, 'master-qrunner.pid')
142 self
.SITE_PW_FILE
= join(datadir
, 'adm.pw')
143 self
.LISTCREATOR_PW_FILE
= join(datadir
, 'creator.pw')
144 self
.CONFIG_FILE
= join(etcdir
, 'mailman.cfg')
145 self
.LOCK_FILE
= join(lockdir
, 'master-qrunner')
146 # Set up the switchboards.
147 from mailman
.queue
import Switchboard
148 Switchboard
.initialize()
149 # Set up all the languages.
150 languages
= self
._config
.getByCategory('language', [])
151 for language
in languages
:
152 code
= language
.name
.split('.')[1]
153 self
.languages
.add_language(code
, language
.description
,
154 language
.charset
, language
.enabled
)
155 # Always enable the server default language, which must be defined.
156 self
.languages
.enable_language(self
._config
.mailman
.default_language
)
159 def logger_configs(self
):
160 """Return all log config sections."""
161 return self
._config
.getByCategory('logging', [])
165 """Return a substitution dictionary of all path variables."""
166 return dict((k
, self
.__dict
__[k
])
167 for k
in self
.__dict
__
168 if k
.endswith('_DIR'))
170 def ensure_directories_exist(self
):
171 """Create all path directories if they do not exist."""
172 for variable
, directory
in self
.paths
.items():
174 os
.makedirs(directory
, 02775)
176 if e
.errno
<> errno
.EEXIST
:
180 def qrunner_configs(self
):
181 for section
in self
._config
.getByCategory('qrunner', []):
185 def header_matches(self
):
186 """Iterate over all spam matching headers.
188 Values are 3-tuples of (header, pattern, chain)
190 matches
= self
._config
.getByCategory('spam.headers', [])
191 for match
in matches
:
192 yield (matches
.header
, matches
.pattern
, matches
.chain
)