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