# Copyright (C) 1998 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. """Process maillist user commands arriving via email.""" __version__ = "$Revision: 621 $" # Try to stay close to majordomo commands, but accept common mistakes. # Not implemented: get / index / which. import string, os, sys, re import mm_message, mm_err, mm_cfg, mm_utils, mm_pending 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', 'plain' : 'Get plain, not MIME-compliant, ' 'digests (only 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, 'plain' : mm_cfg.DisableMime, 'hide' : mm_cfg.ConcealSubscription } class MailCommandHandler: def __init__(self): self._response_buffer = '' self._cmd_dispatch = { 'subscribe' : self.ProcessSubscribeCmd, 'confirm': self.ProcessConfirmCmd, 'unsubscribe' : self.ProcessUnsubscribeCmd, 'who' : self.ProcessWhoCmd, 'info' : self.ProcessInfoCmd, 'lists' : self.ProcessListsCmd, 'help' : self.ProcessHelpCmd, 'set' : self.ProcessSetCmd, 'options' : self.ProcessOptionsCmd, 'password' : self.ProcessPasswordCmd, } self.__NoMailCmdResponse = 0 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") sender = string.lower(mail.GetSender()) if sender in ['daemon', 'nobody', 'mailer-daemon', 'postmaster', 'orphanage', 'postoffice']: # This is for what are probably delivery-failure notices of # subscription confirmations that are, of necessity, bounced # back to the -request address. self.LogMsg("bounce", ("%s: Mailcmd rejected" "\n\tReason: Probable bounced subscribe-confirmation" "\n\tFrom: %s" "\n\tSubject: %s" ), self._internal_name, mail.getheader('from'), subject) return 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: # # check to see if confirmation request -- special handling # conf_pat = r"%s -- confirmation of subscription -- request (\d\d\d\d\d\d)" % \ self.real_name match = re.search(conf_pat, mail.body) if match: lines = ["confirm %s" % (match.group(1))] else: self.AddError("Subject line ignored: %s" % subject) 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) if not self.__NoMailCmdResponse: 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 ") return try: self.ChangeUserPassword(mail.GetSender(), args[0], args[1], args[1]) self.AddToResponse('Succeeded.') 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