diff options
Diffstat (limited to 'src/mailman/commands')
| -rw-r--r-- | src/mailman/commands/__init__.py | 22 | ||||
| -rw-r--r-- | src/mailman/commands/cmd_confirm.py | 98 | ||||
| -rw-r--r-- | src/mailman/commands/cmd_help.py | 93 | ||||
| -rw-r--r-- | src/mailman/commands/cmd_info.py | 50 | ||||
| -rw-r--r-- | src/mailman/commands/cmd_leave.py | 21 | ||||
| -rw-r--r-- | src/mailman/commands/cmd_lists.py | 65 | ||||
| -rw-r--r-- | src/mailman/commands/cmd_password.py | 123 | ||||
| -rw-r--r-- | src/mailman/commands/cmd_remove.py | 21 | ||||
| -rw-r--r-- | src/mailman/commands/cmd_set.py | 360 | ||||
| -rw-r--r-- | src/mailman/commands/cmd_unsubscribe.py | 88 | ||||
| -rw-r--r-- | src/mailman/commands/cmd_who.py | 152 | ||||
| -rw-r--r-- | src/mailman/commands/docs/echo.txt | 30 | ||||
| -rw-r--r-- | src/mailman/commands/docs/end.txt | 37 | ||||
| -rw-r--r-- | src/mailman/commands/docs/join.txt | 170 | ||||
| -rw-r--r-- | src/mailman/commands/echo.py | 48 | ||||
| -rw-r--r-- | src/mailman/commands/end.py | 51 | ||||
| -rw-r--r-- | src/mailman/commands/join.py | 126 |
17 files changed, 1555 insertions, 0 deletions
diff --git a/src/mailman/commands/__init__.py b/src/mailman/commands/__init__.py new file mode 100644 index 000000000..6e89bc6da --- /dev/null +++ b/src/mailman/commands/__init__.py @@ -0,0 +1,22 @@ +# Copyright (C) 2008-2009 by the Free Software Foundation, Inc. +# +# This file is part of GNU Mailman. +# +# GNU Mailman is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# GNU Mailman. If not, see <http://www.gnu.org/licenses/>. + +__all__ = [ + 'echo', + 'end', + 'join', + ] diff --git a/src/mailman/commands/cmd_confirm.py b/src/mailman/commands/cmd_confirm.py new file mode 100644 index 000000000..b5e4182bd --- /dev/null +++ b/src/mailman/commands/cmd_confirm.py @@ -0,0 +1,98 @@ +# Copyright (C) 2002-2009 by the Free Software Foundation, Inc. +# +# This file is part of GNU Mailman. +# +# GNU Mailman is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# GNU Mailman. If not, see <http://www.gnu.org/licenses/>. + +""" + confirm <confirmation-string> + Confirm an action. The confirmation-string is required and should be + supplied by a mailback confirmation notice. +""" + +from mailman import Errors +from mailman import Pending +from mailman.config import config +from mailman.i18n import _ + +STOP = 1 + + + +def gethelp(mlist): + return _(__doc__) + + + +def process(res, args): + mlist = res.mlist + if len(args) <> 1: + res.results.append(_('Usage:')) + res.results.append(gethelp(mlist)) + return STOP + cookie = args[0] + try: + results = mlist.ProcessConfirmation(cookie, res.msg) + except Errors.MMBadConfirmation, e: + # Express in approximate days + days = int(config.PENDING_REQUEST_LIFE / config.days(1) + 0.5) + res.results.append(_("""\ +Invalid confirmation string. Note that confirmation strings expire +approximately %(days)s days after the initial subscription request. If your +confirmation has expired, please try to re-submit your original request or +message.""")) + except Errors.MMNeedApproval: + res.results.append(_("""\ +Your request has been forwarded to the list moderator for approval.""")) + except Errors.MMAlreadyAMember: + # Some other subscription request for this address has + # already succeeded. + res.results.append(_('You are already subscribed.')) + except Errors.NotAMemberError: + # They've already been unsubscribed + res.results.append(_("""\ +You are not currently a member. Have you already unsubscribed or changed +your email address?""")) + except Errors.MembershipIsBanned: + owneraddr = mlist.GetOwnerEmail() + res.results.append(_("""\ +You are currently banned from subscribing to this list. If you think this +restriction is erroneous, please contact the list owners at +%(owneraddr)s.""")) + except Errors.HostileSubscriptionError: + res.results.append(_("""\ +You were not invited to this mailing list. The invitation has been discarded, +and both list administrators have been alerted.""")) + except Errors.MMBadPasswordError: + res.results.append(_("""\ +Bad approval password given. Held message is still being held.""")) + else: + if ((results[0] == Pending.SUBSCRIPTION and mlist.send_welcome_msg) + or + (results[0] == Pending.UNSUBSCRIPTION and mlist.send_goodbye_msg)): + # We don't also need to send a confirmation succeeded message + res.respond = 0 + else: + res.results.append(_('Confirmation succeeded')) + # Consume any other confirmation strings with the same cookie so + # the user doesn't get a misleading "unprocessed" message. + match = 'confirm ' + cookie + unprocessed = [] + for line in res.commands: + if line.lstrip() == match: + continue + unprocessed.append(line) + res.commands = unprocessed + # Process just one confirmation string per message + return STOP diff --git a/src/mailman/commands/cmd_help.py b/src/mailman/commands/cmd_help.py new file mode 100644 index 000000000..eeee33ca7 --- /dev/null +++ b/src/mailman/commands/cmd_help.py @@ -0,0 +1,93 @@ +# Copyright (C) 2002-2009 by the Free Software Foundation, Inc. +# +# This file is part of GNU Mailman. +# +# GNU Mailman is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# GNU Mailman. If not, see <http://www.gnu.org/licenses/>. + +""" + help + Print this help message. +""" + +import os +import sys + +from mailman import Utils +from mailman.config import config +from mailman.i18n import _ + +EMPTYSTRING = '' + + + +def gethelp(mlist): + return _(__doc__) + + + +def process(res, args): + # Get the help text introduction + mlist = res.mlist + # Since this message is personalized, add some useful information if the + # address requesting help is a member of the list. + msg = res.msg + for sender in msg.get_senders(): + if mlist.isMember(sender): + memberurl = mlist.GetOptionsURL(sender, absolute=1) + urlhelp = _( + 'You can access your personal options via the following url:') + res.results.append(urlhelp) + res.results.append(memberurl) + # Get a blank line in the output. + res.results.append('') + break + # build the specific command helps from the module docstrings + modhelps = {} + import mailman.Commands + path = os.path.dirname(os.path.abspath(mailman.Commands.__file__)) + for file in os.listdir(path): + if not file.startswith('cmd_') or not file.endswith('.py'): + continue + module = os.path.splitext(file)[0] + modname = 'mailman.Commands.' + module + try: + __import__(modname) + except ImportError: + continue + cmdname = module[4:] + help = None + if hasattr(sys.modules[modname], 'gethelp'): + help = sys.modules[modname].gethelp(mlist) + if help: + modhelps[cmdname] = help + # Now sort the command helps + helptext = [] + keys = modhelps.keys() + keys.sort() + for cmd in keys: + helptext.append(modhelps[cmd]) + commands = EMPTYSTRING.join(helptext) + # Now craft the response + helptext = Utils.maketext( + 'help.txt', + {'listname' : mlist.real_name, + 'version' : config.VERSION, + 'listinfo_url': mlist.GetScriptURL('listinfo', absolute=1), + 'requestaddr' : mlist.GetRequestEmail(), + 'adminaddr' : mlist.GetOwnerEmail(), + 'commands' : commands, + }, mlist=mlist, lang=res.msgdata['lang'], raw=1) + # Now add to the response + res.results.append('help') + res.results.append(helptext) diff --git a/src/mailman/commands/cmd_info.py b/src/mailman/commands/cmd_info.py new file mode 100644 index 000000000..3bdea178f --- /dev/null +++ b/src/mailman/commands/cmd_info.py @@ -0,0 +1,50 @@ +# Copyright (C) 2002-2009 by the Free Software Foundation, Inc. +# +# This file is part of GNU Mailman. +# +# GNU Mailman is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# GNU Mailman. If not, see <http://www.gnu.org/licenses/>. + +""" + info + Get information about this mailing list. +""" + +from mailman.i18n import _ + +STOP = 1 + + + +def gethelp(mlist): + return _(__doc__) + + + +def process(res, args): + mlist = res.mlist + if args: + res.results.append(gethelp(mlist)) + return STOP + listname = mlist.real_name + description = mlist.description or _('n/a') + postaddr = mlist.posting_address + requestaddr = mlist.request_address + owneraddr = mlist.owner_address + listurl = mlist.script_url('listinfo') + res.results.append(_('List name: %(listname)s')) + res.results.append(_('Description: %(description)s')) + res.results.append(_('Postings to: %(postaddr)s')) + res.results.append(_('List Helpbot: %(requestaddr)s')) + res.results.append(_('List Owners: %(owneraddr)s')) + res.results.append(_('More information: %(listurl)s')) diff --git a/src/mailman/commands/cmd_leave.py b/src/mailman/commands/cmd_leave.py new file mode 100644 index 000000000..5844824f7 --- /dev/null +++ b/src/mailman/commands/cmd_leave.py @@ -0,0 +1,21 @@ +# Copyright (C) 2002-2009 by the Free Software Foundation, Inc. +# +# This file is part of GNU Mailman. +# +# GNU Mailman is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# GNU Mailman. If not, see <http://www.gnu.org/licenses/>. + +"""The `leave' command is synonymous with `unsubscribe'. +""" + +from mailman.Commands.cmd_unsubscribe import process diff --git a/src/mailman/commands/cmd_lists.py b/src/mailman/commands/cmd_lists.py new file mode 100644 index 000000000..234ef46fc --- /dev/null +++ b/src/mailman/commands/cmd_lists.py @@ -0,0 +1,65 @@ +# Copyright (C) 2002-2009 by the Free Software Foundation, Inc. +# +# This file is part of GNU Mailman. +# +# GNU Mailman is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# GNU Mailman. If not, see <http://www.gnu.org/licenses/>. + +""" + lists + See a list of the public mailing lists on this GNU Mailman server. +""" + +from mailman.MailList import MailList +from mailman.config import config +from mailman.i18n import _ + + +STOP = 1 + + + +def gethelp(mlist): + return _(__doc__) + + + +def process(res, args): + mlist = res.mlist + if args: + res.results.append(_('Usage:')) + res.results.append(gethelp(mlist)) + return STOP + hostname = mlist.host_name + res.results.append(_('Public mailing lists at %(hostname)s:')) + i = 1 + for listname in sorted(config.list_manager.names): + if listname == mlist.internal_name(): + xlist = mlist + else: + xlist = MailList(listname, lock=0) + # We can mention this list if you already know about it + if not xlist.advertised and xlist is not mlist: + continue + # Skip the list if it isn't in the same virtual domain. + if xlist.host_name <> mlist.host_name: + continue + realname = xlist.real_name + description = xlist.description or _('n/a') + requestaddr = xlist.GetRequestEmail() + if i > 1: + res.results.append('') + res.results.append(_('%(i)3d. List name: %(realname)s')) + res.results.append(_(' Description: %(description)s')) + res.results.append(_(' Requests to: %(requestaddr)s')) + i += 1 diff --git a/src/mailman/commands/cmd_password.py b/src/mailman/commands/cmd_password.py new file mode 100644 index 000000000..545da0cb5 --- /dev/null +++ b/src/mailman/commands/cmd_password.py @@ -0,0 +1,123 @@ +# Copyright (C) 2002-2009 by the Free Software Foundation, Inc. +# +# This file is part of GNU Mailman. +# +# GNU Mailman is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# GNU Mailman. If not, see <http://www.gnu.org/licenses/>. + +""" + password [<oldpassword> <newpassword>] [address=<address>] + Retrieve or change your password. With no arguments, this returns + your current password. With arguments <oldpassword> and <newpassword> + you can change your password. + + If you're posting from an address other than your membership address, + specify your membership address with `address=<address>' (no brackets + around the email address, and no quotes!). Note that in this case the + response is always sent to the subscribed address. +""" + +from email.Utils import parseaddr + +from mailman.config import config +from mailman.i18n import _ + +STOP = 1 + + + +def gethelp(mlist): + return _(__doc__) + + + +def process(res, args): + mlist = res.mlist + address = None + if not args: + # They just want to get their existing password + realname, address = parseaddr(res.msg['from']) + if mlist.isMember(address): + password = mlist.getMemberPassword(address) + res.results.append(_('Your password is: %(password)s')) + # Prohibit multiple password retrievals. + return STOP + else: + listname = mlist.real_name + res.results.append( + _('You are not a member of the %(listname)s mailing list')) + return STOP + elif len(args) == 1 and args[0].startswith('address='): + # They want their password, but they're posting from a different + # address. We /must/ return the password to the subscribed address. + address = args[0][8:] + res.returnaddr = address + if mlist.isMember(address): + password = mlist.getMemberPassword(address) + res.results.append(_('Your password is: %(password)s')) + # Prohibit multiple password retrievals. + return STOP + else: + listname = mlist.real_name + res.results.append( + _('You are not a member of the %(listname)s mailing list')) + return STOP + elif len(args) == 2: + # They are changing their password + oldpasswd = args[0] + newpasswd = args[1] + realname, address = parseaddr(res.msg['from']) + if mlist.isMember(address): + if mlist.Authenticate((config.AuthUser, config.AuthListAdmin), + oldpasswd, address): + mlist.setMemberPassword(address, newpasswd) + res.results.append(_('Password successfully changed.')) + else: + res.results.append(_("""\ +You did not give the correct old password, so your password has not been +changed. Use the no argument version of the password command to retrieve your +current password, then try again.""")) + res.results.append(_('\nUsage:')) + res.results.append(gethelp(mlist)) + return STOP + else: + listname = mlist.real_name + res.results.append( + _('You are not a member of the %(listname)s mailing list')) + return STOP + elif len(args) == 3 and args[2].startswith('address='): + # They want to change their password, and they're sending this from a + # different address than what they're subscribed with. Be sure the + # response goes to the subscribed address. + oldpasswd = args[0] + newpasswd = args[1] + address = args[2][8:] + res.returnaddr = address + if mlist.isMember(address): + if mlist.Authenticate((config.AuthUser, config.AuthListAdmin), + oldpasswd, address): + mlist.setMemberPassword(address, newpasswd) + res.results.append(_('Password successfully changed.')) + else: + res.results.append(_("""\ +You did not give the correct old password, so your password has not been +changed. Use the no argument version of the password command to retrieve your +current password, then try again.""")) + res.results.append(_('\nUsage:')) + res.results.append(gethelp(mlist)) + return STOP + else: + listname = mlist.real_name + res.results.append( + _('You are not a member of the %(listname)s mailing list')) + return STOP diff --git a/src/mailman/commands/cmd_remove.py b/src/mailman/commands/cmd_remove.py new file mode 100644 index 000000000..8f3ce9669 --- /dev/null +++ b/src/mailman/commands/cmd_remove.py @@ -0,0 +1,21 @@ +# Copyright (C) 2002-2009 by the Free Software Foundation, Inc. +# +# This file is part of GNU Mailman. +# +# GNU Mailman is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# GNU Mailman. If not, see <http://www.gnu.org/licenses/>. + +"""The `remove' command is synonymous with `unsubscribe'. +""" + +from mailman.Commands.cmd_unsubscribe import process diff --git a/src/mailman/commands/cmd_set.py b/src/mailman/commands/cmd_set.py new file mode 100644 index 000000000..020bc3636 --- /dev/null +++ b/src/mailman/commands/cmd_set.py @@ -0,0 +1,360 @@ +# Copyright (C) 2002-2009 by the Free Software Foundation, Inc. +# +# This file is part of GNU Mailman. +# +# GNU Mailman is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# GNU Mailman. If not, see <http://www.gnu.org/licenses/>. + +from email.Utils import parseaddr, formatdate + +from mailman import Errors +from mailman import MemberAdaptor +from mailman import i18n +from mailman.config import config + +def _(s): return s + +OVERVIEW = _(""" + set ... + Set or view your membership options. + + Use `set help' (without the quotes) to get a more detailed list of the + options you can change. + + Use `set show' (without the quotes) to view your current option + settings. +""") + +DETAILS = _(""" + set help + Show this detailed help. + + set show [address=<address>] + View your current option settings. If you're posting from an address + other than your membership address, specify your membership address + with `address=<address>' (no brackets around the email address, and no + quotes!). + + set authenticate <password> [address=<address>] + To set any of your options, you must include this command first, along + with your membership password. If you're posting from an address + other than your membership address, specify your membership address + with `address=<address>' (no brackets around the email address, and no + quotes!). + + set ack on + set ack off + When the `ack' option is turned on, you will receive an + acknowledgement message whenever you post a message to the list. + + set digest plain + set digest mime + set digest off + When the `digest' option is turned off, you will receive postings + immediately when they are posted. Use `set digest plain' if instead + you want to receive postings bundled into a plain text digest + (i.e. RFC 1153 digest). Use `set digest mime' if instead you want to + receive postings bundled together into a MIME digest. + + set delivery on + set delivery off + Turn delivery on or off. This does not unsubscribe you, but instead + tells Mailman not to deliver messages to you for now. This is useful + if you're going on vacation. Be sure to use `set delivery on' when + you return from vacation! + + set myposts on + set myposts off + Use `set myposts off' to not receive copies of messages you post to + the list. This has no effect if you're receiving digests. + + set hide on + set hide off + Use `set hide on' to conceal your email address when people request + the membership list. + + set duplicates on + set duplicates off + Use `set duplicates off' if you want Mailman to not send you messages + if your address is explicitly mentioned in the To: or Cc: fields of + the message. This can reduce the number of duplicate postings you + will receive. + + set reminders on + set reminders off + Use `set reminders off' if you want to disable the monthly password + reminder for this mailing list. +""") + +_ = i18n._ + +STOP = 1 + + + +def gethelp(mlist): + return _(OVERVIEW) + + + +class SetCommands: + def __init__(self): + self.__address = None + self.__authok = 0 + + def process(self, res, args): + if not args: + res.results.append(_(DETAILS)) + return STOP + subcmd = args.pop(0) + methname = 'set_' + subcmd + method = getattr(self, methname, None) + if method is None: + res.results.append(_('Bad set command: %(subcmd)s')) + res.results.append(_(DETAILS)) + return STOP + return method(res, args) + + def set_help(self, res, args=1): + res.results.append(_(DETAILS)) + if args: + return STOP + + def _usage(self, res): + res.results.append(_('Usage:')) + return self.set_help(res) + + def set_show(self, res, args): + mlist = res.mlist + if not args: + realname, address = parseaddr(res.msg['from']) + elif len(args) == 1 and args[0].startswith('address='): + # Send the results to the address, not the From: dude + address = args[0][8:] + res.returnaddr = address + else: + return self._usage(res) + if not mlist.isMember(address): + listname = mlist.real_name + res.results.append( + _('You are not a member of the %(listname)s mailing list')) + return STOP + res.results.append(_('Your current option settings:')) + opt = mlist.getMemberOption(address, config.AcknowledgePosts) + onoff = opt and _('on') or _('off') + res.results.append(_(' ack %(onoff)s')) + # Digests are a special ternary value + digestsp = mlist.getMemberOption(address, config.Digests) + if digestsp: + plainp = mlist.getMemberOption(address, config.DisableMime) + if plainp: + res.results.append(_(' digest plain')) + else: + res.results.append(_(' digest mime')) + else: + res.results.append(_(' digest off')) + # If their membership is disabled, let them know why + status = mlist.getDeliveryStatus(address) + how = None + if status == MemberAdaptor.ENABLED: + status = _('delivery on') + elif status == MemberAdaptor.BYUSER: + status = _('delivery off') + how = _('by you') + elif status == MemberAdaptor.BYADMIN: + status = _('delivery off') + how = _('by the admin') + elif status == MemberAdaptor.BYBOUNCE: + status = _('delivery off') + how = _('due to bounces') + else: + assert status == MemberAdaptor.UNKNOWN + status = _('delivery off') + how = _('for unknown reasons') + changetime = mlist.getDeliveryStatusChangeTime(address) + if how and changetime > 0: + date = formatdate(changetime) + res.results.append(_(' %(status)s (%(how)s on %(date)s)')) + else: + res.results.append(' ' + status) + opt = mlist.getMemberOption(address, config.DontReceiveOwnPosts) + # sense is reversed + onoff = (not opt) and _('on') or _('off') + res.results.append(_(' myposts %(onoff)s')) + opt = mlist.getMemberOption(address, config.ConcealSubscription) + onoff = opt and _('on') or _('off') + res.results.append(_(' hide %(onoff)s')) + opt = mlist.getMemberOption(address, config.DontReceiveDuplicates) + # sense is reversed + onoff = (not opt) and _('on') or _('off') + res.results.append(_(' duplicates %(onoff)s')) + opt = mlist.getMemberOption(address, config.SuppressPasswordReminder) + # sense is reversed + onoff = (not opt) and _('on') or _('off') + res.results.append(_(' reminders %(onoff)s')) + + def set_authenticate(self, res, args): + mlist = res.mlist + if len(args) == 1: + realname, address = parseaddr(res.msg['from']) + password = args[0] + elif len(args) == 2 and args[1].startswith('address='): + password = args[0] + address = args[1][8:] + else: + return self._usage(res) + # See if the password matches + if not mlist.isMember(address): + listname = mlist.real_name + res.results.append( + _('You are not a member of the %(listname)s mailing list')) + return STOP + if not mlist.Authenticate((config.AuthUser, + config.AuthListAdmin), + password, address): + res.results.append(_('You did not give the correct password')) + return STOP + self.__authok = 1 + self.__address = address + + def _status(self, res, arg): + status = arg.lower() + if status == 'on': + flag = 1 + elif status == 'off': + flag = 0 + else: + res.results.append(_('Bad argument: %(arg)s')) + self._usage(res) + return -1 + # See if we're authenticated + if not self.__authok: + res.results.append(_('Not authenticated')) + self._usage(res) + return -1 + return flag + + def set_ack(self, res, args): + mlist = res.mlist + if len(args) <> 1: + return self._usage(res) + status = self._status(res, args[0]) + if status < 0: + return STOP + mlist.setMemberOption(self.__address, config.AcknowledgePosts, status) + res.results.append(_('ack option set')) + + def set_digest(self, res, args): + mlist = res.mlist + if len(args) <> 1: + return self._usage(res) + if not self.__authok: + res.results.append(_('Not authenticated')) + self._usage(res) + return STOP + arg = args[0].lower() + if arg == 'off': + try: + mlist.setMemberOption(self.__address, config.Digests, 0) + except Errors.AlreadyReceivingRegularDeliveries: + pass + elif arg == 'plain': + try: + mlist.setMemberOption(self.__address, config.Digests, 1) + except Errors.AlreadyReceivingDigests: + pass + mlist.setMemberOption(self.__address, config.DisableMime, 1) + elif arg == 'mime': + try: + mlist.setMemberOption(self.__address, config.Digests, 1) + except Errors.AlreadyReceivingDigests: + pass + mlist.setMemberOption(self.__address, config.DisableMime, 0) + else: + res.results.append(_('Bad argument: %(arg)s')) + self._usage(res) + return STOP + res.results.append(_('digest option set')) + + def set_delivery(self, res, args): + mlist = res.mlist + if len(args) <> 1: + return self._usage(res) + status = self._status(res, args[0]) + if status < 0: + return STOP + # Delivery status is handled differently than other options. If + # status is true (set delivery on), then we enable delivery. + # Otherwise, we have to use the setDeliveryStatus() interface to + # specify that delivery was disabled by the user. + if status: + mlist.setDeliveryStatus(self.__address, MemberAdaptor.ENABLED) + res.results.append(_('delivery enabled')) + else: + mlist.setDeliveryStatus(self.__address, MemberAdaptor.BYUSER) + res.results.append(_('delivery disabled by user')) + + def set_myposts(self, res, args): + mlist = res.mlist + if len(args) <> 1: + return self._usage(res) + status = self._status(res, args[0]) + if status < 0: + return STOP + # sense is reversed + mlist.setMemberOption(self.__address, config.DontReceiveOwnPosts, + not status) + res.results.append(_('myposts option set')) + + def set_hide(self, res, args): + mlist = res.mlist + if len(args) <> 1: + return self._usage(res) + status = self._status(res, args[0]) + if status < 0: + return STOP + mlist.setMemberOption(self.__address, config.ConcealSubscription, + status) + res.results.append(_('hide option set')) + + def set_duplicates(self, res, args): + mlist = res.mlist + if len(args) <> 1: + return self._usage(res) + status = self._status(res, args[0]) + if status < 0: + return STOP + # sense is reversed + mlist.setMemberOption(self.__address, config.DontReceiveDuplicates, + not status) + res.results.append(_('duplicates option set')) + + def set_reminders(self, res, args): + mlist = res.mlist + if len(args) <> 1: + return self._usage(res) + status = self._status(res, args[0]) + if status < 0: + return STOP + # sense is reversed + mlist.setMemberOption(self.__address, config.SuppressPasswordReminder, + not status) + res.results.append(_('reminder option set')) + + + +def process(res, args): + # We need to keep some state between set commands + if not getattr(res, 'setstate', None): + res.setstate = SetCommands() + res.setstate.process(res, args) diff --git a/src/mailman/commands/cmd_unsubscribe.py b/src/mailman/commands/cmd_unsubscribe.py new file mode 100644 index 000000000..456b8089d --- /dev/null +++ b/src/mailman/commands/cmd_unsubscribe.py @@ -0,0 +1,88 @@ +# Copyright (C) 2002-2009 by the Free Software Foundation, Inc. +# +# This file is part of GNU Mailman. +# +# GNU Mailman is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# GNU Mailman. If not, see <http://www.gnu.org/licenses/>. + +""" + unsubscribe [password] [address=<address>] + Unsubscribe from the mailing list. If given, your password must match + your current password. If omitted, a confirmation email will be sent + to the unsubscribing address. If you wish to unsubscribe an address + other than the address you sent this request from, you may specify + `address=<address>' (no brackets around the email address, and no + quotes!) +""" + +from email.Utils import parseaddr + +from mailman import Errors +from mailman.i18n import _ + +STOP = 1 + + + +def gethelp(mlist): + return _(__doc__) + + + +def process(res, args): + mlist = res.mlist + password = None + address = None + argnum = 0 + for arg in args: + if arg.startswith('address='): + address = arg[8:] + elif argnum == 0: + password = arg + else: + res.results.append(_('Usage:')) + res.results.append(gethelp(mlist)) + return STOP + argnum += 1 + # Fill in empty defaults + if address is None: + realname, address = parseaddr(res.msg['from']) + if not mlist.isMember(address): + listname = mlist.real_name + res.results.append( + _('%(address)s is not a member of the %(listname)s mailing list')) + return STOP + # If we're doing admin-approved unsubs, don't worry about the password + if mlist.unsubscribe_policy: + try: + mlist.DeleteMember(address, 'mailcmd') + except Errors.MMNeedApproval: + res.results.append(_("""\ +Your unsubscription request has been forwarded to the list administrator for +approval.""")) + elif password is None: + # No password was given, so we need to do a mailback confirmation + # instead of unsubscribing them here. + cpaddr = mlist.getMemberCPAddress(address) + mlist.ConfirmUnsubscription(cpaddr) + # We don't also need to send a confirmation to this command + res.respond = 0 + else: + # No admin approval is necessary, so we can just delete them if the + # passwords match. + oldpw = mlist.getMemberPassword(address) + if oldpw <> password: + res.results.append(_('You gave the wrong password')) + return STOP + mlist.ApprovedDeleteMember(address, 'mailcmd') + res.results.append(_('Unsubscription request succeeded.')) diff --git a/src/mailman/commands/cmd_who.py b/src/mailman/commands/cmd_who.py new file mode 100644 index 000000000..6c66610b3 --- /dev/null +++ b/src/mailman/commands/cmd_who.py @@ -0,0 +1,152 @@ +# Copyright (C) 2002-2009 by the Free Software Foundation, Inc. +# +# This file is part of GNU Mailman. +# +# GNU Mailman is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# GNU Mailman. If not, see <http://www.gnu.org/licenses/>. + +from email.Utils import parseaddr + +from mailman import i18n +from mailman.config import config + +STOP = 1 + +def _(s): return s + +PUBLICHELP = _(""" + who + See the non-hidden members of this mailing list. + who password + See everyone who is on this mailing list. The password is the + list's admin or moderator password. +""") + +MEMBERSONLYHELP = _(""" + who password [address=<address>] + See the non-hidden members of this mailing list. The roster is + limited to list members only, and you must supply your membership + password to retrieve it. If you're posting from an address other + than your membership address, specify your membership address with + `address=<address>' (no brackets around the email address, and no + quotes!). If you provide the list's admin or moderator password, + hidden members will be included. +""") + +ADMINONLYHELP = _(""" + who password + See everyone who is on this mailing list. The roster is limited to + list administrators and moderators only; you must supply the list + admin or moderator password to retrieve the roster. +""") + +_ = i18n._ + + + +def gethelp(mlist): + if mlist.private_roster == 0: + return _(PUBLICHELP) + elif mlist.private_roster == 1: + return _(MEMBERSONLYHELP) + elif mlist.private_roster == 2: + return _(ADMINONLYHELP) + + +def usage(res): + res.results.append(_('Usage:')) + res.results.append(gethelp(res.mlist)) + + + +def process(res, args): + mlist = res.mlist + address = None + password = None + ok = False + full = False + if mlist.private_roster == 0: + # Public rosters + if args: + if len(args) == 1: + if mlist.Authenticate((config.AuthListModerator, + config.AuthListAdmin), + args[0]): + full = True + else: + usage(res) + return STOP + else: + usage(res) + return STOP + ok = True + elif mlist.private_roster == 1: + # List members only + if len(args) == 1: + password = args[0] + realname, address = parseaddr(res.msg['from']) + elif len(args) == 2 and args[1].startswith('address='): + password = args[0] + address = args[1][8:] + else: + usage(res) + return STOP + if mlist.isMember(address) and mlist.Authenticate( + (config.AuthUser, + config.AuthListModerator, + config.AuthListAdmin), + password, address): + # Then + ok = True + if mlist.Authenticate( + (config.AuthListModerator, + config.AuthListAdmin), + password): + # Then + ok = full = True + else: + # Admin only + if len(args) <> 1: + usage(res) + return STOP + if mlist.Authenticate((config.AuthListModerator, + config.AuthListAdmin), + args[0]): + ok = full = True + if not ok: + res.results.append( + _('You are not allowed to retrieve the list membership.')) + return STOP + # It's okay for this person to see the list membership + dmembers = mlist.getDigestMemberKeys() + rmembers = mlist.getRegularMemberKeys() + if not dmembers and not rmembers: + res.results.append(_('This list has no members.')) + return + # Convenience function + def addmembers(members): + for member in members: + if not full and mlist.getMemberOption(member, + config.ConcealSubscription): + continue + realname = mlist.getMemberName(member) + if realname: + res.results.append(' %s (%s)' % (member, realname)) + else: + res.results.append(' %s' % member) + if rmembers: + res.results.append(_('Non-digest (regular) members:')) + addmembers(rmembers) + if dmembers: + res.results.append(_('Digest members:')) + addmembers(dmembers) diff --git a/src/mailman/commands/docs/echo.txt b/src/mailman/commands/docs/echo.txt new file mode 100644 index 000000000..181cc58c8 --- /dev/null +++ b/src/mailman/commands/docs/echo.txt @@ -0,0 +1,30 @@ +The 'echo' command +================== + +The mail command 'echo' simply replies with the original command and arguments +to the sender. + + >>> command = config.commands['echo'] + >>> command.name + 'echo' + >>> command.argument_description + '[args]' + >>> command.description + u'Echo an acknowledgement. Arguments are return unchanged.' + +The original message is ignored, but the results receive the echoed command. + + >>> from mailman.app.lifecycle import create_list + >>> mlist = create_list(u'test@example.com') + + >>> from mailman.queue.command import Results + >>> results = Results() + + >>> from mailman.Message import Message + >>> print command.process(mlist, Message(), {}, ('foo', 'bar'), results) + ContinueProcessing.yes + >>> print unicode(results) + The results of your email command are provided below. + <BLANKLINE> + echo foo bar + <BLANKLINE> diff --git a/src/mailman/commands/docs/end.txt b/src/mailman/commands/docs/end.txt new file mode 100644 index 000000000..4f6af26cb --- /dev/null +++ b/src/mailman/commands/docs/end.txt @@ -0,0 +1,37 @@ +The 'end' command +================= + +The mail command processor recognized an 'end' command which tells it to stop +processing email messages. + + >>> command = config.commands['end'] + >>> command.name + 'end' + >>> command.description + u'Stop processing commands.' + +The 'end' command takes no arguments. + + >>> command.argument_description + '' + +The command itself is fairly simple; it just stops command processing, and the +message isn't even looked at. + + >>> from mailman.app.lifecycle import create_list + >>> mlist = create_list(u'test@example.com') + >>> from mailman.Message import Message + >>> print command.process(mlist, Message(), {}, (), None) + ContinueProcessing.no + +The 'stop' command is a synonym for 'end'. + + >>> command = config.commands['stop'] + >>> command.name + 'stop' + >>> command.description + u'Stop processing commands.' + >>> command.argument_description + '' + >>> print command.process(mlist, Message(), {}, (), None) + ContinueProcessing.no diff --git a/src/mailman/commands/docs/join.txt b/src/mailman/commands/docs/join.txt new file mode 100644 index 000000000..9b85e816c --- /dev/null +++ b/src/mailman/commands/docs/join.txt @@ -0,0 +1,170 @@ +The 'join' command +================== + +The mail command 'join' subscribes an email address to the mailing list. +'subscribe' is an alias for 'join'. + + >>> command = config.commands['join'] + >>> print command.name + join + >>> print command.description + Join this mailing list. You will be asked to confirm your subscription + request and you may be issued a provisional password. + <BLANKLINE> + By using the 'digest' option, you can specify whether you want digest + delivery or not. If not specified, the mailing list's default will be + used. You can also subscribe an alternative address by using the + 'address' option. For example: + <BLANKLINE> + join address=myotheraddress@example.com + <BLANKLINE> + >>> print command.argument_description + [digest=<yes|no>] [address=<address>] + + +No address to join +------------------ + + >>> from mailman.Message import Message + >>> from mailman.app.lifecycle import create_list + >>> from mailman.queue.command import Results + >>> mlist = create_list(u'alpha@example.com') + +When no address argument is given, the message's From address will be used. +If that's missing though, then an error is returned. + + >>> results = Results() + >>> print command.process(mlist, Message(), {}, (), results) + ContinueProcessing.no + >>> print unicode(results) + The results of your email command are provided below. + <BLANKLINE> + join: No valid address found to subscribe + <BLANKLINE> + +The 'subscribe' command is an alias. + + >>> subscribe = config.commands['subscribe'] + >>> print subscribe.name + subscribe + >>> results = Results() + >>> print subscribe.process(mlist, Message(), {}, (), results) + ContinueProcessing.no + >>> print unicode(results) + The results of your email command are provided below. + <BLANKLINE> + subscribe: No valid address found to subscribe + <BLANKLINE> + + +Joining the sender +------------------ + +When the message has a From field, that address will be subscribed. + + >>> msg = message_from_string("""\ + ... From: Anne Person <anne@example.com> + ... + ... """) + >>> results = Results() + >>> print command.process(mlist, msg, {}, (), results) + ContinueProcessing.yes + >>> print unicode(results) + The results of your email command are provided below. + <BLANKLINE> + Confirmation email sent to Anne Person <anne@example.com> + <BLANKLINE> + +Anne is not yet a member because she must confirm her subscription request +first. + + >>> print config.db.user_manager.get_user(u'anne@example.com') + None + +Mailman has sent her the confirmation message. + + >>> virginq = config.switchboards['virgin'] + >>> qmsg, qdata = virginq.dequeue(virginq.files[0]) + >>> print qmsg.as_string() + MIME-Version: 1.0 + ... + Subject: confirm ... + From: confirm-...@example.com + To: anne@example.com + ... + <BLANKLINE> + Email Address Registration Confirmation + <BLANKLINE> + Hello, this is the GNU Mailman server at example.com. + <BLANKLINE> + We have received a registration request for the email address + <BLANKLINE> + anne@example.com + <BLANKLINE> + Before you can start using GNU Mailman at this site, you must first + confirm that this is your email address. You can do this by replying to + this message, keeping the Subject header intact. Or you can visit this + web page + <BLANKLINE> + http://lists.example.com/confirm/... + <BLANKLINE> + If you do not wish to register this email address simply disregard this + message. If you think you are being maliciously subscribed to the list, or + have any other questions, you may contact + <BLANKLINE> + postmaster@example.com + <BLANKLINE> + +Once Anne confirms her registration, she will be made a member of the mailing +list. + + >>> token = str(qmsg['subject']).split()[1].strip() + >>> from mailman.interfaces.registrar import IRegistrar + >>> registrar = IRegistrar(config.domains['example.com']) + >>> registrar.confirm(token) + True + + >>> user = config.db.user_manager.get_user(u'anne@example.com') + >>> print user.real_name + Anne Person + >>> list(user.addresses) + [<Address: Anne Person <anne@example.com> [verified] at ...>] + +Anne is also now a member of the mailing list. + + >>> mlist.members.get_member(u'anne@example.com') + <Member: Anne Person <anne@example.com> + on alpha@example.com as MemberRole.member> + + +Joining a second list +--------------------- + + >>> mlist_2 = create_list(u'baker@example.com') + >>> msg = message_from_string("""\ + ... From: Anne Person <anne@example.com> + ... + ... """) + >>> print command.process(mlist_2, msg, {}, (), Results()) + ContinueProcessing.yes + +Anne of course, is still registered. + + >>> print config.db.user_manager.get_user(u'anne@example.com') + <User "Anne Person" at ...> + +But she is not a member of the mailing list. + + >>> print mlist_2.members.get_member(u'anne@example.com') + None + +One Anne confirms this subscription, she becomes a member of the mailing list. + + >>> qmsg, qdata = virginq.dequeue(virginq.files[0]) + >>> token = str(qmsg['subject']).split()[1].strip() + >>> registrar.confirm(token) + True + + >>> print mlist_2.members.get_member(u'anne@example.com') + <Member: Anne Person <anne@example.com> + on baker@example.com as MemberRole.member> diff --git a/src/mailman/commands/echo.py b/src/mailman/commands/echo.py new file mode 100644 index 000000000..30590acf8 --- /dev/null +++ b/src/mailman/commands/echo.py @@ -0,0 +1,48 @@ +# Copyright (C) 2002-2009 by the Free Software Foundation, Inc. +# +# This file is part of GNU Mailman. +# +# GNU Mailman is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# GNU Mailman. If not, see <http://www.gnu.org/licenses/>. + +"""The email command 'echo'.""" + +__metaclass__ = type +__all__ = [ + 'Echo', + ] + + +from zope.interface import implements + +from mailman.i18n import _ +from mailman.interfaces.command import ContinueProcessing, IEmailCommand + + +SPACE = ' ' + + + +class Echo: + """The email 'echo' command.""" + implements(IEmailCommand) + + name = 'echo' + argument_description = '[args]' + description = _( + 'Echo an acknowledgement. Arguments are return unchanged.') + + def process(self, mlist, msg, msgdata, arguments, results): + """See `IEmailCommand`.""" + print >> results, 'echo', SPACE.join(arguments) + return ContinueProcessing.yes diff --git a/src/mailman/commands/end.py b/src/mailman/commands/end.py new file mode 100644 index 000000000..a9298bc92 --- /dev/null +++ b/src/mailman/commands/end.py @@ -0,0 +1,51 @@ +# Copyright (C) 2002-2009 by the Free Software Foundation, Inc. +# +# This file is part of GNU Mailman. +# +# GNU Mailman is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# GNU Mailman. If not, see <http://www.gnu.org/licenses/>. + +"""The email commands 'end' and 'stop'.""" + +__metaclass__ = type +__all__ = [ + 'End', + 'Stop', + ] + + +from zope.interface import implements + +from mailman.i18n import _ +from mailman.interfaces.command import ContinueProcessing, IEmailCommand + + + +class End: + """The email 'end' command.""" + implements(IEmailCommand) + + name = 'end' + argument_description = '' + description = _('Stop processing commands.') + + def process(self, mlist, msg, msgdata, arguments, results): + """See `IEmailCommand`.""" + # Ignore all arguments. + return ContinueProcessing.no + + +class Stop(End): + """The email 'stop' command (an alias for 'end').""" + + name = 'stop' diff --git a/src/mailman/commands/join.py b/src/mailman/commands/join.py new file mode 100644 index 000000000..c14f3142b --- /dev/null +++ b/src/mailman/commands/join.py @@ -0,0 +1,126 @@ +# Copyright (C) 2002-2009 by the Free Software Foundation, Inc. +# +# This file is part of GNU Mailman. +# +# GNU Mailman is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# GNU Mailman. If not, see <http://www.gnu.org/licenses/>. + +"""The email commands 'join' and 'subscribe'.""" + +__metaclass__ = type +__all__ = [ + 'Join', + 'Subscribe', + ] + + +from email.utils import formataddr, parseaddr +from zope.interface import implements + +from mailman.config import config +from mailman.i18n import _ +from mailman.interfaces.command import ContinueProcessing, IEmailCommand +from mailman.interfaces.member import DeliveryMode +from mailman.interfaces.registrar import IRegistrar + + + +class Join: + """The email 'join' command.""" + implements(IEmailCommand) + + name = 'join' + argument_description = '[digest=<yes|no>] [address=<address>]' + description = _("""\ +Join this mailing list. You will be asked to confirm your subscription +request and you may be issued a provisional password. + +By using the 'digest' option, you can specify whether you want digest delivery +or not. If not specified, the mailing list's default will be used. You can +also subscribe an alternative address by using the 'address' option. For +example: + + join address=myotheraddress@example.com +""") + + def process(self, mlist, msg, msgdata, arguments, results): + """See `IEmailCommand`.""" + # Parse the arguments. + address, delivery_mode = self._parse_arguments(arguments) + if address is None: + real_name, address = parseaddr(msg['from']) + # Address could be None or the empty string. + if not address: + address = msg.get_sender() + if not address: + print >> results, _( + '$self.name: No valid address found to subscribe') + return ContinueProcessing.no + domain = config.domains[mlist.host_name] + registrar = IRegistrar(domain) + registrar.register(address, real_name, mlist) + person = formataddr((real_name, address)) + print >> results, _('Confirmation email sent to $person') + return ContinueProcessing.yes + + def _parse_arguments(self, arguments): + """Parse command arguments. + + :param arguments: The sequences of arguments as given to the + `process()` method. + :return: address, delivery_mode + """ + address = None + delivery_mode = None + for argument in arguments: + parts = argument.split('=', 1) + if parts[0].lower() == 'digest': + if digest is not None: + print >> results, self.name, \ + _('duplicate argument: $argument') + return ContinueProcessing.no + if len(parts) == 0: + # We treat just plain 'digest' as 'digest=yes'. We don't + # yet support the other types of digest delivery. + delivery_mode = DeliveryMode.mime_digests + else: + if parts[1].lower() == 'yes': + delivery_mode = DeliveryMode.mime_digests + elif parts[1].lower() == 'no': + delivery_mode = DeliveryMode.regular + else: + print >> results, self.name, \ + _('bad argument: $argument') + return ContinueProcessing.no + elif parts[0].lower() == 'address': + if address is not None: + print >> results, self.name, \ + _('duplicate argument $argument') + return ContinueProcessing.no + if len(parts) == 0: + print >> results, self.name, \ + _('missing argument value: $argument') + return ContinueProcessing.no + if len(parts) > 1: + print >> results, self.name, \ + _('too many argument values: $argument') + return ContinueProcessing.no + address = parts[1] + return address, delivery_mode + + + +class Subscribe(Join): + """The email 'subscribe' command (an alias for 'join').""" + + name = 'subscribe' |
