Ejemplo n.º 1
0
    def get_payload(self, i = None, decode = False):
        if i is None:
            payload = self._payload
        elif not isinstance(self._payload, list):
            raise TypeError('Expected list, got %s' % type(self._payload))
        else:
            payload = self._payload[i]
        if decode:
            if self.is_multipart():
                return
            cte = self.get('content-transfer-encoding', '').lower()
            if cte == 'quoted-printable':
                return utils._qdecode(payload)
            if cte == 'base64':
                try:
                    return utils._bdecode(payload)
                except binascii.Error:
                    return payload

            elif cte in ('x-uuencode', 'uuencode', 'uue', 'x-uue'):
                sfp = StringIO()
                try:
                    uu.decode(StringIO(payload + '\n'), sfp, quiet=True)
                    payload = sfp.getvalue()
                except uu.Error:
                    return payload

        return payload
Ejemplo n.º 2
0
    def decode_payload(self, encoding, payload):
        """
        Decode attachment payload data.

        :param encoding:
            The current encoding of the payload data.

        :param payload:
            the payload data
        """
        cte = encoding.lower()
        if cte == 'quoted-printable':
            return utils._qdecode(payload)
        elif cte == 'base64':
            try:
                return utils._bdecode(payload)
            except binascii.Error:
                # Incorrect padding
                return payload
        elif cte in ('x-uuencode', 'uuencode', 'uue', 'x-uue'):
            sfp = StringIO()
            try:
                uu.decode(StringIO(payload + '\n'), sfp, quiet=True)
                payload = sfp.getvalue()
            except uu.Error:
                # Some decoding problem
                return payload
Ejemplo n.º 3
0
    def get_payload(self, i=None, decode=False):
        if i is None:
            payload = self._payload
        elif not isinstance(self._payload, list):
            raise TypeError('Expected list, got %s' % type(self._payload))
        else:
            payload = self._payload[i]
        if decode:
            if self.is_multipart():
                return
            cte = self.get('content-transfer-encoding', '').lower()
            if cte == 'quoted-printable':
                return utils._qdecode(payload)
            if cte == 'base64':
                try:
                    return utils._bdecode(payload)
                except binascii.Error:
                    return payload

            elif cte in ('x-uuencode', 'uuencode', 'uue', 'x-uue'):
                sfp = StringIO()
                try:
                    uu.decode(StringIO(payload + '\n'), sfp, quiet=True)
                    payload = sfp.getvalue()
                except uu.Error:
                    return payload

        return payload
Ejemplo n.º 4
0
def DecodeData(data, cte):
    if data == None:
        return data
    if "?gb2312?b?" in data:
        records = GetDataList(data, "?gb2312?b?")
        ret = ""
        for record in records:
            ret += utils._bdecode(record)
        return ret
    if "?gb2312?B?" in data:
        records = GetDataList(data, "?gb2312?B?")
        ret = ""
        for record in records:
            ret += utils._bdecode(record)
        return ret
    else:
        return data
Ejemplo n.º 5
0
def DecodeData(data, cte):
    if data == None:
        return data
    if "?gb2312?b?" in data:
        records = GetDataList(data, "?gb2312?b?")
        ret = ""
        for record in records:
            ret += utils._bdecode(record)
        return ret
    if "?gb2312?B?" in data:
        records = GetDataList(data, "?gb2312?B?")
        ret = ""
        for record in records:
            ret += utils._bdecode(record)
        return ret
    else:
        return data
