1 # Copyright (C) 2009 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 """The 'lists' subcommand."""
20 from __future__
import absolute_import
, unicode_literals
30 from zope
.component
import getUtility
31 from zope
.interface
import implements
33 from mailman
.Utils
import maketext
34 from mailman
.app
.lifecycle
import create_list
, remove_list
35 from mailman
.config
import config
36 from mailman
.core
.constants
import system_preferences
37 from mailman
.core
.errors
import InvalidEmailAddress
38 from mailman
.email
.message
import UserNotification
39 from mailman
.i18n
import _
, using_language
40 from mailman
.interfaces
.command
import ICLISubCommand
41 from mailman
.interfaces
.domain
import (
42 BadDomainSpecificationError
, IDomainManager
)
43 from mailman
.interfaces
.listmanager
import IListManager
, ListAlreadyExistsError
48 """List all mailing lists"""
50 implements(ICLISubCommand
)
54 def add(self
, parser
, command_parser
):
55 """See `ICLISubCommand`."""
56 command_parser
.add_argument(
58 default
=False, action
='store_true',
60 'List only those mailing lists that are publicly advertised'))
61 command_parser
.add_argument(
63 default
=False, action
='store_true',
64 help=_('Show only the list name, with no description'))
65 command_parser
.add_argument(
67 action
='append', help=_("""\
68 List only those mailing lists hosted on the given domain, which
69 must be the email host name. Multiple -d options may be given.
71 command_parser
.add_argument(
73 default
=False, action
='store_true',
75 'Show the full mailing list name (i.e. the posting address'))
77 def process(self
, args
):
78 """See `ICLISubCommand`."""
80 list_manager
= getUtility(IListManager
)
81 # Gather the matching mailing lists.
82 for fqdn_name
in sorted(list_manager
.names
):
83 mlist
= list_manager
.get(fqdn_name
)
84 if args
.advertised
and not mlist
.advertised
:
86 domains
= getattr(args
, 'domains', None)
87 if domains
and mlist
.host_name
not in domains
:
89 mailing_lists
.append(mlist
)
90 # Maybe no mailing lists matched.
91 if len(mailing_lists
) == 0:
93 print _('No matching mailing lists found')
96 count
= len(mailing_lists
)
97 print _('$count matching mailing lists found:')
98 # Calculate the longest mailing list name.
100 max(mlist
.fqdn_listname
for mlist
in mailing_lists
)
102 max(mlist
.real_name
for mlist
in mailing_lists
))
104 for mlist
in mailing_lists
:
105 name
= (mlist
.fqdn_listname
if args
.full
else mlist
.real_name
)
109 description
= (mlist
.description
110 if mlist
.description
is not None
111 else _('[no description available]'))
112 print '{0:{2}} - {1:{3}}'.format(
113 name
, description
, longest
, 77 - longest
)
118 """Create a mailing list"""
120 implements(ICLISubCommand
)
124 def add(self
, parser
, command_parser
):
125 """See `ICLISubCommand`."""
127 command_parser
.add_argument(
129 type='unicode', metavar
='CODE', help=_("""\
130 Set the list's preferred language to CODE, which must be a
131 registered two letter language code."""))
132 command_parser
.add_argument(
134 type='unicode', action
='append', default
=[],
135 dest
='owners', metavar
='OWNER', help=_("""\
136 Specify a listowner email address. If the address is not
137 currently registered with Mailman, the address is registered and
138 linked to a user. Mailman will send a confirmation message to the
139 address, but it will also send a list creation notice to the
140 address. More than one owner can be specified."""))
141 command_parser
.add_argument(
143 default
=False, action
='store_true',
145 Notify the list owner by email that their mailing list has been
147 command_parser
.add_argument(
149 default
=False, action
='store_true',
150 help=_('Print less output.'))
151 command_parser
.add_argument(
153 default
=False, action
='store_true',
155 Register the mailing list's domain if not yet registered."""))
156 # Required positional argument.
157 command_parser
.add_argument(
158 'listname', metavar
='LISTNAME', nargs
=1,
160 The 'fully qualified list name', i.e. the posting address of the
161 mailing list. It must be a valid email address and the domain
162 must be registered with Mailman. List names are forced to lower
165 def process(self
, args
):
166 """See `ICLISubCommand`."""
167 language_code
= (args
.language
168 if args
.language
is not None
169 else system_preferences
.preferred_language
.code
)
170 # Make sure that the selected language code is known.
171 if language_code
not in config
.languages
.codes
:
172 self
.parser
.error(_('Invalid language code: $language_code'))
174 assert len(args
.listname
) == 1, (
175 'Unexpected positional arguments: %s' % args
.listname
)
176 # Check to see if the domain exists or not.
177 fqdn_listname
= args
.listname
[0]
178 listname
, at
, domain
= fqdn_listname
.partition('@')
179 domain_mgr
= IDomainManager(config
)
180 if domain_mgr
.get(domain
) is None and args
.domain
:
181 domain_mgr
.add(domain
)
183 mlist
= create_list(fqdn_listname
, args
.owners
)
184 except InvalidEmailAddress
:
185 self
.parser
.error(_('Illegal list name: $fqdn_listname'))
187 except ListAlreadyExistsError
:
188 self
.parser
.error(_('List already exists: $fqdn_listname'))
190 except BadDomainSpecificationError
, domain
:
191 self
.parser
.error(_('Undefined domain: $domain'))
193 # Find the language associated with the code, then set the mailing
194 # list's preferred language to that. The changes then must be
195 # committed to the database.
196 mlist
.preferred_language
= config
.languages
[language_code
]
198 # Do the notification.
200 print _('Created mailing list: $mlist.fqdn_listname')
203 listname
= mlist
.fqdn_listname
,
204 admin_url
= mlist
.script_url('admin'),
205 listinfo_url
= mlist
.script_url('listinfo'),
206 requestaddr
= mlist
.request_address
,
207 siteowner
= mlist
.no_reply_address
,
209 text
= maketext('newlist.txt', d
, mlist
=mlist
)
210 # Set the I18N language to the list's preferred language so the
211 # header will match the template language. Stashing and restoring
212 # the old translation context is just (healthy? :) paranoia.
213 with
using_language(mlist
.preferred_language
.code
):
214 msg
= UserNotification(
215 args
.owners
, mlist
.no_reply_address
,
216 _('Your new mailing list: $fqdn_listname'),
217 text
, mlist
.preferred_language
)
223 """Remove a mailing list"""
225 implements(ICLISubCommand
)
229 def add(self
, parser
, command_parser
):
230 """See `ICLISubCommand`."""
231 command_parser
.add_argument(
233 default
=False, action
='store_true',
235 Remove the list's archives too, or if the list has already been deleted,
236 remove any residual archives."""))
237 command_parser
.add_argument(
239 default
=False, action
='store_true',
240 help=_('Suppress status messages'))
241 # Required positional argument.
242 command_parser
.add_argument(
243 'listname', metavar
='LISTNAME', nargs
=1,
245 The 'fully qualified list name', i.e. the posting address of the
248 def process(self
, args
):
249 """See `ICLISubCommand`."""
253 assert len(args
.listname
) == 1, (
254 'Unexpected positional arguments: %s' % args
.listname
)
255 fqdn_listname
= args
.listname
[0]
256 mlist
= getUtility(IListManager
).get(fqdn_listname
)
259 log(_('No such list: $fqdn_listname; '
260 'removing residual archives.'))
262 log(_('No such list: $fqdn_listname'))
265 log(_('Removed list: $fqdn_listname'))
266 if not args
.archives
:
267 log(_('Not removing archives. Reinvoke with -a to remove them.'))
268 remove_list(fqdn_listname
, mlist
, args
.archives
)