def _dispose(self, mlist, msg, msgdata): message_id = msg.get('message-id', 'n/a') # The policy here is similar to the Replybot policy. If a message has # "Precedence: bulk|junk|list" and no "X-Ack: yes" header, we discard # the command message. precedence = msg.get('precedence', '').lower() ack = msg.get('x-ack', '').lower() if ack != 'yes' and precedence in ('bulk', 'junk', 'list'): log.info('%s Precedence: %s message discarded by: %s', message_id, precedence, mlist.request_address) return False # Do replybot for commands. replybot = config.handlers['replybot'] replybot.process(mlist, msg, msgdata) if mlist.autorespond_requests == ResponseAction.respond_and_discard: # Respond and discard. log.info('%s -request message replied and discarded', message_id) return False # Now craft the response and process the command lines. charset = msg.get_param('charset') if charset is None: charset = 'us-ascii' results = Results(charset) # Include just a few key pieces of information from the original: the # sender, date, and message id. print(_('- Original message details:'), file=results) subject = msg.get('subject', 'n/a') # noqa: F841 date = msg.get('date', 'n/a') # noqa: F841 from_ = msg.get('from', 'n/a') # noqa: F841 print(_(' From: $from_'), file=results) print(_(' Subject: $subject'), file=results) print(_(' Date: $date'), file=results) print(_(' Message-ID: $message_id'), file=results) print(_('\n- Results:'), file=results) finder = CommandFinder(msg, msgdata, results) for parts in finder: command = None # Try to find a command on this line. There may be a Re: prefix # (possibly internationalized) so try with the first and second # words on the line. if len(parts) > 0: command_name = parts.pop(0) command = config.commands.get(command_name) if command is None and len(parts) > 0: command_name = parts.pop(0) command = config.commands.get(command_name) if command is None: print(_('No such command: $command_name'), file=results) else: status = command.process(mlist, msg, msgdata, parts, results) assert status in ContinueProcessing, ('Invalid status: %s' % status) if status == ContinueProcessing.no: break # All done. If we don't need to send response, return. if not finder.send_response: return # Strip blank lines and send the response. lines = [line.strip() for line in finder.command_lines if line] if len(lines) > 0: print(_('\n- Unprocessed:'), file=results) for line in lines: print(line, file=results) lines = [line.strip() for line in finder.ignored_lines if line] if len(lines) > 0: print(_('\n- Ignored:'), file=results) for line in lines: print(line, file=results) print(_('\n- Done.'), file=results) # 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. language = getUtility(ILanguageManager)[msgdata['lang']] reply = UserNotification(msg.sender, mlist.bounces_address, _('The results of your email commands'), lang=language) cte = msg.get('content-transfer-encoding') if cte is not None: reply['Content-Transfer-Encoding'] = cte # Find a charset for the response body. Try the original message's # charset first, then ascii, then latin-1 and finally falling back to # utf-8. reply_body = str(results) for charset in (results.charset, 'us-ascii', 'latin-1'): with suppress(UnicodeError): reply_body.encode(charset) break else: charset = 'utf-8' reply.set_payload(reply_body, charset=charset) reply.send(mlist)
def _dispose(self, mlist, msg, msgdata): message_id = msg.get('message-id', 'n/a') # The policy here is similar to the Replybot policy. If a message has # "Precedence: bulk|junk|list" and no "X-Ack: yes" header, we discard # the command message. precedence = msg.get('precedence', '').lower() ack = msg.get('x-ack', '').lower() if ack <> 'yes' and precedence in ('bulk', 'junk', 'list'): log.info('%s Precedence: %s message discarded by: %s', message_id, precedence, mlist.request_address) return False # Do replybot for commands. replybot = config.handlers['replybot'] replybot.process(mlist, msg, msgdata) if mlist.autorespond_requests == 1: # Respond and discard. log.info('%s -request message replied and discard', message_id) return False # Now craft the response and process the command lines. charset = msg.get_param('charset') if charset is None: charset = 'us-ascii' results = Results(charset) # Include just a few key pieces of information from the original: the # sender, date, and message id. print(_('- Original message details:'), file=results) subject = msg.get('subject', 'n/a') date = msg.get('date', 'n/a') from_ = msg.get('from', 'n/a') print(_(' From: $from_'), file=results) print(_(' Subject: $subject'), file=results) print(_(' Date: $date'), file=results) print(_(' Message-ID: $message_id'), file=results) print(_('\n- Results:'), file=results) finder = CommandFinder(msg, msgdata, results) for parts in finder: command = None # Try to find a command on this line. There may be a Re: prefix # (possibly internationalized) so try with the first and second # words on the line. if len(parts) > 0: command_name = parts.pop(0) command = config.commands.get(command_name) if command is None and len(parts) > 0: command_name = parts.pop(0) command = config.commands.get(command_name) if command is None: print(_('No such command: $command_name'), file=results) else: status = command.process( mlist, msg, msgdata, parts, results) assert status in ContinueProcessing, ( 'Invalid status: %s' % status) if status == ContinueProcessing.no: break # All done. Strip blank lines and send the response. lines = filter(None, (line.strip() for line in finder.command_lines)) if len(lines) > 0: print(_('\n- Unprocessed:'), file=results) for line in lines: print(line, file=results) lines = filter(None, (line.strip() for line in finder.ignored_lines)) if len(lines) > 0: print(_('\n- Ignored:'), file=results) for line in lines: print(line, file=results) print(_('\n- Done.'), file=results) # 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. language = getUtility(ILanguageManager)[msgdata['lang']] reply = UserNotification(msg.sender, mlist.bounces_address, _('The results of your email commands'), lang=language) cte = msg.get('content-transfer-encoding') if cte is not None: reply['Content-Transfer-Encoding'] = cte # Find a charset for the response body. Try the original message's # charset first, then ascii, then latin-1 and finally falling back to # utf-8. reply_body = unicode(results) for charset in (results.charset, '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)
def _dispose(self, mlist, msg, msgdata): message_id = msg.get("message-id", "n/a") # The policy here is similar to the Replybot policy. If a message has # "Precedence: bulk|junk|list" and no "X-Ack: yes" header, we discard # the command message. precedence = msg.get("precedence", "").lower() ack = msg.get("x-ack", "").lower() if ack != "yes" and precedence in ("bulk", "junk", "list"): log.info("%s Precedence: %s message discarded by: %s", message_id, precedence, mlist.request_address) return False # Do replybot for commands. replybot = config.handlers["replybot"] replybot.process(mlist, msg, msgdata) if mlist.autorespond_requests == 1: # Respond and discard. log.info("%s -request message replied and discard", message_id) return False # Now craft the response and process the command lines. charset = msg.get_param("charset") if charset is None: charset = "us-ascii" results = Results(charset) # Include just a few key pieces of information from the original: the # sender, date, and message id. print(_("- Original message details:"), file=results) subject = msg.get("subject", "n/a") date = msg.get("date", "n/a") from_ = msg.get("from", "n/a") print(_(" From: $from_"), file=results) print(_(" Subject: $subject"), file=results) print(_(" Date: $date"), file=results) print(_(" Message-ID: $message_id"), file=results) print(_("\n- Results:"), file=results) finder = CommandFinder(msg, msgdata, results) for parts in finder: command = None # Try to find a command on this line. There may be a Re: prefix # (possibly internationalized) so try with the first and second # words on the line. if len(parts) > 0: command_name = parts.pop(0) command = config.commands.get(command_name) if command is None and len(parts) > 0: command_name = parts.pop(0) command = config.commands.get(command_name) if command is None: print(_("No such command: $command_name"), file=results) else: status = command.process(mlist, msg, msgdata, parts, results) assert status in ContinueProcessing, "Invalid status: %s" % status if status == ContinueProcessing.no: break # All done. Strip blank lines and send the response. lines = [line.strip() for line in finder.command_lines if line] if len(lines) > 0: print(_("\n- Unprocessed:"), file=results) for line in lines: print(line, file=results) lines = [line.strip() for line in finder.ignored_lines if line] if len(lines) > 0: print(_("\n- Ignored:"), file=results) for line in lines: print(line, file=results) print(_("\n- Done."), file=results) # 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. language = getUtility(ILanguageManager)[msgdata["lang"]] reply = UserNotification( msg.sender, mlist.bounces_address, _("The results of your email commands"), lang=language ) cte = msg.get("content-transfer-encoding") if cte is not None: reply["Content-Transfer-Encoding"] = cte # Find a charset for the response body. Try the original message's # charset first, then ascii, then latin-1 and finally falling back to # utf-8. reply_body = str(results) for charset in (results.charset, "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)