Ejemplo n.º 6
0
    def get_payload(self, i=None, decode=False):
        """Return a reference to the payload.

        The payload will either be a list object or a string.  If you mutate
        the list object, you modify the message's payload in place.  Optional
        i returns that index into the payload.

        Optional decode is a flag indicating whether the payload should be
        decoded or not, according to the Content-Transfer-Encoding header
        (default is False).

        When True and the message is not a multipart, the payload will be
        decoded if this header's value is `quoted-printable' or `base64'.  If
        some other encoding is used, or the header is missing, or if the
        payload has bogus data (i.e. bogus base64 or uuencoded data), the
        payload is returned as-is.

        If the message is a multipart and the decode flag is True, then None
        is returned.
        """
        if i is None:
            payload = self._payload
        elif not isinstance(self._payload, list):
            raise TypeError('Expected list, got %s' % type(self._payload))
        else:
            payload = self._payload[i]
        if decode:
            if self.is_multipart():
                return None
            cte = self.get('content-transfer-encoding', '').lower()
            if cte == 'quoted-printable':
                return utils._qdecode(payload)
            elif cte == 'base64':
                try:
                    return utils._bdecode(payload)
                except binascii.Error:
                    # Incorrect padding
                    return payload
            elif cte in ('x-uuencode', 'uuencode', 'uue', 'x-uue'):
                sfp = StringIO()
                try:
                    uu.decode(StringIO(payload+'\n'), sfp, quiet=True)
                    payload = sfp.getvalue()
                except uu.Error:
                    # Some decoding problem
                    return payload
        # Everything else, including encodings with 8bit or 7bit are returned
        # unchanged.
        return payload
Ejemplo n.º 7
0
    def get_payload(self, i=None, decode=False):
        """Return a reference to the payload.

        The payload will either be a list object or a string.  If you mutate
        the list object, you modify the message's payload in place.  Optional
        i returns that index into the payload.

        Optional decode is a flag indicating whether the payload should be
        decoded or not, according to the Content-Transfer-Encoding header
        (default is False).

        When True and the message is not a multipart, the payload will be
        decoded if this header's value is `quoted-printable' or `base64'.  If
        some other encoding is used, or the header is missing, or if the
        payload has bogus data (i.e. bogus base64 or uuencoded data), the
        payload is returned as-is.

        If the message is a multipart and the decode flag is True, then None
        is returned.
        """
        if i is None:
            payload = self._payload
        elif not isinstance(self._payload, list):
            raise TypeError("Expected list, got %s" % type(self._payload))
        else:
            payload = self._payload[i]
        if decode:
            if self.is_multipart():
                return None
            cte = self.get("content-transfer-encoding", "").lower()
            if cte == "quoted-printable":
                return utils._qdecode(payload)
            elif cte == "base64":
                try:
                    return utils._bdecode(payload)
                except binascii.Error:
                    # Incorrect padding
                    return payload
            elif cte in ("x-uuencode", "uuencode", "uue", "x-uue"):
                sfp = StringIO()
                try:
                    uu.decode(StringIO(payload + "\n"), sfp, quiet=True)
                    payload = sfp.getvalue()
                except uu.Error:
                    # Some decoding problem
                    return payload
        # Everything else, including encodings with 8bit or 7bit are returned
        # unchanged.
        return payload
Ejemplo n.º 8
0
    def get_payload(self, i = None, decode = False):
        """Return a reference to the payload.
        
        The payload will either be a list object or a string.  If you mutate
        the list object, you modify the message's payload in place.  Optional
        i returns that index into the payload.
        
        Optional decode is a flag indicating whether the payload should be
        decoded or not, according to the Content-Transfer-Encoding header
        (default is False).
        
        When True and the message is not a multipart, the payload will be
        decoded if this header's value is `quoted-printable' or `base64'.  If
        some other encoding is used, or the header is missing, or if the
        payload has bogus data (i.e. bogus base64 or uuencoded data), the
        payload is returned as-is.
        
        If the message is a multipart and the decode flag is True, then None
        is returned.
        """
        if i is None:
            payload = self._payload
        elif not isinstance(self._payload, list):
            raise TypeError('Expected list, got %s' % type(self._payload))
        else:
            payload = self._payload[i]
        if decode:
            if self.is_multipart():
                return
            cte = self.get('content-transfer-encoding', '').lower()
            if cte == 'quoted-printable':
                return utils._qdecode(payload)
            if cte == 'base64':
                try:
                    return utils._bdecode(payload)
                except binascii.Error:
                    return payload

            elif cte in ('x-uuencode', 'uuencode', 'uue', 'x-uue'):
                sfp = StringIO()
                try:
                    uu.decode(StringIO(payload + '\n'), sfp, quiet=True)
                    payload = sfp.getvalue()
                except uu.Error:
                    return payload

        return payload
