diff options
| author | mailman | 1998-02-25 16:18:17 +0000 |
|---|---|---|
| committer | mailman | 1998-02-25 16:18:17 +0000 |
| commit | 978e8db8c4234a83e4f47be922597352af5454fc (patch) | |
| tree | 29bd19abc72064c3db7550faca4422a8008ab987 /Mailman/MailCommandHandler.py | |
| parent | 563d1a40520c2c214535d08a164a7b20954c806d (diff) | |
| download | mailman-978e8db8c4234a83e4f47be922597352af5454fc.tar.gz mailman-978e8db8c4234a83e4f47be922597352af5454fc.tar.zst mailman-978e8db8c4234a83e4f47be922597352af5454fc.zip | |
Diffstat (limited to 'Mailman/MailCommandHandler.py')
| -rw-r--r-- | Mailman/MailCommandHandler.py | 450 |
1 files changed, 450 insertions, 0 deletions
diff --git a/Mailman/MailCommandHandler.py b/Mailman/MailCommandHandler.py new file mode 100644 index 000000000..6c930a7ed --- /dev/null +++ b/Mailman/MailCommandHandler.py @@ -0,0 +1,450 @@ +# Process mail commands. +# Try to stay close to majordomo commands, but accept common mistakes. +# Not implemented: get / index / which + + + + +import string, os, sys +import mm_message, mm_err, mm_cfg, mm_utils + + + + +option_descs = { 'digest' : 'receive mail from the list bundled together instead of ' + 'one post at a time', + 'nomail' : 'Stop delivering mail. Useful if you plan on taking a ' + 'short vacation.', + 'norcv' : 'Turn this on to NOT receive posts you send to the list. ' + 'does not work if digest is set', + 'ack' : 'Turn this on to receive acknowlegement mail when you ' + 'send mail to the list', + 'fancy' : 'Get MIME-compliant digests (only works if digest is set)', + 'hide' : 'Conceals your email from the list of subscribers' + } +option_info = { 'digest' : 0, + 'nomail' : mm_cfg.DisableDelivery, + 'norcv' : mm_cfg.DontReceiveOwnPosts, + 'ack' : mm_cfg.AcknowlegePosts, + 'fancy' : mm_cfg.EnableMime, + 'hide' : mm_cfg.ConcealSubscription + } + +class MailCommandHandler: + def __init__(self): + self._response_buffer = '' + self._cmd_dispatch = { + 'subscribe' : self.ProcessSubscribeCmd, + 'unsubscribe' : self.ProcessUnsubscribeCmd, + 'who' : self.ProcessWhoCmd, + 'info' : self.ProcessInfoCmd, + 'lists' : self.ProcessListsCmd, + 'help' : self.ProcessHelpCmd, + 'set' : self.ProcessSetCmd, + 'options' : self.ProcessOptionsCmd, + 'password' : self.ProcessPasswordCmd, + } + + def AddToResponse(self, text): + self._response_buffer = self._response_buffer + text + "\n" + + def AddError(self, text): + self._response_buffer = self._response_buffer + "**** " + text + "\n" + + def ParseMailCommands(self): + mail = mm_message.IncomingMessage() + subject = mail.getheader("subject") + if subject: + subject = string.strip(subject) + if (subject and self._cmd_dispatch.has_key(string.split(subject)[0])): + lines = [subject] + string.split(mail.body, '\n') + else: + lines = string.split(mail.body, '\n') + if subject: + self.AddError("Subject line ignored.") + for line in lines: + line = string.strip(line) + if not line: + continue + self.AddToResponse("\n>>>> %s" % line) + line = string.strip(line) + if not line: + continue + args = string.split(line) + cmd = string.lower(args[0]) + args = args[1:] + if cmd == 'end': + self.AddError("End of commands.") + break + if not self._cmd_dispatch.has_key(cmd): + self.AddError("%s: Command UNKNOWN." % cmd) + else: + self._cmd_dispatch[cmd](args, line, mail) + self.SendMailCmdResponse(mail) + + def SendMailCmdResponse(self, mail): + self.SendTextToUser(subject = 'Mailman results for %s' % + self.real_name, + recipient = mail.GetSender(), + sender = self.GetRequestEmail(), + text = self._response_buffer) + self._response_buffer = '' + + def ProcessPasswordCmd(self, args, cmd, mail): + if len(args) <> 2: + self.AddError("Usage: password <oldpw> <newpw>") + return + try: + self.ChangeUserPassword(mail.GetSender(), args[0], args[1], args[1]) + self.AddToResponse('Succeded.') + except mm_err.MMListNotReady: + self.AddError("List is not functional.") + except mm_err.MMNotAMemberError: + self.AddError("%s isn't subscribed to this list." % mail.GetSender()) + except mm_err.MMBadPasswordError: + self.AddError("You gave the wrong password.") + except: + self.AddError("An unknown Mailman error occured.") + self.AddError("Please forward on your request to %s" % + self.GetAdminEmail()) + self.AddError("%s" % sys.exc_type) + + def ProcessOptionsCmd(self, args, cmd, mail): + sender = self.FindUser(mail.GetSender()) + if not sender: + self.AddError("%s is not a member of the list." % mail.GetSender()) + return + options = option_info.keys() + options.sort() + value = '' + for option in options: + if self.GetUserOption(sender, option_info[option]): + value = 'on' + else: + value = 'off' + self.AddToResponse("%s: %s" % (option, value)) + self.AddToResponse("") + self.AddToResponse("To change an option, do: set <option> <on|off> <password>") + self.AddToResponse("") + self.AddToResponse("Option explanations:") + self.AddToResponse("--------------------") + for option in options: + self.AddToResponse("%s:" % option) + self.AddToResponse(option_descs[option]) + self.AddToResponse("") + + def ProcessSetCmd(self, args, cmd, mail): + def ShowSetUsage(s=self, od = option_descs): + options = od.keys() + options.sort() + s.AddError("Usage: set <option> <on|off> <password>") + s.AddError("Valid options are:") + for option in options: + s.AddError("%s: %s" % (option, od[option])) + if len(args) <> 3: + ShowSetUsage() + return + if args[1] == 'on': + value = 1 + elif args[1] == 'off': + value = 0 + else: + ShowSetUsage() + return + if option_info.has_key(args[0]): + try: + sender = self.FindUser(mail.GetSender()) + if not sender: + self.AddError("You aren't subscribed.") + return + self.ConfirmUserPassword(sender, args[2]) + self.SetUserOption(sender, option_info[args[0]], value) + self.AddToResponse("Succeeded.") + except mm_err.MMBadPasswordError: + self.AddError("You gave the wrong password.") + except: + self.AddError("An unknown Mailman error occured.") + self.AddError("Please forward on your request to %s" % + self.GetAdminEmail()) + self.AddError("%s" % sys.exc_type) + elif args[0] == 'digest': + try: + self.SetUserDigest(mail.GetSender(), args[2], value) + self.AddToResponse("Succeeded.") + except mm_err.MMAlreadyDigested: + self.AddError("You are already receiving digests.") + except mm_err.MMAlreadyUndigested: + self.AddError("You already have digests off.") + except mm_err.MMBadEmailError: + self.AddError("Email address '%s' not accepted by Mailman." % + mail.GetSender()) + except mm_err.MMMustDigestError: + self.AddError("List only accepts digest members.") + except mm_err.MMCantDigestError: + self.AddError("List doesn't accept digest members.") + except mm_err.MMNotAMemberError: + self.AddError("%s isn't subscribed to this list." % mail.GetSender()) + except mm_err.MMListNotReady: + self.AddError("List is not functional.") + except mm_err.MMNoSuchUserError: + self.AddError("%s is not subscribed to this list." %mail.GetSender()) + except mm_err.MMBadPasswordError: + self.AddError("You gave the wrong password.") + except mm_err.MMNeedApproval: + self.AddApprovalMsg(cmd) + except: + # TODO: Should log the error we got if we got here. + self.AddError("An unknown Mailman error occured.") + self.AddError("Please forward on your request to %s" % + self.GetAdminEmail()) + self.AddError("%s" % sys.exc_type) + else: + ShowSetUsage() + return + + def ProcessListsCmd(self, args, cmd, mail): + lists = os.listdir(mm_cfg.LIST_DATA_DIR) + self.AddToResponse("Mailing lists run by Mailman@%s:" % self.host_name) + for list in lists: + if list == self._internal_name: + listob = self + else: + try: + import maillist + listob = maillist.MailList(list) + except: + continue + # We can mention this list if you already know about it. + if not listob.advertised and listob <> self: + continue + self.AddToResponse("%s (requests to %s): %s" % + (listob.real_name, listob.GetRequestEmail(), + listob.description)) + + def ProcessInfoCmd(self, args, cmd, mail): + if self.closed and not self.IsMember(mail.GetSender()): + self.AddError("Closed list: only members may see info.") + return + + self.AddToResponse("Here is the info for list %s:" % self.real_name) + if not self.info: + self.AddToResponse("No information on list %s found." % + self.real_name) + else: + self.AddToResponse(self.info) + + def ProcessWhoCmd(self, args, cmd, mail): + def AddTab(str): + return '\t' + str + + if self.closed == 2: + self.AddError("Closed list: No one may see subscription list.") + return + if self.closed and not self.IsMember(mail.GetSender()): + self.AddError("Closed list: only members may see list subscribers.") + return + if not len(self.digest_members) and not len(self.members): + self.AddToResponse("NO MEMBERS.") + return + + def NotHidden(x, s=self, v=mm_cfg.ConcealSubscription): + return not s.GetUserOption(x, v) + + if len(self.members): + self.AddToResponse("Non-Digest Members:") + self.AddToResponse(string.join(map(AddTab, filter(NotHidden, + self.members)), "\n")) + + if len(self.digest_members): + self.AddToResponse("") + self.AddToResponse("Digest Members:") + self.AddToResponse(string.join(map(AddTab, filter(NotHidden, + self.digest_members)), "\n")) + + + def ProcessUnsubscribeCmd(self, args, cmd, mail): + if not len(args): + self.AddError("Must supply a password.") + return + if len(args) > 2: + self.AddError("Extra text '%s' not understood. IGNORED." % + string.join(args[1:])) + + if len(args) == 2: + addr = args[1] + else: + addr = mail.GetSender() + try: + self.ConfirmUserPassword(addr, args[0]) + self.DeleteMember(addr) + self.AddToResponse("Succeded.") + except mm_err.MMListNotReady: + self.AddError("List is not functional.") + except mm_err.MMNoSuchUserError: + self.AddError("%s is not subscribed to this list." %mail.GetSender()) + except mm_err.MMBadPasswordError: + self.AddError("You gave the wrong password.") + except: + # TODO: Should log the error we got if we got here. + self.AddError("An unknown Mailman error occured.") + self.AddError("Please forward on your request to %s" % + self.GetAdminEmail()) + self.AddError("%s %s" % (sys.exc_type, sys.exc_value)) + self.AddError("%s" % sys.exc_traceback) + + def ProcessSubscribeCmd(self, args, cmd, mail): + digest = self.digest_is_default + if not len(args): + password = "%s%s" % (mm_utils.GetRandomSeed(), + mm_utils.GetRandomSeed()) + elif len(args) == 1: + if string.lower(args[0]) == 'digest': + digest = 1 + password = "%s%s" % (mm_utils.GetRandomSeed(), + mm_utils.GetRandomSeed()) + elif string.lower(args[0]) == 'nodigest': + digest = 0 + password = "%s%s" % (mm_utils.GetRandomSeed(), + mm_utils.GetRandomSeed()) + else: + password = args[0] + + elif len(args) == 2: + if string.lower(args[1]) == 'nodigest': + digest = 0 + password = args[0] + elif string.lower(args[1]) == 'digest': + digest = 1 + password = args[0] + elif string.lower(args[0]) == 'nodigest': + digest = 0 + password = args[1] + elif string.lower(args[0]) == 'digest': + digest = 1 + password = args[1] + else: + self.AddError("Usage: subscribe [password] [digest|nodigest]") + return + elif len(args) > 2: + self.AddError("Usage: subscribe [password] [digest|nodigest]") + return + + try: + self.AddMember(mail.GetSender(), password, digest) + self.AddToResponse("Succeded.") + except mm_err.MMBadEmailError: + self.AddError("Email address '%s' not accepted by Mailman." % + mail.GetSender()) + except mm_err.MMMustDigestError: + self.AddError("List only accepts digest members.") + except mm_err.MMCantDigestError: + self.AddError("List doesn't accept digest members.") + except mm_err.MMListNotReady: + self.AddError("List is not functional.") + except mm_err.MMNeedApproval: + self.AddApprovalMsg(cmd) + except mm_err.MMHostileAddress: + self.AddError("Email address '%s' not accepted by Mailman (insecure address)" % mail.GetSender()) + except mm_err.MMAlreadyAMember: + self.AddError("%s is already a list member." % mail.GetSender()) + except: + # TODO: Should log the error we got if we got here. + self.AddError("An unknown Mailman error occured.") + self.AddError("Please forward on your request to %s" % + self.GetAdminEmail()) + self.AddError("%s" % sys.exc_type) + + def AddApprovalMsg(self, cmd): + self.AddError('''Your request to %s: + + %s + +has been forwarded to the person running the list. + +This is probably because you are trying to subscribe to a 'closed' list. + +If the list owner decides what to do with your request, you will receive +e-mail notification. + +Any questions about the list owner's policy should be directed to: + + %s + +''' % (self.GetRequestEmail(), cmd, self.GetAdminEmail())) + + + def ProcessHelpCmd(self, args, cmd, mail): + self.AddToResponse("**** Help for %s:" % self.real_name) + self.AddToResponse(""" +This is version %s of the "Mailman" list manager. +Words in <>'s denote required items. When providing them, do not include +the <>'s around it. Words in [] denote OPTIONAL items. do not include the +[]'s in your response. + +The following commands are valid: + + subscribe [password] [digest-option] + Subscribe to the mailing list. Your password must be given to + unsubscribe or change your options. When you subscribe to the + list, you'll be reminded of your password periodically. + 'digest-option' may be either: 'nodigest' or 'digest' (no quotes!) + To subscribe this way, you must subscribe from the account in + which you wish to receive mail. + + unsubscribe <password> [address] + Unsubscribe from the mailing list. Your password must match + the one you gave when you subscribed. If you are trying to + unsubscribe from a different address than the one you subscribed + from, you may specify it in the 'address' field. + + who + See who is on this mailing list. + + info + View the introductory information for this list. + + lists + See what other mailing lists are run by this Mailman server. + + help + This message. + + set <option> <on|off> <password> + Turn on or off list options. Valid options are: + + ack: + Turn this on to receive acknowlegement mail when you send mail to the list + + digest: + receive mail from the list bundled together instead of one post at a time + + fancy: + Get MIME-compliant digests (only works if digest is set) + + nomail: + Stop delivering mail. Useful if you plan on taking a short vacation. + + norcv: + Turn this on to NOT receive posts you send to the list. + Does not work if digest is set + + hide: + Conceals your address when people look at who is on this list. + + + options + Show the current values of your list options. + + password <oldpassword> <newpassword> + Change your list password. + + end + Stop processing commands (good to do if your mailer automatically + adds a signature file. It'll save you from a lot of spam.) + + +Commands should be sent to "%s". + +Other concerns should be addressed to "%s". +""" % (mm_cfg.VERSION, self.GetRequestEmail(), self.GetAdminEmail())) + |
