Home | History | Annotate | Download | only in plat-mac
      1 """IC wrapper module, based on Internet Config 1.3"""
      2 
      3 from warnings import warnpy3k
      4 warnpy3k("In 3.x, the ic module is removed.", stacklevel=2)
      5 
      6 import icglue
      7 import string
      8 import sys
      9 import os
     10 from Carbon import Res
     11 import Carbon.File
     12 import macostools
     13 
     14 error=icglue.error
     15 
     16 # From ictypes.h:
     17 icPrefNotFoundErr = -666        # preference not found (duh!)
     18 icPermErr = -667                # cannot set preference
     19 icPrefDataErr = -668            # problem with preference data
     20 icInternalErr = -669            # hmm, this is not good
     21 icTruncatedErr = -670           # more data was present than was returned
     22 icNoMoreWritersErr = -671       # you cannot begin a write session because someone else is already doing it */
     23 icNothingToOverrideErr = -672   # no component for the override component to capture
     24 icNoURLErr = -673               # no URL found
     25 icConfigNotFoundErr = -674      # no configuration was found
     26 icConfigInappropriateErr = -675 # incorrect manufacturer code
     27 
     28 ICattr_no_change = -1
     29 
     30 icNoPerm = 0
     31 icReadOnlyPerm = 1
     32 icReadWritePerm = 2
     33 # End of ictypes.h
     34 
     35 class ICOpaqueData:
     36     """An unparseable IC entry"""
     37     def __init__(self, data):
     38         self.data = data
     39 
     40     def __repr__(self):
     41         return "ICOpaqueData(%r)"%(self.data,)
     42 
     43 _ICOpaqueDataType=type(ICOpaqueData(''))
     44 
     45 def _decode_default(data, key):
     46     if len(data) == 0:
     47         return data
     48     if ord(data[0]) == len(data)-1:
     49         # Assume Pstring
     50         return data[1:]
     51     return ICOpaqueData(data)
     52 
     53 
     54 def _decode_multistr(data, key):
     55     numstr = ord(data[0]) << 8 | ord(data[1])
     56     rv = []
     57     ptr = 2
     58     for i in range(numstr):
     59         strlen = ord(data[ptr])
     60         str = data[ptr+1:ptr+strlen+1]
     61         rv.append(str)
     62         ptr = ptr + strlen + 1
     63     return rv
     64 
     65 def _decode_fontrecord(data, key):
     66     size = ord(data[0]) << 8 | ord(data[1])
     67     face = ord(data[2])
     68     namelen = ord(data[4])
     69     return size, face, data[5:5+namelen]
     70 
     71 def _decode_boolean(data, key):
     72     return ord(data[0])
     73 
     74 def _decode_text(data, key):
     75     return data
     76 
     77 def _decode_charset(data, key):
     78     return data[:256], data[256:]
     79 
     80 def _decode_appspec(data, key):
     81     namelen = ord(data[4])
     82     return data[0:4], data[5:5+namelen]
     83 
     84 def _code_default(data, key):
     85     return chr(len(data)) + data
     86 
     87 def _code_multistr(data, key):
     88     numstr = len(data)
     89     rv = chr((numstr>>8) & 0xff) + chr(numstr & 0xff)
     90     for i in data:
     91         rv = rv + _code_default(i)
     92     return rv
     93 
     94 def _code_fontrecord(data, key):
     95     size, face, name = data
     96     return chr((size>>8) & 0xff) + chr(size & 0xff) + chr(face & 0xff) + \
     97         chr(0) + _code_default(name)
     98 
     99 def _code_boolean(data, key):
    100     print 'XXXX boolean:', repr(data)
    101     return chr(data)
    102 
    103 def _code_text(data, key):
    104     return data
    105 
    106 def _code_charset(data, key):
    107     return data[0] + data[1]
    108 
    109 def _code_appspec(data, key):
    110     return data[0] + _code_default(data[1])
    111 
    112 _decoder_table = {
    113     "ArchieAll" : (_decode_multistr , _code_multistr),
    114     "UMichAll" : (_decode_multistr , _code_multistr),
    115     "InfoMacAll" : (_decode_multistr , _code_multistr),
    116     "ListFont" : (_decode_fontrecord , _code_fontrecord),
    117     "ScreenFont" : (_decode_fontrecord , _code_fontrecord),
    118     "PrinterFont" : (_decode_fontrecord , _code_fontrecord),
    119 #   "DownloadFolder" : (_decode_filespec , _code_filespec),
    120     "Signature": (_decode_text , _code_text),
    121     "Plan" : (_decode_text , _code_text),
    122     "MailHeaders" : (_decode_text , _code_text),
    123     "NewsHeaders" : (_decode_text , _code_text),
    124 #   "Mapping"
    125     "CharacterSet" : (_decode_charset , _code_charset),
    126     "Helper\245" : (_decode_appspec , _code_appspec),
    127 #   "Services" : (_decode_services, ????),
    128     "NewMailFlashIcon" : (_decode_boolean , _code_boolean),
    129     "NewMailDialog" : (_decode_boolean , _code_boolean),
    130     "NewMailPlaySound" : (_decode_boolean , _code_boolean),
    131 #   "WebBackgroundColor" : _decode_color,
    132     "NoProxyDomains" : (_decode_multistr , _code_multistr),
    133     "UseHTTPProxy" : (_decode_boolean , _code_boolean),
    134     "UseGopherProxy": (_decode_boolean , _code_boolean),
    135     "UseFTPProxy" : (_decode_boolean , _code_boolean),
    136     "UsePassiveFTP" : (_decode_boolean , _code_boolean),
    137 }
    138 
    139 def _decode(data, key):
    140     if '\245' in key:
    141         key2 = key[:string.index(key, '\245')+1]
    142     else:
    143         key2 = key
    144     if key2 in _decoder_table:
    145         decoder = _decoder_table[key2][0]
    146     else:
    147         decoder = _decode_default
    148     return decoder(data, key)
    149 
    150 def _code(data, key):
    151     if type(data) == _ICOpaqueDataType:
    152         return data.data
    153     if '\245' in key:
    154         key2 = key[:string.index(key, '\245')+1]
    155     else:
    156         key2 = key
    157     if key2 in _decoder_table:
    158         coder = _decoder_table[key2][1]
    159     else:
    160         coder = _code_default
    161     return coder(data, key)
    162 
    163 class IC:
    164     def __init__(self, signature='Pyth', ic=None):
    165         if ic:
    166             self.ic = ic
    167         else:
    168             self.ic = icglue.ICStart(signature)
    169             if hasattr(self.ic, 'ICFindConfigFile'):
    170                 self.ic.ICFindConfigFile()
    171         self.h = Res.Resource('')
    172 
    173     def keys(self):
    174         rv = []
    175         self.ic.ICBegin(icReadOnlyPerm)
    176         num = self.ic.ICCountPref()
    177         for i in range(num):
    178             rv.append(self.ic.ICGetIndPref(i+1))
    179         self.ic.ICEnd()
    180         return rv
    181 
    182     def has_key(self, key):
    183         return self.__contains__(key)
    184 
    185     def __contains__(self, key):
    186         try:
    187             dummy = self.ic.ICFindPrefHandle(key, self.h)
    188         except icglue.error:
    189             return 0
    190         return 1
    191 
    192     def __getitem__(self, key):
    193         attr = self.ic.ICFindPrefHandle(key, self.h)
    194         return _decode(self.h.data, key)
    195 
    196     def __setitem__(self, key, value):
    197         value = _code(value, key)
    198         self.ic.ICSetPref(key, ICattr_no_change, value)
    199 
    200     def launchurl(self, url, hint=""):
    201         # Work around a bug in ICLaunchURL: file:/foo does
    202         # not work but file:///foo does.
    203         if url[:6] == 'file:/' and url[6] != '/':
    204             url = 'file:///' + url[6:]
    205         self.ic.ICLaunchURL(hint, url, 0, len(url))
    206 
    207     def parseurl(self, data, start=None, end=None, hint=""):
    208         if start is None:
    209             selStart = 0
    210             selEnd = len(data)
    211         else:
    212             selStart = selEnd = start
    213         if end is not None:
    214             selEnd = end
    215         selStart, selEnd = self.ic.ICParseURL(hint, data, selStart, selEnd, self.h)
    216         return self.h.data, selStart, selEnd
    217 
    218     def mapfile(self, file):
    219         if type(file) != type(''):
    220             file = file.as_tuple()[2]
    221         return self.ic.ICMapFilename(file)
    222 
    223     def maptypecreator(self, type, creator, filename=""):
    224         return self.ic.ICMapTypeCreator(type, creator, filename)
    225 
    226     def settypecreator(self, file):
    227         file = Carbon.File.pathname(file)
    228         record = self.mapfile(os.path.split(file)[1])
    229         MacOS.SetCreatorAndType(file, record[2], record[1])
    230         macostools.touched(fss)
    231 
    232 # Convenience routines
    233 _dft_ic = None
    234 
    235 def launchurl(url, hint=""):
    236     global _dft_ic
    237     if _dft_ic is None: _dft_ic = IC()
    238     return _dft_ic.launchurl(url, hint)
    239 
    240 def parseurl(data, start=None, end=None, hint=""):
    241     global _dft_ic
    242     if _dft_ic is None: _dft_ic = IC()
    243     return _dft_ic.parseurl(data, start, end, hint)
    244 
    245 def mapfile(filename):
    246     global _dft_ic
    247     if _dft_ic is None: _dft_ic = IC()
    248     return _dft_ic.mapfile(filename)
    249 
    250 def maptypecreator(type, creator, filename=""):
    251     global _dft_ic
    252     if _dft_ic is None: _dft_ic = IC()
    253     return _dft_ic.maptypecreator(type, creator, filename)
    254 
    255 def settypecreator(file):
    256     global _dft_ic
    257     if _dft_ic is None: _dft_ic = IC()
    258     return _dft_ic.settypecreator(file)
    259 
    260 def _test():
    261     ic = IC()
    262     for k in ic.keys():
    263         try:
    264             v = ic[k]
    265         except error:
    266             v = '????'
    267         print k, '\t', v
    268     sys.exit(1)
    269 
    270 if __name__ == '__main__':
    271     _test()
    272