Exemplo n.º 1
0
def _send_email_oops(trans, log, mail, error_msg, file_alias_url):
    """Handle an error that generates an oops.

    It does the following:
        * records an OOPS with error_msg and file_alias_url
        * commits the current transaction to ensure that the
            message gets sent
    """
    log.info('error processing mail: %s' % (error_msg, ))
    oops_id = report_oops(file_alias_url=file_alias_url, error_msg=error_msg)
    log.info('oops %s' % (oops_id, ))
    send_process_error_notification(
        mail['From'], 'Submit Request Failure',
        get_error_message('oops.txt', oops_id=oops_id), mail)
    trans.commit()
Exemplo n.º 2
0
    def processComment(self, mail, email_addr, file_alias):
        """Process an email and create a CodeReviewComment.

        The only mail command understood is 'vote', which takes 'approve',
        'disapprove', or 'abstain' as values.  Specifically, it takes
        any CodeReviewVote item value, case-insensitively.
        :return: True.
        """
        user = getUtility(ILaunchBag).user
        try:
            merge_proposal = self.getBranchMergeProposal(email_addr)
        except NonExistantBranchMergeProposalAddress:
            send_process_error_notification(
                str(user.preferredemail.email),
                'Submit Request Failure',
                'There is no merge proposal at %s' % email_addr,
                mail)
            return True
        except BadBranchMergeProposalAddress:
            return False
        context = CodeReviewEmailCommandExecutionContext(merge_proposal, user)
        try:
            email_body_text = get_main_body(mail)
            commands = CodeEmailCommands.getCommands(email_body_text)
            processed_count = self.processCommands(context, commands)

            # Make sure that the email is in fact signed.
            if processed_count > 0:
                ensure_not_weakly_authenticated(mail, 'code review')

            message = getUtility(IMessageSet).fromEmail(
                mail.parsed_string,
                owner=getUtility(ILaunchBag).user,
                filealias=file_alias,
                parsed_message=mail)
            merge_proposal.createCommentFromMessage(
                message, context.vote, context.vote_tags, mail)

        except IncomingEmailError as error:
            send_process_error_notification(
                str(user.preferredemail.email),
                'Submit Request Failure',
                error.message, mail, error.failing_command)
            transaction.abort()
        return True
Exemplo n.º 3
0
    def processComment(self, mail, email_addr, file_alias):
        """Process an email and create a CodeReviewComment.

        The only mail command understood is 'vote', which takes 'approve',
        'disapprove', or 'abstain' as values.  Specifically, it takes
        any CodeReviewVote item value, case-insensitively.
        :return: True.
        """
        user = getUtility(ILaunchBag).user
        try:
            merge_proposal = self.getBranchMergeProposal(email_addr)
        except NonExistantBranchMergeProposalAddress:
            send_process_error_notification(
                str(user.preferredemail.email), 'Submit Request Failure',
                'There is no merge proposal at %s' % email_addr, mail)
            return True
        except BadBranchMergeProposalAddress:
            return False
        context = CodeReviewEmailCommandExecutionContext(merge_proposal, user)
        try:
            email_body_text = get_main_body(mail)
            commands = CodeEmailCommands.getCommands(email_body_text)
            processed_count = self.processCommands(context, commands)

            # Make sure that the email is in fact signed.
            if processed_count > 0:
                ensure_not_weakly_authenticated(mail, 'code review')

            message = getUtility(IMessageSet).fromEmail(
                mail.parsed_string,
                owner=getUtility(ILaunchBag).user,
                filealias=file_alias,
                parsed_message=mail)
            merge_proposal.createCommentFromMessage(message, context.vote,
                                                    context.vote_tags, mail)

        except IncomingEmailError as error:
            send_process_error_notification(str(user.preferredemail.email),
                                            'Submit Request Failure',
                                            error.message, mail,
                                            error.failing_command)
            transaction.abort()
        return True
Exemplo n.º 4
0
def _send_email_oops(trans, log, mail, error_msg, file_alias_url):
    """Handle an error that generates an oops.

    It does the following:
        * records an OOPS with error_msg and file_alias_url
        * commits the current transaction to ensure that the
            message gets sent
    """
    log.info('error processing mail: %s' % (error_msg,))
    oops_id = report_oops(
        file_alias_url=file_alias_url,
        error_msg=error_msg)
    log.info('oops %s' % (oops_id,))
    send_process_error_notification(
        mail['From'],
        'Submit Request Failure',
        get_error_message('oops.txt', oops_id=oops_id),
        mail)
    trans.commit()
