diff options
author | <> | 2003-01-02 05:25:50 +0000 |
---|---|---|
committer | <> | 2003-01-02 05:25:50 +0000 |
commit | b132a73f15e432eaf43310fce9196ca0c0651465 (patch) | |
tree | c15f816ba7c4de99fef510e3bd75af0890d47441 /Mailman/Commands | |
download | mailman2-b132a73f15e432eaf43310fce9196ca0c0651465.tar.gz mailman2-b132a73f15e432eaf43310fce9196ca0c0651465.tar.xz mailman2-b132a73f15e432eaf43310fce9196ca0c0651465.zip |
This commit was manufactured by cvs2svn to create branch
'Release_2_1-maint'.
Diffstat (limited to '')
-rw-r--r-- | Mailman/Commands/.cvsignore | 1 | ||||
-rw-r--r-- | Mailman/Commands/Makefile.in | 69 | ||||
-rw-r--r-- | Mailman/Commands/__init__.py | 15 | ||||
-rw-r--r-- | Mailman/Commands/cmd_confirm.py | 84 | ||||
-rw-r--r-- | Mailman/Commands/cmd_echo.py | 26 | ||||
-rw-r--r-- | Mailman/Commands/cmd_end.py | 33 | ||||
-rw-r--r-- | Mailman/Commands/cmd_help.py | 92 | ||||
-rw-r--r-- | Mailman/Commands/cmd_info.py | 49 | ||||
-rw-r--r-- | Mailman/Commands/cmd_join.py | 20 | ||||
-rw-r--r-- | Mailman/Commands/cmd_leave.py | 20 | ||||
-rw-r--r-- | Mailman/Commands/cmd_lists.py | 69 | ||||
-rw-r--r-- | Mailman/Commands/cmd_password.py | 118 | ||||
-rw-r--r-- | Mailman/Commands/cmd_remove.py | 20 | ||||
-rw-r--r-- | Mailman/Commands/cmd_set.py | 353 | ||||
-rw-r--r-- | Mailman/Commands/cmd_stop.py | 20 | ||||
-rw-r--r-- | Mailman/Commands/cmd_subscribe.py | 136 | ||||
-rw-r--r-- | Mailman/Commands/cmd_unsubscribe.py | 87 | ||||
-rw-r--r-- | Mailman/Commands/cmd_who.py | 133 |
18 files changed, 1345 insertions, 0 deletions
diff --git a/Mailman/Commands/.cvsignore b/Mailman/Commands/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/Mailman/Commands/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/Mailman/Commands/Makefile.in b/Mailman/Commands/Makefile.in new file mode 100644 index 00000000..bacd9629 --- /dev/null +++ b/Mailman/Commands/Makefile.in @@ -0,0 +1,69 @@ +# Copyright (C) 2002 by the Free Software Foundation, Inc. +# +# This program 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 2 +# of the License, or (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# NOTE: Makefile.in is converted into Makefile by the configure script +# in the parent directory. Once configure has run, you can recreate +# the Makefile by running just config.status. + +# Variables set by configure + +VPATH= @srcdir@ +srcdir= @srcdir@ +bindir= @bindir@ +prefix= @prefix@ +exec_prefix= @exec_prefix@ + +CC= @CC@ +CHMOD= @CHMOD@ +INSTALL= @INSTALL@ + +DEFS= @DEFS@ + +# Customizable but not set by configure + +OPT= @OPT@ +CFLAGS= $(OPT) $(DEFS) +PACKAGEDIR= $(prefix)/Mailman/Commands +SHELL= /bin/sh + +MODULES= *.py + +# Modes for directories and executables created by the install +# process. Default to group-writable directories but +# user-only-writable for executables. +DIRMODE= 775 +EXEMODE= 755 +FILEMODE= 644 +INSTALL_PROGRAM=$(INSTALL) -m $(EXEMODE) + + +# Rules + +all: + +install: + for f in $(MODULES); \ + do \ + $(INSTALL) -m $(FILEMODE) $(srcdir)/$$f $(PACKAGEDIR); \ + done + +finish: + +clean: + +distclean: + -rm *.pyc + -rm Makefile diff --git a/Mailman/Commands/__init__.py b/Mailman/Commands/__init__.py new file mode 100644 index 00000000..ac6d2391 --- /dev/null +++ b/Mailman/Commands/__init__.py @@ -0,0 +1,15 @@ +# Copyright (C) 2001 by the Free Software Foundation, Inc. +# +# This program 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 2 +# of the License, or (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. diff --git a/Mailman/Commands/cmd_confirm.py b/Mailman/Commands/cmd_confirm.py new file mode 100644 index 00000000..5e4fc701 --- /dev/null +++ b/Mailman/Commands/cmd_confirm.py @@ -0,0 +1,84 @@ +# Copyright (C) 2002 by the Free Software Foundation, Inc. +# +# This program 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 2 +# of the License, or (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +""" + confirm <confirmation-string> + Confirm an action. The confirmation-string is required and should be + supplied with in mailback confirmation notice. +""" + +from Mailman import mm_cfg +from Mailman import Errors +from Mailman import Pending +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(mm_cfg.PENDING_REQUEST_LIFE / mm_cfg.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 current a member. Have you already unsubscribed or changed +your email address?""")) + 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/Mailman/Commands/cmd_echo.py b/Mailman/Commands/cmd_echo.py new file mode 100644 index 00000000..1f8b5979 --- /dev/null +++ b/Mailman/Commands/cmd_echo.py @@ -0,0 +1,26 @@ +# Copyright (C) 2002 by the Free Software Foundation, Inc. +# +# This program 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 2 +# of the License, or (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +""" + echo [args] + Simply echo an acknowledgement. Args are echoed back unchanged. +""" + +SPACE = ' ' + +def process(res, args): + res.results.append('echo %s' % SPACE.join(args)) + return 1 diff --git a/Mailman/Commands/cmd_end.py b/Mailman/Commands/cmd_end.py new file mode 100644 index 00000000..aeec7936 --- /dev/null +++ b/Mailman/Commands/cmd_end.py @@ -0,0 +1,33 @@ +# Copyright (C) 2002 by the Free Software Foundation, Inc. +# +# This program 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 2 +# of the License, or (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +""" + end + Stop processing commands. Use this if your mail program automatically + adds a signature file. +""" + +from Mailman.i18n import _ + + + +def gethelp(mlist): + return _(__doc__) + + + +def process(res, args): + return 1 # STOP diff --git a/Mailman/Commands/cmd_help.py b/Mailman/Commands/cmd_help.py new file mode 100644 index 00000000..e2d865e8 --- /dev/null +++ b/Mailman/Commands/cmd_help.py @@ -0,0 +1,92 @@ +# Copyright (C) 2002 by the Free Software Foundation, Inc. +# +# This program 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 2 +# of the License, or (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +""" + help + Print this help message. +""" + +import sys +import os + +from Mailman import mm_cfg +from Mailman import Utils +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' : mm_cfg.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/Mailman/Commands/cmd_info.py b/Mailman/Commands/cmd_info.py new file mode 100644 index 00000000..1c28da70 --- /dev/null +++ b/Mailman/Commands/cmd_info.py @@ -0,0 +1,49 @@ +# Copyright (C) 2002 by the Free Software Foundation, Inc. +# +# This program 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 2 +# of the License, or (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +""" + 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.GetListEmail() + requestaddr = mlist.GetRequestEmail() + owneraddr = mlist.GetOwnerEmail() + listurl = mlist.GetScriptURL('listinfo', absolute=1) + 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/Mailman/Commands/cmd_join.py b/Mailman/Commands/cmd_join.py new file mode 100644 index 00000000..4daccc1a --- /dev/null +++ b/Mailman/Commands/cmd_join.py @@ -0,0 +1,20 @@ +# Copyright (C) 2002 by the Free Software Foundation, Inc. +# +# This program 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 2 +# of the License, or (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +"""The `join' command is synonymous with `subscribe'. +""" + +from Mailman.Commands.cmd_subscribe import process diff --git a/Mailman/Commands/cmd_leave.py b/Mailman/Commands/cmd_leave.py new file mode 100644 index 00000000..ed5ccc7b --- /dev/null +++ b/Mailman/Commands/cmd_leave.py @@ -0,0 +1,20 @@ +# Copyright (C) 2002 by the Free Software Foundation, Inc. +# +# This program 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 2 +# of the License, or (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +"""The `leave' command is synonymous with `unsubscribe'. +""" + +from Mailman.Commands.cmd_unsubscribe import process diff --git a/Mailman/Commands/cmd_lists.py b/Mailman/Commands/cmd_lists.py new file mode 100644 index 00000000..81b60e60 --- /dev/null +++ b/Mailman/Commands/cmd_lists.py @@ -0,0 +1,69 @@ +# Copyright (C) 2002 by the Free Software Foundation, Inc. +# +# This program 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 2 +# of the License, or (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +""" + lists + See a list of the public mailing lists on this GNU Mailman server. +""" + +from Mailman import mm_cfg +from Mailman import Utils +from Mailman.MailList import MailList +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:')) + lists = Utils.list_names() + lists.sort() + i = 1 + for listname in lists: + 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. BAW: should a + # message to the site list include everything regardless of domain? + if mm_cfg.VIRTUAL_HOST_OVERVIEW and \ + 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/Mailman/Commands/cmd_password.py b/Mailman/Commands/cmd_password.py new file mode 100644 index 00000000..c2347be9 --- /dev/null +++ b/Mailman/Commands/cmd_password.py @@ -0,0 +1,118 @@ +# Copyright (C) 2002 by the Free Software Foundation, Inc. +# +# This program 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 2 +# of the License, or (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +""" + 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 import mm_cfg +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')) + 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')) + 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((mm_cfg.AuthUser, mm_cfg.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((mm_cfg.AuthUser, mm_cfg.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/Mailman/Commands/cmd_remove.py b/Mailman/Commands/cmd_remove.py new file mode 100644 index 00000000..55be1f3e --- /dev/null +++ b/Mailman/Commands/cmd_remove.py @@ -0,0 +1,20 @@ +# Copyright (C) 2002 by the Free Software Foundation, Inc. +# +# This program 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 2 +# of the License, or (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +"""The `remove' command is synonymous with `unsubscribe'. +""" + +from Mailman.Commands.cmd_unsubscribe import process diff --git a/Mailman/Commands/cmd_set.py b/Mailman/Commands/cmd_set.py new file mode 100644 index 00000000..c3eaa9a6 --- /dev/null +++ b/Mailman/Commands/cmd_set.py @@ -0,0 +1,353 @@ +# Copyright (C) 2002 by the Free Software Foundation, Inc. +# +# This program 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 2 +# of the License, or (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +from email.Utils import parseaddr, formatdate + +from Mailman import mm_cfg +from Mailman import Errors +from Mailman import MemberAdaptor +from Mailman import i18n + +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, mm_cfg.AcknowledgePosts) + onoff = opt and _('on') or _('off') + res.results.append(_(' ack %(onoff)s')) + # Digests are a special ternary value + digestsp = mlist.getMemberOption(address, mm_cfg.Digests) + if digestsp: + plainp = mlist.getMemberOption(address, mm_cfg.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, mm_cfg.DontReceiveOwnPosts) + # sense is reversed + onoff = (not opt) and _('on') or _('off') + res.results.append(_(' myposts %(onoff)s')) + opt = mlist.getMemberOption(address, mm_cfg.ConcealSubscription) + onoff = opt and _('on') or _('off') + res.results.append(_(' hide %(onoff)s')) + opt = mlist.getMemberOption(address, mm_cfg.DontReceiveDuplicates) + # sense is reversed + onoff = (not opt) and _('on') or _('off') + res.results.append(_(' duplicates %(onoff)s')) + opt = mlist.getMemberOption(address, mm_cfg.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((mm_cfg.AuthUser, + mm_cfg.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, mm_cfg.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, mm_cfg.Digests, 0) + except Errors.AlreadyReceivingRegularDeliveries: + pass + elif arg == 'plain': + try: + mlist.setMemberOption(self.__address, mm_cfg.Digests, 1) + except Errors.AlreadyReceivingDigests: + pass + mlist.setMemberOption(self.__address, mm_cfg.DisableMime, 1) + elif arg == 'mime': + try: + mlist.setMemberOption(self.__address, mm_cfg.Digests, 1) + except Errors.AlreadyReceivingDigests: + pass + mlist.setMemberOption(self.__address, mm_cfg.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 + # sense is reversed + mlist.setMemberOption(self.__address, mm_cfg.DisableDelivery, + not status) + res.results.append(_('delivery option set')) + + 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, mm_cfg.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, mm_cfg.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, mm_cfg.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, mm_cfg.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/Mailman/Commands/cmd_stop.py b/Mailman/Commands/cmd_stop.py new file mode 100644 index 00000000..defcf64d --- /dev/null +++ b/Mailman/Commands/cmd_stop.py @@ -0,0 +1,20 @@ +# Copyright (C) 2002 by the Free Software Foundation, Inc. +# +# This program 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 2 +# of the License, or (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +"""stop is synonymous with the end command. +""" + +from Mailman.Commands.cmd_end import process diff --git a/Mailman/Commands/cmd_subscribe.py b/Mailman/Commands/cmd_subscribe.py new file mode 100644 index 00000000..1a5048d6 --- /dev/null +++ b/Mailman/Commands/cmd_subscribe.py @@ -0,0 +1,136 @@ +# Copyright (C) 2002 by the Free Software Foundation, Inc. +# +# This program 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 2 +# of the License, or (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +""" + subscribe [password] [digest|nodigest] [address=<address>] + Subscribe to this mailing list. Your password must be given to + unsubscribe or change your options, but if you omit the password, one + will be generated for you. You may be periodically reminded of your + password. + + The next argument may be either: `nodigest' or `digest' (no quotes!). + If you wish to subscribe 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 email.Header import decode_header, make_header + +from Mailman import Utils +from Mailman import Errors +from Mailman.UserDesc import UserDesc +from Mailman.i18n import _ + +STOP = 1 + + + +def gethelp(mlist): + return _(__doc__) + + + +def process(res, args): + mlist = res.mlist + digest = None + password = None + address = None + realname = None + # Parse the args + argnum = 0 + for arg in args: + if arg.startswith('address='): + address = arg[8:] + elif argnum == 0: + password = arg + elif argnum == 1: + if arg.lower() not in ('digest', 'nodigest'): + res.results.append(_('Bad digest specifier: %(arg)s')) + return STOP + if arg.lower() == 'digest': + digest = 1 + else: + digest = 0 + else: + res.results.append(_('Usage:')) + res.results.append(gethelp(mlist)) + return STOP + argnum += 1 + # Fill in empty defaults + if digest is None: + digest = mlist.digest_is_default + if password is None: + password = Utils.MakeRandomPassword() + if address is None: + realname, address = parseaddr(res.msg['from']) + if not address: + # Fall back to the sender address + address = res.msg.get_sender() + if not address: + res.results.append(_('No valid address found to subscribe')) + return STOP + # Watch for encoded names + h = make_header(decode_header(realname)) + # BAW: in Python 2.2, use just unicode(h) + realname = h.__unicode__() + # Coerce to byte string if uh contains only ascii + try: + realname = realname.encode('us-ascii') + except UnicodeError: + pass + # Create the UserDesc record and do a non-approved subscription + listowner = mlist.GetOwnerEmail() + userdesc = UserDesc(address, realname, password, digest) + remote = res.msg.get_sender() + try: + mlist.AddMember(userdesc, remote) + except Errors.MembershipIsBanned: + res.results.append(_("""\ +The email address you supplied is banned from this mailing list. +If you think this restriction is erroneous, please contact the list +owners at %(listowner)s.""")) + return STOP + except Errors.MMBadEmailError: + res.results.append(_("""\ +Mailman won't accept the given email address as a valid address. +(E.g. it must have an @ in it.)""")) + return STOP + except Errors.MMHostileAddress: + res.results.append(_("""\ +Your subscription is not allowed because +the email address you gave is insecure.""")) + return STOP + except Errors.MMAlreadyAMember: + res.results.append(_('You are already subscribed!')) + return STOP + except Errors.MMCantDigestError: + res.results.append( + _('No one can subscribe to the digest of this list!')) + return STOP + except Errors.MMMustDigestError: + res.results.append(_('This list only supports digest subscriptions!')) + return STOP + except Errors.MMSubscribeNeedsConfirmation: + # We don't need to respond /and/ send a confirmation message. + res.respond = 0 + except Errors.MMNeedApproval: + res.results.append(_("""\ +Your subscription request has been forwarded to the list administrator +at %(listowner)s for review.""")) + else: + # Everything is a-ok + res.results.append(_('Subscription request succeeded.')) diff --git a/Mailman/Commands/cmd_unsubscribe.py b/Mailman/Commands/cmd_unsubscribe.py new file mode 100644 index 00000000..c574a80f --- /dev/null +++ b/Mailman/Commands/cmd_unsubscribe.py @@ -0,0 +1,87 @@ +# Copyright (C) 2002 by the Free Software Foundation, Inc. +# +# This program 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 2 +# of the License, or (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +""" + 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/Mailman/Commands/cmd_who.py b/Mailman/Commands/cmd_who.py new file mode 100644 index 00000000..62505b3d --- /dev/null +++ b/Mailman/Commands/cmd_who.py @@ -0,0 +1,133 @@ +# Copyright (C) 2002 by the Free Software Foundation, Inc. +# +# This program 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 2 +# of the License, or (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# Remove this when base minimal compatibility is Python 2.2 +from __future__ import nested_scopes + +from email.Utils import parseaddr + +from Mailman import mm_cfg +from Mailman import i18n + +STOP = 1 + +def _(s): return s + +PUBLICHELP = _(""" + who + See everyone who is on this mailing list. +""") + +MEMBERSONLYHELP = _(""" + who password [address=<address>] + See everyone who is on 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!) +""") + +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 = 0 + if mlist.private_roster == 0: + # Public rosters + if args: + usage(res) + return STOP + ok = 1 + 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( + (mm_cfg.AuthUser, + mm_cfg.AuthListModerator, + mm_cfg.AuthListAdmin), + password, address): + # Then + ok = 1 + else: + # Admin only + if len(args) <> 1: + usage(res) + return STOP + if mlist.Authenticate((mm_cfg.AuthListModerator, + mm_cfg.AuthListAdmin), + args[0]): + ok = 1 + 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 mlist.getMemberOption(member, mm_cfg.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) |