"""-request robot command queue runner."""
from __future__ import nested_scopes
import re
import sys
from types import StringType, UnicodeType
from Mailman import mm_cfg
from Mailman import Utils
from Mailman import Message
from Mailman.Handlers import Replybot
from Mailman.i18n import _
from Mailman.Queue.Runner import Runner
from Mailman.Logging.Syslog import syslog
from Mailman import LockFile
from email.Header import decode_header, make_header, Header
from email.Errors import HeaderParseError
from email.Iterators import typed_subpart_iterator
from email.MIMEText import MIMEText
from email.MIMEMessage import MIMEMessage
NL = '\n'
try:
True, False
except NameError:
True = 1
False = 0
class Results:
def __init__(self, mlist, msg, msgdata):
self.mlist = mlist
self.msg = msg
self.msgdata = msgdata
self.returnaddr = None
self.commands = []
self.results = []
self.ignored = []
self.lineno = 0
self.subjcmdretried = 0
self.respond = True
subj = msg.get('subject', '')
try:
subj = make_header(decode_header(subj)).__unicode__()
subj = subj.encode('us-ascii')
self.commands.append(subj)
except (HeaderParseError, UnicodeError, LookupError):
pass
part = None
for part in typed_subpart_iterator(msg, 'text', 'plain'):
break
if part is None or part is not msg:
self.results.append(_('Ignoring non-text/plain MIME parts'))
if part is None:
return
body = part.get_payload()
assert isinstance(body, StringType) or isinstance(body, UnicodeType)
lines = body.splitlines()
self.commands.extend(lines[:mm_cfg.DEFAULT_MAIL_COMMANDS_MAX_LINES])
self.ignored.extend(lines[mm_cfg.DEFAULT_MAIL_COMMANDS_MAX_LINES:])
def process(self):
stop = False
for line in self.commands:
if line and line.strip():
args = line.split()
cmd = args.pop(0).lower()
stop = self.do_command(cmd, args)
self.lineno += 1
if stop:
break
def do_command(self, cmd, args=None):
if args is None:
args = ()
modname = 'Mailman.Commands.cmd_' + cmd
try:
__import__(modname)
handler = sys.modules[modname]
except (ImportError, ValueError):
if not self.subjcmdretried and args:
self.subjcmdretried += 1
cmd = args.pop(0)
return self.do_command(cmd, args)
return self.lineno <> 0
return handler.process(self, args)
def send_response(self):
def indent(lines):
return [' ' + line for line in lines]
if not self.respond:
return
resp = [Utils.wrap(_("""\
The results of your email command are provided below.
Attached is your original message.
"""))]
if self.results:
resp.append(_('- Results:'))
resp.extend(indent(self.results))
unprocessed = [line for line in self.commands[self.lineno:]
if line and line.strip()]
if unprocessed:
resp.append(_('\n- Unprocessed:'))
resp.extend(indent(unprocessed))
if not unprocessed and not self.results:
resp.append(Utils.wrap(_("""\
No commands were found in this message.
To obtain instructions, send a message containing just the word "help".
""")))
if self.ignored:
resp.append(_('\n- Ignored:'))
resp.extend(indent(self.ignored))
resp.append(_('\n- Done.\n\n'))
charset = Utils.GetCharSet(self.msgdata['lang'])
encoded_resp = []
for item in resp:
if isinstance(item, UnicodeType):
item = item.encode(charset, 'replace')
encoded_resp.append(item)
results = MIMEText(NL.join(encoded_resp), _charset=charset)
recip = self.returnaddr or self.msg.get_sender()
if not self.mlist.autorespondToSender(recip, self.msgdata['lang']):
return
msg = Message.UserNotification(
recip,
self.mlist.GetBouncesEmail(),
_('The results of your email commands'),
lang=self.msgdata['lang'])
msg.set_type('multipart/mixed')
msg.attach(results)
orig = MIMEMessage(self.msg)
msg.attach(orig)
msg.send(self.mlist)
class CommandRunner(Runner):
QDIR = mm_cfg.CMDQUEUE_DIR
def _dispose(self, mlist, msg, msgdata):
precedence = msg.get('precedence', '').lower()
ack = msg.get('x-ack', '').lower()
if ack <> 'yes' and precedence in ('bulk', 'junk', 'list'):
syslog('vette', 'Precedence: %s message discarded by: %s',
precedence, mlist.GetRequestEmail())
return False
mlist.Load()
Replybot.process(mlist, msg, msgdata)
if mlist.autorespond_requests == 1:
syslog('vette', 'replied and discard')
return False
res = Results(mlist, msg, msgdata)
try:
mlist.Lock(timeout=mm_cfg.LIST_LOCK_TIMEOUT)
except LockFile.TimeOutError:
return True
try:
if msgdata.get('torequest'):
res.process()
elif msgdata.get('tojoin'):
res.do_command('join')
elif msgdata.get('toleave'):
res.do_command('leave')
elif msgdata.get('toconfirm'):
mo = re.match(mm_cfg.VERP_CONFIRM_REGEXP, msg.get('to', ''))
if mo:
res.do_command('confirm', (mo.group('cookie'),))
res.send_response()
mlist.Save()
finally:
mlist.Unlock()