diff options
Diffstat (limited to 'mailman/queue/command.py')
| -rw-r--r-- | mailman/queue/command.py | 106 |
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) |