Ejemplo n.º 9
0
def rewrite(part):
    need_rewrite = False

    for hdr in part.values():
        if max([len(i) for i in hdr.split('\n')]) > MAX_LINE_LENGTH:
            need_rewrite = True # Force MIME rewrite if we have long headers
            sys.stderr.write("FIXUP NEXT: Rewrite forced by long header line\n")

    for hdr, max_lines, max_items, max_bytes in NUKE_HDRS:
        (hdr, val) = (hdr.lower(), msg.get(hdr))
        if (val and ((max_lines >= 0 and len(val.split('\n')) > max_lines) or
                     (max_items >= 0 and len(val.split()) > max_items) or
                     (max_bytes >= 0 and len(val) > max_bytes))):
            del msg[hdr]
            sys.stderr.write("FIXUP NEXT: Removed long header line: "+hdr+"\n")
            need_rewrite = True

    if part.is_multipart():
        for subpart in part.get_payload():
            if rewrite(subpart):
                need_rewrite = True
        return need_rewrite

    payload = part.get_payload()
    max_line_length = max([ len(i) for i in payload.split('\n') ])

    cte     = part.get('content-transfer-encoding', '').lower().strip()
    if cte in ['8bit', '7bit', 'binary', '']:
        # Encode unencoded forms which contain 8bit characters or long lines
        update_cte = part.replace_header if (cte != '') else part.add_header
        nonascii_count = [(ord(c) >= 128) for c in payload].count(True)
        if ((NUKE_8BIT and nonascii_count > 0) or
            max_line_length > MAX_LINE_LENGTH):
            if nonascii_count < 100: 
                part.set_payload(qp_encode(payload))
                update_cte('Content-Transfer-Encoding', "quoted-printable")
            else:
                part.set_payload(utils._bencode(payload))
                update_cte('Content-Transfer-Encoding', "base64")
            need_rewrite = True
    elif cte in ['quoted-printable', 'base64']:
        # Recode quoted-printable or base64 with long lines
        if max_line_length > MAX_LINE_LENGTH:
            if cte == 'quoted-printable':
                raw=utils._qdecode(payload)
                part.set_payload(qp_encode(raw))
                need_rewrite = True
            elif cte == 'base64':
                try:
                    raw=utils._bdecode(payload)
                    part.set_payload(utils._bencode(raw))
                    need_rewrite = True
                except binascii.Error:
                    pass

    newcte =  part.get('content-transfer-encoding', '').lower().strip()
    if (newcte != cte):
        part.add_header('X-Mime-Autoconverted',
                        "from " + (cte or "none") + " to " + newcte)
        sys.stderr.write("FIXUP NEXT: Attachment converted " +
                         "from " + (cte or "none") + " to " + newcte + "\n")
    return need_rewrite
