Parse branch notification messages sent by Launchpad.

def parse(self, m, prefix=None):
        """Parse branch notification messages sent by Launchpad.
        """

        subject = m["subject"]
        match = re.search(r"^\s*\[Branch\s+([^]]+)\]", subject)
        if match:
            repository = match.group(1)
        else:
            repository = None

        # Put these into a dictionary, otherwise we cannot assign them
        # from nested function definitions.
        d = {'files': [], 'comments': ""}
        gobbler = None
        rev = None
        author = None
        when = util.now()

        def gobble_comment(s):
            d['comments'] += s + "\n"

        def gobble_removed(s):
            d['files'].append('%s REMOVED' % s)

        def gobble_added(s):
            d['files'].append('%s ADDED' % s)

        def gobble_modified(s):
            d['files'].append('%s MODIFIED' % s)

        def gobble_renamed(s):
            match = re.search(r"^(.+) => (.+)$", s)
            if match:
                d['files'].append('%s RENAMED %s' %
                                  (match.group(1), match.group(2)))
            else:
                d['files'].append('%s RENAMED' % s)

        lines = list(body_line_iterator(m, True))
        rev = None
        while lines:
            line = str(lines.pop(0), "utf-8", errors="ignore")

            # revno: 101
            match = re.search(r"^revno: ([0-9.]+)", line)
            if match:
                rev = match.group(1)

            # committer: Joe <joe@acme.com>
            match = re.search(r"^committer: (.*)$", line)
            if match:
                author = match.group(1)

            # timestamp: Fri 2009-05-15 10:35:43 +0200
            # datetime.strptime() is supposed to support %z for time zone, but
            # it does not seem to work. So handle the time zone manually.
            match = re.search(
                r"^timestamp: [a-zA-Z]{3} (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) ([-+])(\d{2})(\d{2})$", line)
            if match:
                datestr = match.group(1)
                tz_sign = match.group(2)
                tz_hours = match.group(3)
                tz_minutes = match.group(4)
                when = parseLaunchpadDate(
                    datestr, tz_sign, tz_hours, tz_minutes)

            if re.search(r"^message:\s*$", line):
                gobbler = gobble_comment
            elif re.search(r"^removed:\s*$", line):
                gobbler = gobble_removed
            elif re.search(r"^added:\s*$", line):
                gobbler = gobble_added
            elif re.search(r"^renamed:\s*$", line):
                gobbler = gobble_renamed
            elif re.search(r"^modified:\s*$", line):
                gobbler = gobble_modified
            elif re.search(r"^  ", line) and gobbler:
                gobbler(line[2:-1])  # Use :-1 to gobble trailing newline

        # Determine the name of the branch.
        branch = None
        if self.branchMap and repository:
            if repository in self.branchMap:
                branch = self.branchMap[repository]
            elif ("lp:" + repository) in self.branchMap:
                branch = self.branchMap['lp:' + repository]
        if not branch:
            if self.defaultBranch:
                branch = self.defaultBranch
            else:
                if repository:
                    branch = 'lp:' + repository
                else:
                    branch = None

        if rev and author:
            return ('bzr', dict(author=author, files=d['files'],
                                comments=d['comments'],
                                when=when, revision=rev,
                                branch=branch, repository=repository or ''))
        return None