home *** CD-ROM | disk | FTP | other *** search
/ Freelog 33 / Freelog033.iso / Progr / Python-2.2.1.exe / UTILS.PY < prev    next >
Encoding:
Python Source  |  2001-12-03  |  4.7 KB  |  153 lines

  1. # Copyright (C) 2001 Python Software Foundation
  2. # Author: barry@zope.com (Barry Warsaw)
  3.  
  4. """Miscellaneous utilities.
  5. """
  6.  
  7. import time
  8. import re
  9.  
  10. from rfc822 import unquote, quote, parseaddr
  11. from rfc822 import dump_address_pair
  12. from rfc822 import AddrlistClass as _AddrlistClass
  13. from rfc822 import parsedate_tz, parsedate, mktime_tz
  14.  
  15. from quopri import decodestring as _qdecode
  16. import base64
  17.  
  18. # Intrapackage imports
  19. from Encoders import _bencode, _qencode
  20.  
  21. COMMASPACE = ', '
  22. UEMPTYSTRING = u''
  23.  
  24.  
  25.  
  26. # Helpers
  27.  
  28. def _identity(s):
  29.     return s
  30.  
  31.  
  32. def _bdecode(s):
  33.     if not s:
  34.         return s
  35.     # We can't quite use base64.encodestring() since it tacks on a "courtesy
  36.     # newline".  Blech!
  37.     if not s:
  38.         return s
  39.     hasnewline = (s[-1] == '\n')
  40.     value = base64.decodestring(s)
  41.     if not hasnewline and value[-1] == '\n':
  42.         return value[:-1]
  43.     return value
  44.  
  45.  
  46.  
  47. def getaddresses(fieldvalues):
  48.     """Return a list of (REALNAME, EMAIL) for each fieldvalue."""
  49.     all = COMMASPACE.join(fieldvalues)
  50.     a = _AddrlistClass(all)
  51.     return a.getaddrlist()
  52.  
  53.  
  54.  
  55. ecre = re.compile(r'''
  56.   =\?                   # literal =?
  57.   (?P<charset>[^?]*?)   # non-greedy up to the next ? is the charset
  58.   \?                    # literal ?
  59.   (?P<encoding>[qb])    # either a "q" or a "b", case insensitive
  60.   \?                    # literal ?
  61.   (?P<atom>.*?)         # non-greedy up to the next ?= is the atom
  62.   \?=                   # literal ?=
  63.   ''', re.VERBOSE | re.IGNORECASE)
  64.  
  65.  
  66. def decode(s):
  67.     """Return a decoded string according to RFC 2047, as a unicode string."""
  68.     rtn = []
  69.     parts = ecre.split(s, 1)
  70.     while parts:
  71.         # If there are less than 4 parts, it can't be encoded and we're done
  72.         if len(parts) < 5:
  73.             rtn.extend(parts)
  74.             break
  75.         # The first element is any non-encoded leading text
  76.         rtn.append(parts[0])
  77.         charset = parts[1]
  78.         encoding = parts[2].lower()
  79.         atom = parts[3]
  80.         # The next chunk to decode should be in parts[4]
  81.         parts = ecre.split(parts[4])
  82.         # The encoding must be either `q' or `b', case-insensitive
  83.         if encoding == 'q':
  84.             func = _qdecode
  85.         elif encoding == 'b':
  86.             func = _bdecode
  87.         else:
  88.             func = _identity
  89.         # Decode and get the unicode in the charset
  90.         rtn.append(unicode(func(atom), charset))
  91.     # Now that we've decoded everything, we just need to join all the parts
  92.     # together into the final string.
  93.     return UEMPTYSTRING.join(rtn)
  94.  
  95.  
  96.  
  97. def encode(s, charset='iso-8859-1', encoding='q'):
  98.     """Encode a string according to RFC 2047."""
  99.     encoding = encoding.lower()
  100.     if encoding == 'q':
  101.         estr = _qencode(s)
  102.     elif encoding == 'b':
  103.         estr = _bencode(s)
  104.     else:
  105.         raise ValueError, 'Illegal encoding code: ' + encoding
  106.     return '=?%s?%s?%s?=' % (charset.lower(), encoding, estr)
  107.  
  108.  
  109.  
  110. def formatdate(timeval=None, localtime=0):
  111.     """Returns a date string as specified by RFC 2822, e.g.:
  112.  
  113.     Fri, 09 Nov 2001 01:08:47 -0000
  114.  
  115.     Optional timeval if given is a floating point time value as accepted by
  116.     gmtime() and localtime(), otherwise the current time is used.
  117.  
  118.     Optional localtime is a flag that when true, interprets timeval, and
  119.     returns a date relative to the local timezone instead of UTC, properly
  120.     taking daylight savings time into account.
  121.     """
  122.     # Note: we cannot use strftime() because that honors the locale and RFC
  123.     # 2822 requires that day and month names be the English abbreviations.
  124.     if timeval is None:
  125.         timeval = time.time()
  126.     if localtime:
  127.         now = time.localtime(timeval)
  128.         # Calculate timezone offset, based on whether the local zone has
  129.         # daylight savings time, and whether DST is in effect.
  130.         if time.daylight and now[-1]:
  131.             offset = time.altzone
  132.         else:
  133.             offset = time.timezone
  134.         hours, minutes = divmod(abs(offset), 3600)
  135.         # Remember offset is in seconds west of UTC, but the timezone is in
  136.         # minutes east of UTC, so the signs differ.
  137.         if offset > 0:
  138.             sign = '-'
  139.         else:
  140.             sign = '+'
  141.         zone = '%s%02d%02d' % (sign, hours, minutes / 60)
  142.     else:
  143.         now = time.gmtime(timeval)
  144.         # Timezone offset is always -0000
  145.         zone = '-0000'
  146.     return '%s, %02d %s %04d %02d:%02d:%02d %s' % (
  147.         ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'][now[6]],
  148.         now[2],
  149.         ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
  150.          'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][now[1] - 1],
  151.         now[0], now[3], now[4], now[5],
  152.         zone)
  153.