Ejemplo n.º 10
0
def rewrite(part):
    need_rewrite = False

    for hdr in part.values():
        if max([len(i) for i in hdr.split('\n')]) > MAX_LINE_LENGTH:
            need_rewrite = True  # Force MIME rewrite if we have long headers
            sys.stderr.write(
                "FIXUP NEXT: Rewrite forced by long header line\n")

    for hdr, max_lines, max_items, max_bytes in NUKE_HDRS:
        (hdr, val) = (hdr.lower(), msg.get(hdr))
        if (val and ((max_lines >= 0 and len(val.split('\n')) > max_lines) or
                     (max_items >= 0 and len(val.split()) > max_items) or
                     (max_bytes >= 0 and len(val) > max_bytes))):
            del msg[hdr]
            sys.stderr.write("FIXUP NEXT: Removed long header line: " + hdr +
                             "\n")
            need_rewrite = True

    if part.is_multipart():
        for subpart in part.get_payload():
            if rewrite(subpart):
                need_rewrite = True
        return need_rewrite

    payload = part.get_payload()
    max_line_length = max([len(i) for i in payload.split('\n')])

    cte = part.get('content-transfer-encoding', '').lower().strip()
    if cte in ['8bit', '7bit', 'binary', '']:
        # Encode unencoded forms which contain 8bit characters or long lines
        update_cte = part.replace_header if (cte != '') else part.add_header
        nonascii_count = [(ord(c) >= 128) for c in payload].count(True)
        if ((NUKE_8BIT and nonascii_count > 0)
                or max_line_length > MAX_LINE_LENGTH):
            if nonascii_count < 100:
                part.set_payload(qp_encode(payload))
                update_cte('Content-Transfer-Encoding', "quoted-printable")
            else:
                part.set_payload(utils._bencode(payload))
                update_cte('Content-Transfer-Encoding', "base64")
            need_rewrite = True
    elif cte in ['quoted-printable', 'base64']:
        # Recode quoted-printable or base64 with long lines
        if max_line_length > MAX_LINE_LENGTH:
            if cte == 'quoted-printable':
                raw = utils._qdecode(payload)
                part.set_payload(qp_encode(raw))
                need_rewrite = True
            elif cte == 'base64':
                try:
                    raw = utils._bdecode(payload)
                    part.set_payload(utils._bencode(raw))
                    need_rewrite = True
                except binascii.Error:
                    pass

    newcte = part.get('content-transfer-encoding', '').lower().strip()
    if (newcte != cte):
        part.add_header('X-Mime-Autoconverted',
                        "from " + (cte or "none") + " to " + newcte)
        sys.stderr.write("FIXUP NEXT: Attachment converted " + "from " +
                         (cte or "none") + " to " + newcte + "\n")
    return need_rewrite
