summaryrefslogtreecommitdiff
path: root/mailman/queue/command.py
diff options
context:
space:
mode:
Diffstat (limited to 'mailman/queue/command.py')
-rw-r--r--mailman/queue/command.py106
1 files changed, 48 insertions, 58 deletions
diff --git a/mailman/queue/command.py b/mailman/queue/command.py
index b06a5387b..319cab87c 100644
--- a/mailman/queue/command.py
+++ b/mailman/queue/command.py
@@ -56,7 +56,7 @@ log = logging.getLogger('mailman.vette')
class CommandFinder:
"""Generate commands from the content of a message."""
- def __init__(self, msg, results):
+ def __init__(self, msg, msgdata, results):
self.command_lines = []
self.ignored_lines = []
self.processed_lines = []
@@ -73,7 +73,7 @@ class CommandFinder:
if mo:
self.command_lines.append('confirm ' + mo.group('cookie'))
# Extract the subject header and do RFC 2047 decoding.
- subject = msg.get('subject', '')
+ raw_subject = msg.get('subject', '')
try:
subject = unicode(make_header(decode_header(raw_subject)))
# Mail commands must be ASCII.
@@ -118,21 +118,21 @@ class CommandFinder:
class Results:
"""The email command results."""
- implements(IResults)
+ implements(IEmailResults)
def __init__(self):
self._output = StringIO()
print >> self._output, _("""\
The results of your email command are provided below.
-
""")
- print >> self._output, _('- Results:')
def write(self, text):
self._output.write(text)
- def __str__(self):
- return self._output.getvalue()
+ def __unicode__(self):
+ value = self._output.getvalue()
+ assert isinstance(value, unicode), 'Not a unicode: %r' % value
+ return value
@@ -159,61 +159,51 @@ class CommandRunner(Runner):
return False
# Now craft the response and process the command lines.
results = Results()
- finder = CommandFinder(msg, results)
+ # Include just a few key pieces of information from the original: the
+ # sender, date, and message id.
+ print >> results, _('- Original message details:')
+ subject = msg.get('subject', 'n/a')
+ date = msg.get('date', 'n/a')
+ from_ = msg.get('from', 'n/a')
+ print >> results, _(' From: $from_')
+ print >> results, _(' Subject: $subject')
+ print >> results, _(' Date: $date')
+ print >> results, _(' Message-ID: $message_id')
+ print >> results, _('\n- Results:')
+ finder = CommandFinder(msg, msgdata, results)
for command_name, arguments in finder:
command = config.commands.get(command_name)
if command is None:
print >> results, _('No such command: $command_name')
else:
- command.process(msg, msgdata, arguments, results)
+ command.process(mlist, msg, msgdata, arguments, results)
# All done, send the response.
- print >> results, _('\n- Unprocessed:')
- # XXX
-
-
- # Ignore empty lines
- 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:
- # The user sent an empty message; return a helpful one.
- 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'))
- # Encode any unicode strings into the list charset, so we don't try to
- # join unicode strings and invalid ASCII.
- charset = Utils.GetCharSet(self.msgdata['lang'])
- encoded_resp = []
- for item in resp:
- if isinstance(item, unicode):
- item = item.encode(charset, 'replace')
- encoded_resp.append(item)
- results = MIMEText(NL.join(encoded_resp), _charset=charset)
- # Safety valve for mail loops with misconfigured email 'bots. We
- # don't respond to commands sent with "Precedence: bulk|junk|list"
- # unless they explicitly "X-Ack: yes", but not all mail 'bots are
- # correctly configured, so we max out the number of responses we'll
- # give to an address in a single day.
- #
- # BAW: We wait until now to make this decision since our sender may
- # not be self.msg.get_sender(), but I'm not sure this is right.
- recip = self.returnaddr or self.msg.get_sender()
- if not autorespond_to_sender(self.mlist, recip, self.msgdata['lang']):
- return
- msg = Message.UserNotification(
- recip,
- self.mlist.GetBouncesEmail(),
+ if len(finder.command_lines) > 0:
+ print >> results, _('\n- Unprocessed:')
+ for line in finder.command_lines:
+ print >> results, line
+ if len(finder.ignored_lines) > 0:
+ print >> results, _('\n- Ignored:')
+ for line in finder.ignored_lines:
+ print >> results, line
+ print >> results, _('\n- Done.')
+ # Send a reply, but do not attach the original message. This is a
+ # compromise because the original message is often helpful in tracking
+ # down problems, but it's also a vector for backscatter spam.
+ reply = Message.UserNotification(
+ msg.get_sender(), mlist.bounces_address,
_('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)
+ lang=msgdata['lang'])
+ # Find a charset for the response body. Try ascii first, then
+ # latin-1 and finally falling back to utf-8.
+ reply_body = unicode(results)
+ for charset in ('us-ascii', 'latin-1'):
+ try:
+ reply_body.encode(charset)
+ break
+ except UnicodeError:
+ pass
+ else:
+ charset = 'utf-8'
+ reply.set_payload(reply_body, charset=charset)
+ reply.send(mlist)