183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Copyright (C) 2001-2010 Python Software Foundation 283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Author: Barry Warsaw 383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Contact: email-sig@python.org 483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh"""Miscellaneous utilities.""" 683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh__all__ = [ 883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 'collapse_rfc2231_value', 983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 'decode_params', 1083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 'decode_rfc2231', 1183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 'encode_rfc2231', 1283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 'formataddr', 1383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 'formatdate', 1483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 'getaddresses', 1583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 'make_msgid', 1683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 'mktime_tz', 1783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 'parseaddr', 1883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 'parsedate', 1983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 'parsedate_tz', 2083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 'unquote', 2183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ] 2283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 2383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehimport os 2483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehimport re 2583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehimport time 2683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehimport base64 2783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehimport random 2883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehimport socket 2983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehimport urllib 3083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehimport warnings 3183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 3283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehfrom email._parseaddr import quote 3383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehfrom email._parseaddr import AddressList as _AddressList 3483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehfrom email._parseaddr import mktime_tz 3583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 3683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# We need wormarounds for bugs in these methods in older Pythons (see below) 3783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehfrom email._parseaddr import parsedate as _parsedate 3883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehfrom email._parseaddr import parsedate_tz as _parsedate_tz 3983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 4083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehfrom quopri import decodestring as _qdecode 4183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 4283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Intrapackage imports 4383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehfrom email.encoders import _bencode, _qencode 4483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 4583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehCOMMASPACE = ', ' 4683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehEMPTYSTRING = '' 4783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehUEMPTYSTRING = u'' 4883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehCRLF = '\r\n' 4983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehTICK = "'" 5083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 5183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehspecialsre = re.compile(r'[][\\()<>@,:;".]') 5283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehescapesre = re.compile(r'[][\\()"]') 5383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 5483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 5583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 5683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Helpers 5783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 5883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef _identity(s): 5983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return s 6083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 6183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 6283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef _bdecode(s): 6383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Decodes a base64 string. 6483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 6583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh This function is equivalent to base64.decodestring and it's retained only 6683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for backward compatibility. It used to remove the last \\n of the decoded 6783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh string, if it had any (see issue 7143). 6883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 6983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if not s: 7083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return s 7183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return base64.decodestring(s) 7283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 7383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 7483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 7583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef fix_eols(s): 7683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Replace all line-ending characters with \\r\\n.""" 7783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Fix newlines with no preceding carriage return 7883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh s = re.sub(r'(?<!\r)\n', CRLF, s) 7983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Fix carriage returns with no following newline 8083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh s = re.sub(r'\r(?!\n)', CRLF, s) 8183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return s 8283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 8383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 8483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 8583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef formataddr(pair): 8683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """The inverse of parseaddr(), this takes a 2-tuple of the form 8783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh (realname, email_address) and returns the string value suitable 8883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for an RFC 2822 From, To or Cc header. 8983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 9083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh If the first element of pair is false, then the second element is 9183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh returned unmodified. 9283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 9383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh name, address = pair 9483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if name: 9583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh quotes = '' 9683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if specialsre.search(name): 9783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh quotes = '"' 9883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh name = escapesre.sub(r'\\\g<0>', name) 9983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return '%s%s%s <%s>' % (quotes, name, quotes, address) 10083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return address 10183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 10283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 10383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 10483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef getaddresses(fieldvalues): 10583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Return a list of (REALNAME, EMAIL) for each fieldvalue.""" 10683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh all = COMMASPACE.join(fieldvalues) 10783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh a = _AddressList(all) 10883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return a.addresslist 10983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 11083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 11183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 11283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehecre = re.compile(r''' 11383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh =\? # literal =? 11483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh (?P<charset>[^?]*?) # non-greedy up to the next ? is the charset 11583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh \? # literal ? 11683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh (?P<encoding>[qb]) # either a "q" or a "b", case insensitive 11783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh \? # literal ? 11883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh (?P<atom>.*?) # non-greedy up to the next ?= is the atom 11983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh \?= # literal ?= 12083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ''', re.VERBOSE | re.IGNORECASE) 12183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 12283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 12383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 12483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef formatdate(timeval=None, localtime=False, usegmt=False): 12583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Returns a date string as specified by RFC 2822, e.g.: 12683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 12783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Fri, 09 Nov 2001 01:08:47 -0000 12883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 12983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Optional timeval if given is a floating point time value as accepted by 13083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh gmtime() and localtime(), otherwise the current time is used. 13183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 13283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Optional localtime is a flag that when True, interprets timeval, and 13383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh returns a date relative to the local timezone instead of UTC, properly 13483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh taking daylight savings time into account. 13583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 13683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Optional argument usegmt means that the timezone is written out as 13783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh an ascii string, not numeric one (so "GMT" instead of "+0000"). This 13883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh is needed for HTTP, and is only used when localtime==False. 13983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 14083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Note: we cannot use strftime() because that honors the locale and RFC 14183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # 2822 requires that day and month names be the English abbreviations. 14283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if timeval is None: 14383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh timeval = time.time() 14483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if localtime: 14583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh now = time.localtime(timeval) 14683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Calculate timezone offset, based on whether the local zone has 14783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # daylight savings time, and whether DST is in effect. 14883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if time.daylight and now[-1]: 14983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh offset = time.altzone 15083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 15183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh offset = time.timezone 15283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh hours, minutes = divmod(abs(offset), 3600) 15383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Remember offset is in seconds west of UTC, but the timezone is in 15483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # minutes east of UTC, so the signs differ. 15583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if offset > 0: 15683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh sign = '-' 15783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 15883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh sign = '+' 15983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh zone = '%s%02d%02d' % (sign, hours, minutes // 60) 16083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 16183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh now = time.gmtime(timeval) 16283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Timezone offset is always -0000 16383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if usegmt: 16483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh zone = 'GMT' 16583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 16683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh zone = '-0000' 16783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return '%s, %02d %s %04d %02d:%02d:%02d %s' % ( 16883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'][now[6]], 16983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh now[2], 17083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 17183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][now[1] - 1], 17283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh now[0], now[3], now[4], now[5], 17383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh zone) 17483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 17583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 17683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 17783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef make_msgid(idstring=None): 17883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Returns a string suitable for RFC 2822 compliant Message-ID, e.g: 17983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 18083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh <20020201195627.33539.96671@nightshade.la.mastaler.com> 18183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 18283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Optional idstring if given is a string used to strengthen the 18383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh uniqueness of the message id. 18483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 18583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh timeval = time.time() 18683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh utcdate = time.strftime('%Y%m%d%H%M%S', time.gmtime(timeval)) 18783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh pid = os.getpid() 18883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh randint = random.randrange(100000) 18983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if idstring is None: 19083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh idstring = '' 19183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 19283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh idstring = '.' + idstring 19383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh idhost = socket.getfqdn() 19483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh msgid = '<%s.%s.%s%s@%s>' % (utcdate, pid, randint, idstring, idhost) 19583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return msgid 19683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 19783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 19883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 19983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# These functions are in the standalone mimelib version only because they've 20083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# subsequently been fixed in the latest Python versions. We use this to worm 20183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# around broken older Pythons. 20283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef parsedate(data): 20383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if not data: 20483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return None 20583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return _parsedate(data) 20683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 20783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 20883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef parsedate_tz(data): 20983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if not data: 21083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return None 21183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return _parsedate_tz(data) 21283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 21383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 21483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef parseaddr(addr): 21583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh addrs = _AddressList(addr).addresslist 21683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if not addrs: 21783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return '', '' 21883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return addrs[0] 21983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 22083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 22183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# rfc822.unquote() doesn't properly de-backslash-ify in Python pre-2.3. 22283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef unquote(str): 22383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Remove quotes from a string.""" 22483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if len(str) > 1: 22583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if str.startswith('"') and str.endswith('"'): 22683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return str[1:-1].replace('\\\\', '\\').replace('\\"', '"') 22783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if str.startswith('<') and str.endswith('>'): 22883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return str[1:-1] 22983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return str 23083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 23183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 23283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 23383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# RFC2231-related functions - parameter encoding and decoding 23483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef decode_rfc2231(s): 23583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Decode string according to RFC 2231""" 23683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh parts = s.split(TICK, 2) 23783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if len(parts) <= 2: 23883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return None, None, s 23983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return parts 24083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 24183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 24283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef encode_rfc2231(s, charset=None, language=None): 24383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Encode string according to RFC 2231. 24483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 24583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh If neither charset nor language is given, then s is returned as-is. If 24683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh charset is given but not language, the string is encoded using the empty 24783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh string for language. 24883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 24983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh import urllib 25083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh s = urllib.quote(s, safe='') 25183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if charset is None and language is None: 25283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return s 25383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if language is None: 25483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh language = '' 25583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return "%s'%s'%s" % (charset, language, s) 25683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 25783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 25883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehrfc2231_continuation = re.compile(r'^(?P<name>\w+)\*((?P<num>[0-9]+)\*?)?$') 25983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 26083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef decode_params(params): 26183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Decode parameters list according to RFC 2231. 26283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 26383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh params is a sequence of 2-tuples containing (param name, string value). 26483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 26583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Copy params so we don't mess with the original 26683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh params = params[:] 26783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh new_params = [] 26883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Map parameter's name to a list of continuations. The values are a 26983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # 3-tuple of the continuation number, the string value, and a flag 27083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # specifying whether a particular segment is %-encoded. 27183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh rfc2231_params = {} 27283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh name, value = params.pop(0) 27383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh new_params.append((name, value)) 27483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh while params: 27583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh name, value = params.pop(0) 27683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if name.endswith('*'): 27783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh encoded = True 27883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 27983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh encoded = False 28083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh value = unquote(value) 28183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh mo = rfc2231_continuation.match(name) 28283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if mo: 28383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh name, num = mo.group('name', 'num') 28483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if num is not None: 28583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh num = int(num) 28683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh rfc2231_params.setdefault(name, []).append((num, value, encoded)) 28783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 28883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh new_params.append((name, '"%s"' % quote(value))) 28983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if rfc2231_params: 29083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for name, continuations in rfc2231_params.items(): 29183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh value = [] 29283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh extended = False 29383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Sort by number 29483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh continuations.sort() 29583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # And now append all values in numerical order, converting 29683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # %-encodings for the encoded segments. If any of the 29783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # continuation names ends in a *, then the entire string, after 29883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # decoding segments and concatenating, must have the charset and 29983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # language specifiers at the beginning of the string. 30083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for num, s, encoded in continuations: 30183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if encoded: 30283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh s = urllib.unquote(s) 30383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh extended = True 30483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh value.append(s) 30583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh value = quote(EMPTYSTRING.join(value)) 30683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if extended: 30783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh charset, language, value = decode_rfc2231(value) 30883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh new_params.append((name, (charset, language, '"%s"' % value))) 30983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 31083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh new_params.append((name, '"%s"' % value)) 31183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return new_params 31283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 31383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef collapse_rfc2231_value(value, errors='replace', 31483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh fallback_charset='us-ascii'): 31583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if isinstance(value, tuple): 31683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh rawval = unquote(value[2]) 31783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh charset = value[0] or 'us-ascii' 31883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh try: 31983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return unicode(rawval, charset, errors) 32083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh except LookupError: 32183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # XXX charset is unknown to Python. 32283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return unicode(rawval, fallback_charset, errors) 32383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 32483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return unquote(value) 325