Ejemplo n.º 11
0
def rewrite(part, drop_all_multipart_err):
    need_rewrite = False

    if (part.preamble and max_line_len(part.preamble) > MAX_LINE_LENGTH):
        part.preamble = "\n"
        sys.stderr.write("FIXUP NEXT: Removed over-long MIME preamble\n")
        need_rewrite = True
            
    if (part.epilogue and max_line_len(part.epilogue) > MAX_LINE_LENGTH):
        part.epilogue = "\n"
        sys.stderr.write("FIXUP NEXT: Removed over-long MIME epilogue\n")
        need_rewrite = True
            
    for hdr in part.values():
        if max_line_len(hdr) > MAX_LINE_LENGTH:
            need_rewrite = True # Force MIME rewrite if we have long headers
            sys.stderr.write("FIXUP NEXT: Rewrite forced by long header line\n")

    for hdr, max_lines, max_items, max_bytes in NUKE_HDRS:
        (hdr, val) = (hdr.lower(), part.get(hdr))
        if (val and ((max_lines >= 0 and len(val.split('\n')) > max_lines) or
                     (max_items >= 0 and len(val.split()) > max_items) or
                     (max_bytes >= 0 and len(val) > max_bytes))):
            del part[hdr]
            sys.stderr.write("FIXUP NEXT: Removed long header line: "+hdr+"\n")
            need_rewrite = True

    # Exchange Online can't cope with very long component in address list    
    for hdr in ['To', 'Cc', 'Bcc']:
        val = part.get(hdr, "")
        for addr in val.split(','): # Need better parsing here!
            if len(addr) > 1950:
                part['X-Broken-' + hdr] = val
                del part[hdr]
                sys.stderr.write("FIXUP NEXT: Renamed broken " + hdr +
                                 " to X-Broken-" + hdr + "\n")
                need_rewrite = True

    ct = part.get_content_type()
    max_name_len = 0
    params = part.get_params()
    if params:
        for (key,value) in part.get_params():
            if key in ['name', 'filename']:
                if len(value) > max_name_len:
                    max_name_len = len(value)
                
    if max_name_len > MAX_FILENAME:
        need_rewrite = True
        part_count=len(part.get_payload())
        part_str = ('Removed ' + ct +
                    ' with long filename (' + str(max_name_len) +
                    ' characters) which chokes Exchange Online')
        nuke_part(part, 1, part_str)
        return need_rewrite
        
    if part.is_multipart():
        if (drop_all_multipart_err):
            need_rewrite = True
            part_count=len(part.get_payload())
            part_str = drop_all_multipart_err
            nuke_part(part, 0, part_str)
        elif (len(part.get_payload()) > MAX_SUBPARTS):
            need_rewrite = True
            part_count=len(part.get_payload())
            part_str = ('Removed ' + ct +
                        ' with ' + str(part_count) +
                        ' subparts/attachments which chokes Exchange Online')
            nuke_part(part, 1, part_str)
        elif ct in ['multipart/appledouble']:
            need_rewrite = True
            part_str = ('Removed ' + ct +
                        ' which chokes Exchange Online')
            nuke_part(part, 1, part_str)
        else:
            for subpart in part.get_payload():
                if rewrite(subpart, drop_all_multipart_err):
                    need_rewrite = True
        return need_rewrite

    payload = part.get_payload()
    max_line_length = max_line_len(payload)

    cte     = part.get('content-transfer-encoding', '').lower().strip()
    if cte in ['8bit', '7bit', 'binary', '']:
        # Encode unencoded forms which contain 8bit characters or long lines
        update_cte = part.replace_header if (cte != '') else part.add_header
        nonascii_count = [(ord(c) >= 128) for c in payload].count(True)
        if ((NUKE_8BIT and nonascii_count > 0) or
            max_line_length > MAX_LINE_LENGTH):
            if nonascii_count < 100: 
                part.set_payload(qp_encode(payload))
                update_cte('Content-Transfer-Encoding', "quoted-printable")
            else:
                part.set_payload(utils._bencode(payload))
                update_cte('Content-Transfer-Encoding', "base64")
            need_rewrite = True
    elif (cte in ['quoted-printable', 'base64']):
        decode_error = False
        try:
            if cte == 'quoted-printable':
                raw=utils._qdecode(payload)
            else:
                raw=utils._bdecode(payload)

            if (len(payload) > 100) and (len(raw) < len(payload)/10):
                raise binascii.Error
        except binascii.Error:
            decode_error = True

        if decode_error:
            # Discard broken attachment which would no decode
            need_rewrite = True
            part_str = ('Removed ' + ct +
                        ' with broken attachment which failed to decode')
            nuke_part(part, 1, part_str)
        elif max_line_length > MAX_LINE_LENGTH:
            sys.stderr.write("FIXUP NEXT: Recoded " +
                             (cte or "none") + " attachment [Long lines]\n")

            # Recode quoted-printable or base64 with long lines
            need_rewrite = True
            if cte == 'quoted-printable':
                part.set_payload(qp_encode(raw))
            else:
                part.set_payload(utils._bencode(raw))
                
    newcte =  part.get('content-transfer-encoding', '').lower().strip()
    if (newcte and (newcte != cte)):
        part.add_header('X-Mime-Autoconverted',
                        "from " + (cte or "none") + " to " + newcte)
        if max_line_length > MAX_LINE_LENGTH:
            sys.stderr.write("FIXUP NEXT: Attachment converted " +
                             "from " + (cte or "none") + " to " + newcte +
                             " [Long lines]\n")
        else:
            sys.stderr.write("FIXUP NEXT: Attachment converted " +
                             "from " + (cte or "none") + " to " + newcte +
                             " [Raw Binary data]\n")
            
    return need_rewrite