Exemplo n.º 5
0
def handle_one_mail(log, mail, file_alias, file_alias_url,
                    signature_timestamp_checker):
    """Process one message.

    Returns None when the message has either been successfully processed, or
    handled as a known error condition, in which case a reply will have been
    sent if appropriate.
    """
    log.debug('processing mail from %r message-id %r' %
              (mail['from'], mail['message-id']))

    # If the Return-Path header is '<>', it probably means
    # that it's a bounce from a message we sent.
    if mail['Return-Path'] == '<>':
        log.info("Message had an empty Return-Path.")
        return
    if mail.get_content_type() == 'multipart/report':
        # Mails with a content type of multipart/report are
        # generally DSN messages and should be ignored.
        log.info("Got a multipart/report message.")
        return
    if 'precedence' in mail:
        log.info("Got a message with a precedence header.")
        return

    if mail.raw_length > MAX_EMAIL_SIZE:
        complaint = (
            "The mail you sent to Launchpad is too long.\n\n"
            "Your message <%s>\nwas %d MB and the limit is %d MB." %
            (mail['message-id'], mail.raw_length / 1e6, MAX_EMAIL_SIZE / 1e6))
        log.info(complaint)
        # It's probably big and it's probably mostly binary, so trim it pretty
        # aggressively.
        send_process_error_notification(mail['From'],
                                        'Mail to Launchpad was too large',
                                        complaint,
                                        mail,
                                        max_return_size=8192)
        return

    try:
        principal = authenticateEmail(mail, signature_timestamp_checker)
    except (InvalidSignature, IncomingEmailError) as error:
        send_process_error_notification(mail['From'], 'Submit Request Failure',
                                        str(error), mail)
        return
    except InactiveAccount:
        log.info("Inactive account found for %s" % mail['From'])
        return

    addresses = extract_addresses(mail, file_alias_url, log)
    log.debug('mail was originally to: %r' % (addresses, ))

    try:
        do_paranoid_envelope_to_validation(addresses)
    except AssertionError as e:
        log.info("Invalid email address: %s" % e)
        return

    handler = None
    for email_addr in addresses:
        user, domain = email_addr.split('@')
        handler = mail_handlers.get(domain)
        if handler is not None:
            break
    else:
        raise AssertionError("No handler registered for '%s' " %
                             (', '.join(addresses)))

    if principal is None and not handler.allow_unknown_users:
        log.info('Mail from unknown users not permitted for this handler')
        return

    handled = handler.process(mail, email_addr, file_alias)
    if not handled:
        raise AssertionError("Handler found, but message was not handled")
Exemplo n.º 6
0
    def process(self, signed_msg, to_addr, filealias=None, log=None):
        """See IMailHandler."""

        try:
            (
                final_result,
                add_comment_to_bug,
                commands,
            ) = self.extractAndAuthenticateCommands(signed_msg, to_addr)
            if final_result is not None:
                return final_result

            bug = None
            bug_event = None
            bugtask = None
            bugtask_event = None

            processing_errors = []
            while len(commands) > 0:
                command = commands.pop(0)
                try:
                    if IBugEmailCommand.providedBy(command):
                        # Finish outstanding work from the previous bug.
                        self.notify_bug_event(bug_event)
                        self.notify_bugtask_event(bugtask_event, bug_event)
                        bugtask = None
                        bugtask_event = None
                        # Get or start building a new bug.
                        bug, bug_event = command.execute(signed_msg, filealias)
                        if add_comment_to_bug:
                            message = self.appendBugComment(
                                bug, signed_msg, filealias)
                            add_comment_to_bug = False
                            self.processAttachments(bug, message, signed_msg)
                    elif IBugTaskEmailCommand.providedBy(command):
                        self.notify_bugtask_event(bugtask_event, bug_event)
                        bugtask, bugtask_event, bug_event = command.execute(
                            bug, bug_event)
                        if isinstance(bug, CreateBugParams):
                            bug = bugtask.bug
                            message = bug.initial_message
                            self.processAttachments(bug, message, signed_msg)
                    elif IBugEditEmailCommand.providedBy(command):
                        bug, bug_event = command.execute(bug, bug_event)
                    elif IBugTaskEditEmailCommand.providedBy(command):
                        if bugtask is None:
                            if isinstance(bug, CreateBugParams):
                                self.handleNoAffectsTarget()
                            bugtask = guess_bugtask(
                                bug,
                                getUtility(ILaunchBag).user)
                            if bugtask is None:
                                self.handleNoDefaultAffectsTarget(bug)
                        bugtask, bugtask_event = command.execute(
                            bugtask, bugtask_event)

                except EmailProcessingError as error:
                    processing_errors.append((error, command))
                    if error.stop_processing:
                        commands = []
                        transaction.abort()
                    else:
                        continue

            if len(processing_errors) > 0:
                raise IncomingEmailError(
                    '\n'.join(
                        str(error) for error, command in processing_errors),
                    [command for error, command in processing_errors])
            if isinstance(bug, CreateBugParams):
                # A new bug without any commands was sent.
                self.handleNoAffectsTarget()
            self.notify_bug_event(bug_event)
            self.notify_bugtask_event(bugtask_event, bug_event)

        except IncomingEmailError as error:
            send_process_error_notification(
                str(getUtility(ILaunchBag).user.preferredemail.email),
                'Submit Request Failure', error.message, signed_msg,
                error.failing_command)

        return True
