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
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
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
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
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
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
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
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
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
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