utils.py (6223B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\stdlib\email\utils.py 2 __all__ = ['collapse_rfc2231_value', 3 'decode_params', 4 'decode_rfc2231', 5 'encode_rfc2231', 6 'formataddr', 7 'formatdate', 8 'getaddresses', 9 'make_msgid', 10 'mktime_tz', 11 'parseaddr', 12 'parsedate', 13 'parsedate_tz', 14 'unquote'] 15 import os 16 import re 17 import time 18 import base64 19 import random 20 import socket 21 import urllib 22 import warnings 23 from email._parseaddr import quote 24 from email._parseaddr import AddressList as _AddressList 25 from email._parseaddr import mktime_tz 26 from email._parseaddr import parsedate as _parsedate 27 from email._parseaddr import parsedate_tz as _parsedate_tz 28 from quopri import decodestring as _qdecode 29 from email.encoders import _bencode, _qencode 30 COMMASPACE = ', ' 31 EMPTYSTRING = '' 32 UEMPTYSTRING = u'' 33 CRLF = '\r\n' 34 TICK = "'" 35 specialsre = re.compile('[][\\\\()<>@,:;".]') 36 escapesre = re.compile('[][\\\\()"]') 37 38 def _identity(s): 39 return s 40 41 42 def _bdecode(s): 43 if not s: 44 return s 45 return base64.decodestring(s) 46 47 48 def fix_eols(s): 49 s = re.sub('(?<!\\r)\\n', CRLF, s) 50 s = re.sub('\\r(?!\\n)', CRLF, s) 51 return s 52 53 54 def formataddr(pair): 55 name, address = pair 56 if name: 57 quotes = '' 58 if specialsre.search(name): 59 quotes = '"' 60 name = escapesre.sub('\\\\\\g<0>', name) 61 return '%s%s%s <%s>' % (quotes, 62 name, 63 quotes, 64 address) 65 return address 66 67 68 def getaddresses(fieldvalues): 69 all = COMMASPACE.join(fieldvalues) 70 a = _AddressList(all) 71 return a.addresslist 72 73 74 ecre = re.compile('\n =\\? # literal =?\n (?P<charset>[^?]*?) # non-greedy up to the next ? is the charset\n \\? # literal ?\n (?P<encoding>[qb]) # either a "q" or a "b", case insensitive\n \\? # literal ?\n (?P<atom>.*?) # non-greedy up to the next ?= is the atom\n \\?= # literal ?=\n ', re.VERBOSE | re.IGNORECASE) 75 76 def formatdate(timeval = None, localtime = False, usegmt = False): 77 if timeval is None: 78 timeval = time.time() 79 if localtime: 80 now = time.localtime(timeval) 81 if time.daylight and now[-1]: 82 offset = time.altzone 83 else: 84 offset = time.timezone 85 hours, minutes = divmod(abs(offset), 3600) 86 if offset > 0: 87 sign = '-' 88 else: 89 sign = '+' 90 zone = '%s%02d%02d' % (sign, hours, minutes // 60) 91 else: 92 now = time.gmtime(timeval) 93 if usegmt: 94 zone = 'GMT' 95 else: 96 zone = '-0000' 97 return '%s, %02d %s %04d %02d:%02d:%02d %s' % (['Mon', 98 'Tue', 99 'Wed', 100 'Thu', 101 'Fri', 102 'Sat', 103 'Sun'][now[6]], 104 now[2], 105 ['Jan', 106 'Feb', 107 'Mar', 108 'Apr', 109 'May', 110 'Jun', 111 'Jul', 112 'Aug', 113 'Sep', 114 'Oct', 115 'Nov', 116 'Dec'][now[1] - 1], 117 now[0], 118 now[3], 119 now[4], 120 now[5], 121 zone) 122 123 124 def make_msgid(idstring = None): 125 timeval = time.time() 126 utcdate = time.strftime('%Y%m%d%H%M%S', time.gmtime(timeval)) 127 pid = os.getpid() 128 randint = random.randrange(100000) 129 if idstring is None: 130 idstring = '' 131 else: 132 idstring = '.' + idstring 133 idhost = socket.getfqdn() 134 msgid = '<%s.%s.%s%s@%s>' % (utcdate, 135 pid, 136 randint, 137 idstring, 138 idhost) 139 return msgid 140 141 142 def parsedate(data): 143 if not data: 144 return None 145 return _parsedate(data) 146 147 148 def parsedate_tz(data): 149 if not data: 150 return None 151 return _parsedate_tz(data) 152 153 154 def parseaddr(addr): 155 addrs = _AddressList(addr).addresslist 156 if not addrs: 157 return ('', '') 158 return addrs[0] 159 160 161 def unquote(str): 162 if len(str) > 1: 163 if str.startswith('"') and str.endswith('"'): 164 return str[1:-1].replace('\\\\', '\\').replace('\\"', '"') 165 if str.startswith('<') and str.endswith('>'): 166 return str[1:-1] 167 return str 168 169 170 def decode_rfc2231(s): 171 parts = s.split(TICK, 2) 172 if len(parts) <= 2: 173 return (None, None, s) 174 return parts 175 176 177 def encode_rfc2231(s, charset = None, language = None): 178 import urllib 179 s = urllib.quote(s, safe='') 180 if charset is None and language is None: 181 return s 182 if language is None: 183 language = '' 184 return "%s'%s'%s" % (charset, language, s) 185 186 187 rfc2231_continuation = re.compile('^(?P<name>\\w+)\\*((?P<num>[0-9]+)\\*?)?$') 188 189 def decode_params(params): 190 params = params[:] 191 new_params = [] 192 rfc2231_params = {} 193 name, value = params.pop(0) 194 new_params.append((name, value)) 195 while params: 196 name, value = params.pop(0) 197 if name.endswith('*'): 198 encoded = True 199 else: 200 encoded = False 201 value = unquote(value) 202 mo = rfc2231_continuation.match(name) 203 if mo: 204 name, num = mo.group('name', 'num') 205 if num is not None: 206 num = int(num) 207 rfc2231_params.setdefault(name, []).append((num, value, encoded)) 208 else: 209 new_params.append((name, '"%s"' % quote(value))) 210 211 if rfc2231_params: 212 for name, continuations in rfc2231_params.items(): 213 value = [] 214 extended = False 215 continuations.sort() 216 for num, s, encoded in continuations: 217 if encoded: 218 s = urllib.unquote(s) 219 extended = True 220 value.append(s) 221 222 value = quote(EMPTYSTRING.join(value)) 223 if extended: 224 charset, language, value = decode_rfc2231(value) 225 new_params.append((name, (charset, language, '"%s"' % value))) 226 else: 227 new_params.append((name, '"%s"' % value)) 228 229 return new_params 230 231 232 def collapse_rfc2231_value(value, errors = 'replace', fallback_charset = 'us-ascii'): 233 if isinstance(value, tuple): 234 rawval = unquote(value[2]) 235 charset = value[0] or 'us-ascii' 236 try: 237 return unicode(rawval, charset, errors) 238 except LookupError: 239 return unicode(rawval, fallback_charset, errors) 240 241 else: 242 return unquote(value)