Exemplo n.º 7
0
def handle_one_mail(log, mail, file_alias, file_alias_url,
                    signature_timestamp_checker):
    """Process one message.

    Returns None when the message has either been successfully processed, or
    handled as a known error condition, in which case a reply will have been
    sent if appropriate.
    """
    log.debug('processing mail from %r message-id %r' %
        (mail['from'], mail['message-id']))

    # If the Return-Path header is '<>', it probably means
    # that it's a bounce from a message we sent.
    if mail['Return-Path'] == '<>':
        log.info("Message had an empty Return-Path.")
        return
    if mail.get_content_type() == 'multipart/report':
        # Mails with a content type of multipart/report are
        # generally DSN messages and should be ignored.
        log.info("Got a multipart/report message.")
        return
    if 'precedence' in mail:
        log.info("Got a message with a precedence header.")
        return

    if mail.raw_length > MAX_EMAIL_SIZE:
        complaint = (
            "The mail you sent to Launchpad is too long.\n\n"
            "Your message <%s>\nwas %d MB and the limit is %d MB." %
            (mail['message-id'], mail.raw_length / 1e6, MAX_EMAIL_SIZE / 1e6))
        log.info(complaint)
        # It's probably big and it's probably mostly binary, so trim it pretty
        # aggressively.
        send_process_error_notification(
            mail['From'], 'Mail to Launchpad was too large', complaint,
            mail, max_return_size=8192)
        return

    try:
        principal = authenticateEmail(mail, signature_timestamp_checker)
    except (InvalidSignature, IncomingEmailError) as error:
        send_process_error_notification(
            mail['From'], 'Submit Request Failure', str(error), mail)
        return
    except InactiveAccount:
        log.info("Inactive account found for %s" % mail['From'])
        return

    addresses = extract_addresses(mail, file_alias_url, log)
    log.debug('mail was originally to: %r' % (addresses,))

    try:
        do_paranoid_envelope_to_validation(addresses)
    except AssertionError as e:
        log.info("Invalid email address: %s" % e)
        return

    handler = None
    for email_addr in addresses:
        user, domain = email_addr.split('@')
        handler = mail_handlers.get(domain)
        if handler is not None:
            break
    else:
        raise AssertionError(
            "No handler registered for '%s' " % (', '.join(addresses)))

    if principal is None and not handler.allow_unknown_users:
        log.info('Mail from unknown users not permitted for this handler')
        return

    handled = handler.process(mail, email_addr, file_alias)
    if not handled:
        raise AssertionError("Handler found, but message was not handled")
Exemplo n.º 8
0
    def process(self, signed_msg, to_addr, filealias=None, log=None):
        """See IMailHandler."""

        try:
            (final_result, add_comment_to_bug,
                commands, ) = self.extractAndAuthenticateCommands(
                    signed_msg, to_addr)
            if final_result is not None:
                return final_result

            bug = None
            bug_event = None
            bugtask = None
            bugtask_event = None

            processing_errors = []
            while len(commands) > 0:
                command = commands.pop(0)
                try:
                    if IBugEmailCommand.providedBy(command):
                        # Finish outstanding work from the previous bug.
                        self.notify_bug_event(bug_event)
                        self.notify_bugtask_event(bugtask_event, bug_event)
                        bugtask = None
                        bugtask_event = None
                        # Get or start building a new bug.
                        bug, bug_event = command.execute(signed_msg, filealias)
                        if add_comment_to_bug:
                            message = self.appendBugComment(
                                bug, signed_msg, filealias)
                            add_comment_to_bug = False
                            self.processAttachments(bug, message, signed_msg)
                    elif IBugTaskEmailCommand.providedBy(command):
                        self.notify_bugtask_event(bugtask_event, bug_event)
                        bugtask, bugtask_event, bug_event = command.execute(
                            bug, bug_event)
                        if isinstance(bug, CreateBugParams):
                            bug = bugtask.bug
                            message = bug.initial_message
                            self.processAttachments(bug, message, signed_msg)
                    elif IBugEditEmailCommand.providedBy(command):
                        bug, bug_event = command.execute(bug, bug_event)
                    elif IBugTaskEditEmailCommand.providedBy(command):
                        if bugtask is None:
                            if isinstance(bug, CreateBugParams):
                                self.handleNoAffectsTarget()
                            bugtask = guess_bugtask(
                                bug, getUtility(ILaunchBag).user)
                            if bugtask is None:
                                self.handleNoDefaultAffectsTarget(bug)
                        bugtask, bugtask_event = command.execute(
                            bugtask, bugtask_event)

                except EmailProcessingError as error:
                    processing_errors.append((error, command))
                    if error.stop_processing:
                        commands = []
                        transaction.abort()
                    else:
                        continue

            if len(processing_errors) > 0:
                raise IncomingEmailError(
                    '\n'.join(str(error) for error, command
                              in processing_errors),
                    [command for error, command in processing_errors])
            if isinstance(bug, CreateBugParams):
                # A new bug without any commands was sent.
                self.handleNoAffectsTarget()
            self.notify_bug_event(bug_event)
            self.notify_bugtask_event(bugtask_event, bug_event)

        except IncomingEmailError as error:
            send_process_error_notification(
                str(getUtility(ILaunchBag).user.preferredemail.email),
                'Submit Request Failure',
                error.message, signed_msg, error.failing_command)

        return True