0001 #!/usr/bin/env python 0002 0003 ### BITPIM 0004 ### 0005 ### 0006 ### 0007 ### This program is free software; you can redistribute it and/or modify 0008 ### it under the terms of the BitPim license as detailed in the LICENSE file. 0009 ### by David Ritter 7/10/07 0010 ### Write to phonebook working msg ringtones not supported 0011 ### Write to Calendar, wallpaper, and ringtones is working 0012 ### 0013 ### $Id: com_lgax8600.py 4595 2008-02-14 03:04:01Z djpham $ 0014 0015 """ 0016 Communicate with the LG AX8600 cell phone 0017 """ 0018 # standard modules 0019 import re 0020 import time 0021 import cStringIO 0022 import sha 0023 import datetime 0024 0025 # BitPim modules 0026 import common 0027 import commport 0028 import fileinfo 0029 import guihelper 0030 import os 0031 import copy 0032 import com_lgvx4400 0033 import p_brew 0034 import p_lgax8600 0035 import com_lgvx8100 0036 import com_brew 0037 import com_phone 0038 import com_lg 0039 import prototypes 0040 import bpcalendar 0041 import call_history 0042 import sms 0043 import memo 0044 import playlist 0045 import helpids 0046 0047 #------------------------------------------------------------------------------- 0048 #Went back to vx8100 to inherit to avoid LGUncountedIndexedMedia 0049 0050 parentphone=com_lgvx8100.Phone 0051 class Phone(parentphone): 0052 "Talk to LG AX-8600 cell phone" 0053 0054 desc="LG-AX8600" 0055 helpid=helpids.ID_PHONE_LGAX8600 0056 protocolclass=p_lgax8600 0057 serialsname='lgax8600' 0058 0059 external_storage_root='mmc1/' 0060 0061 my_model='AX8600' 0062 #Media locations for reading FROM the phone 0063 builtinringtones= () 0064 ringtonelocations= ( 0065 # type index-file size-file directory-to-use lowest-index-to-use maximum-entries type-major icon index_offset 0066 0067 ( 'sounds', 'dload/lg_mysound.dat', 'dload/lg_mysoundsize.dat', 'brew/media/lk/ms', 150, 100, 0x402, 0, 0), 0068 0069 # ( 'sounds(sd)', 'dload/sd_sound.dat', 'mmc1/lg_media/other_sounds', '', 100, 0x02, None), 0070 0071 ) 0072 0073 calendarlocation="sch/schedule.dat" 0074 calendarexceptionlocation="sch/schexception.dat" 0075 calenderrequiresreboot=1 0076 memolocation="sch/memo.dat" 0077 0078 builtinwallpapers = () 0079 wallpaperlocations= ( 0080 0081 # type index-file size-file directory-to-use lowest-index-to-use maximum-entries type-major icon index_offset 0082 ( 'images', 'dload/lg_image.dat', 'dload/lg_imagesize.dat', 'brew/media/lk/mp', 150 , 100, 0x400, 0, 0), 0083 0084 # ( 'images(sd)', 'dload/sd_image.dat', 'mmc1/lg_media/other_image', '', 100, 0x10, None), 0085 # ( 'video', 'dload/lg_video.dat', 'brew/media/lk/mf', '', 100, 0x10, None), 0086 # ( 'video(sd)', 'dload/sd_video.dat', 'mmc1/lg_media/other_video', '', 100, 0x13, None), 0087 ) 0088 # _rs_path=() 0089 # for removable media (miniSD cards) 0090 _rs_path='mmc1/' 0091 _rs_ringers_path=_rs_path+'lg_media/other_sounds' 0092 _rs_images_path=_rs_path+'lg_media/other_image' 0093 0094 #Media locations for writing TO the phone 0095 0096 media_info={ 'sounds': { 0097 'localpath': 'brew/media/lk/ms', 0098 'rspath': None, 0099 'vtype': protocolclass.MEDIA_TYPE_SOUND, 0100 'icon': protocolclass.MEDIA_IMAGE_DEFAULT_ICON, 0101 'index': 150, 0102 'maxsize': 100, 0103 'indexfile': 'dload/lg_mysound.dat', 0104 'sizefile': 'dload/lg_mysoundsize.dat', 0105 'dunno': 0, 0106 'date': False, 0107 'dunno1': 0 }, 0108 'images': { 0109 'localpath': 'brew/media/lk/mp', 0110 'rspath': None, 0111 'vtype': protocolclass.MEDIA_TYPE_IMAGE, 0112 'icon': protocolclass.MEDIA_IMAGE_DEFAULT_ICON, 0113 'index': 150, 0114 'maxsize': 100, 0115 'indexfile': 'dload/lg_image.dat', 0116 'sizefile': 'dload/lg_imagesize.dat', 0117 'dunno': 0, 0118 'date': False, 0119 'dunno1': 0 }, 0120 # 'video': { 0121 # 'localpath': 'brew/16452/mf', 0122 # 'rspath': None, 0123 # 'vtype': protocolclass.MEDIA_TYPE_VIDEO, 0124 # 'icon': protocolclass.MEDIA_VIDEO_DEFAULT_ICON, 0125 # 'index': 1000, 0126 # 'maxsize': 155, 0127 # 'indexfile': 'dload/video.dat', 0128 # 'sizefile': 'dload/videosize.dat', 0129 # 'dunno': 0, 'date': True }, 0130 } 0131 0132 0133 0134 def __init__(self, logtarget, commport): 0135 parentphone.__init__(self, logtarget, commport) 0136 p_brew.PHONE_ENCODING=self.protocolclass.PHONE_ENCODING 0137 self.mode=self.MODENONE 0138 0139 0140 def setDMversion(self): 0141 self._DMv5=True 0142 self._timeout = 30 0143 0144 def get_esn(self, data=None): 0145 # return the ESN of this phone 0146 return self.get_brew_esn() 0147 0148 def get_detect_data(self, res): 0149 com_lgvx8100.Phone.get_detect_data(self, res) 0150 res[self.esn_file_key]=self.get_esn() 0151 0152 #------------------------------------------------------ 0153 # must be included for difference between alltel and verizon 0154 def getcallhistory(self, result): 0155 res={} 0156 # read the incoming call history file 0157 # the telus lg8100 programmers were on something when they wrote their code. 0158 if hasattr(self.protocolclass, 'this_takes_the_prize_for_the_most_brain_dead_call_history_file_naming_ive_seen'): 0159 self._readhistoryfile("pim/missed_log.dat", 'Incoming', res) 0160 self._readhistoryfile("pim/outgoing_log.dat", 'Missed', res) 0161 self._readhistoryfile("pim/incoming_log.dat", 'Outgoing', res) 0162 else: 0163 self._readhistoryfile("pim/missed_log.dat", 'Missed', res) 0164 self._readhistoryfile("pim/outgoing_log.dat", 'Outgoing', res) 0165 self._readhistoryfile("pim/incoming_log.dat", 'Incoming', res) 0166 self._readhistoryfile("pim/data_log.data", 'Data', res) 0167 result['call_history']=res 0168 return result 0169 0170 # Don't need this if there're no changes 0171 ## def _readhistoryfile(self, fname, folder, res): 0172 ## try: 0173 ## buf=prototypes.buffer(self.getfilecontents(fname)) 0174 ## ch=self.protocolclass.callhistory() 0175 ## ch.readfrombuffer(buf, logtitle="Call History") 0176 ## for call_idx in range(ch.numcalls): 0177 ## call=ch.calls[call_idx] 0178 ## if call.number=='' and call.name=='': 0179 ## continue 0180 ## entry=call_history.CallHistoryEntry() 0181 ## entry.folder=folder 0182 ## if call.duration: 0183 ## entry.duration=call.duration 0184 ## entry.datetime=((call.GPStime)) 0185 ## if call.number=='': # restricted calls have no number 0186 ## entry.number=call.name 0187 ## else: 0188 ## entry.number=call.number 0189 ## if call.name: 0190 ## entry.name=call.name 0191 ## res[entry.id]=entry 0192 ## except (com_brew.BrewNoSuchFileException, 0193 ## IndexError): 0194 ## pass # do nothing if file doesn't exist or is corrupted 0195 ## return 0196 0197 def getcalendar(self,result): 0198 res={} 0199 # Read exceptions file first 0200 try: 0201 buf=prototypes.buffer(self.getfilecontents(self.calendarexceptionlocation)) 0202 ex=self.protocolclass.scheduleexceptionfile() 0203 ex.readfrombuffer(buf, logtitle="Calendar exceptions") 0204 exceptions={} 0205 for i in ex.items: 0206 try: 0207 exceptions[i.pos].append( (i.year,i.month,i.day) ) 0208 except KeyError: 0209 exceptions[i.pos]=[ (i.year,i.month,i.day) ] 0210 except com_brew.BrewNoSuchFileException: 0211 exceptions={} 0212 0213 # Now read schedule 0214 try: 0215 buf=prototypes.buffer(self.getfilecontents(self.calendarlocation)) 0216 if len(buf.getdata())<3: 0217 # file is empty, and hence same as non-existent 0218 raise com_brew.BrewNoSuchFileException() 0219 sc=self.protocolclass.schedulefile() 0220 sc.readfrombuffer(buf, logtitle="Calendar") 0221 for event in sc.events: 0222 # the vx8100 has a bad entry when the calender is empty 0223 # stop processing the calender when we hit this record 0224 if event.pos==0: #invalid entry 0225 continue 0226 entry=bpcalendar.CalendarEntry() 0227 entry.desc_loc=event.description 0228 try: # delete events are still in the calender file but have garbage dates 0229 entry.start=event.start 0230 if self.protocolclass.CALENDAR_HAS_SEPARATE_END_TIME_AND_DATE: 0231 if event.repeat[0] == 0: # MIC: If non-repeating event 0232 entry.end = event.end_time # MIC: Set entry.end to full end_time 0233 else: 0234 _,_,_,hour,minute=event.end_time 0235 year,month,day,_,_=event.end_date 0236 entry.end=(year,month,day,hour,minute) 0237 else: 0238 entry.end=event.end 0239 except ValueError: 0240 continue 0241 if event.alarmindex_vibrate&0x1: 0242 entry.vibrate=0 # vibarate bit is inverted in phone 0=on, 1=off 0243 else: 0244 entry.vibrate=1 0245 entry.repeat = self.makerepeat(event.repeat) 0246 min=event.alarmminutes 0247 hour=event.alarmhours 0248 if min==0x64 or hour==0x64: 0249 entry.alarm=None # no alarm set 0250 else: 0251 entry.alarm=hour*60+min 0252 if self.protocolclass.CALENDAR_HAS_SEPARATE_END_TIME_AND_DATE: 0253 # MIC Unlike previous phones, the VX8300 passes the ringtone 0254 # via both the index, and a path. If the index is set to 100 0255 # (0x64), then the ringtone information will be found in the 0256 # "ringpath", the last 256 bytes of the calendar packet. If 0257 # the index is between 0 and 15, inclusive, then it is using 0258 # one of the builtin ringers, and the ringpath is set to 0259 # null. 0260 try: 0261 if (event.ringtone == 100): # MIC Ringer is downloaded to phone or microSD 0262 entry.ringtone = common.basename(event.ringpath) 0263 else: # MIC Ringer is built-in 0264 entry.ringtone=self.builtinringtones[event.ringtone] 0265 except: 0266 # hack, not having a phone makes it hard to figure out the best approach 0267 if entry.alarm==None: 0268 entry.ringtone='No Ring' 0269 else: 0270 entry.ringtone='Loud Beeps' 0271 else: 0272 #hack for alltel 0273 if entry.alarm==None: 0274 entry.ringtone='No Ring' 0275 else: 0276 entry.ringtone='Loud Beeps' 0277 # entry.ringtone=result['ringtone-index'][event.ringtone]['name'] ## This doesn't work on alltel 0278 entry.snoozedelay=0 0279 # check for exceptions and remove them 0280 if event.repeat[3] and exceptions.has_key(event.pos): 0281 for year, month, day in exceptions[event.pos]: 0282 entry.suppress_repeat_entry(year, month, day) 0283 res[entry.id]=entry 0284 0285 assert sc.numactiveitems==len(res) 0286 except com_brew.BrewNoSuchFileException: 0287 pass # do nothing if file doesn't exist 0288 result['calendar']=res 0289 return result 0290 0291 def _build_pb_info(self, fundamentals): 0292 # build a dict of info to update pbentry 0293 pbook=fundamentals.get('phonebook', {}) 0294 wallpaper_index=fundamentals.get('wallpaper-index', {}) 0295 ringtone_index=fundamentals.get('ringtone-index', {}) 0296 r1={} 0297 for k,e in pbook.items(): 0298 r1[e['bitpimserial']['id']]={ 'wallpaper': \ 0299 self._findmediainindex(wallpaper_index, 0300 e['wallpaper'], 0301 e['name'], 0302 'wallpaper'), 0303 'msgringtone': \ 0304 self._findmediainindex(ringtone_index, 0305 e['msgringtone'], 0306 e['name'], 0307 'message ringtone')} 0308 serialupdates=fundamentals.get("serialupdates", []) 0309 r2={} 0310 for bps, serials in serialupdates: 0311 r2[serials['serial1']]=r1[bps['id']] 0312 return r2 0313 0314 def _update_pb_file(self, pb, fundamentals, pbinfo): 0315 # update the pbentry file 0316 update_flg=False 0317 for e in pb.items: 0318 _info=pbinfo.get(e.serial1, None) 0319 if _info: 0320 wp=_info.get('wallpaper', None) 0321 if wp is not None and wp!=e.wallpaper: 0322 update_flg=True 0323 e.wallpaper=wp 0324 rt=_info.get('ringtone', None) 0325 if rt is not None and rt!=e.ringtone: 0326 update_flg=True 0327 e.ringtone=rt 0328 if update_flg: 0329 self.log('Updating wallpaper index') 0330 buf=prototypes.buffer() 0331 pb.writetobuffer(buf, logtitle="Updated index "+self.protocolclass.pb_file_name) 0332 self.writefile(self.protocolclass.pb_file_name, buf.getvalue()) 0333 0334 0335 def _update_pb_info(self, pbentries, fundamentals): 0336 # Manually update phonebook data that the normal protocol should have 0337 _pbinfo=self._build_pb_info(fundamentals) 0338 self._update_pb_file(pbentries, fundamentals, _pbinfo) 0339 0340 def _write_path_index(self, pbentries, pbmediakey, media_index, 0341 index_file, invalid_values): 0342 _path_entry=self.protocolclass.PathIndexEntry() 0343 _path_file=self.protocolclass.PathIndexFile() 0344 for _ in range(self.protocolclass.NUMPHONEBOOKENTRIES): 0345 _path_file.items.append(_path_entry) 0346 for _entry in pbentries.items: 0347 _idx=getattr(_entry, pbmediakey) 0348 if _idx in invalid_values or not media_index.has_key(_idx): 0349 continue 0350 if media_index[_idx].get('origin', None)=='builtin': 0351 _filename=media_index[_idx]['name'] 0352 elif media_index[_idx].get('filename', None): 0353 _filename=media_index[_idx]['filename'] 0354 else: 0355 continue 0356 _path_file.items[_entry.entrynumber]=self.protocolclass.PathIndexEntry( 0357 pathname=_filename) 0358 _buf=prototypes.buffer() 0359 _path_file.writetobuffer(_buf, logtitle='Writing Path ID') 0360 self.writefile(index_file, _buf.getvalue()) 0361 0362 # Must be included due to changed indexfile format 0363 def _write_index_file(self, type): 0364 _info=self.media_info.get(type, None) 0365 0366 if not _info: 0367 return 0368 _files={} 0369 _local_dir=_info['localpath'] 0370 0371 _rs_dir=_info['rspath'] 0372 _vtype=_info['vtype'] 0373 _icon=_info['icon'] 0374 _index=_info['index'] 0375 _maxsize=_info['maxsize'] 0376 _dunno=_info['dunno'] 0377 _dunno1=_info['dunno1'] 0378 indexfile=_info['indexfile'] 0379 sizefile=_info['sizefile'] 0380 _need_date=_info['date'] 0381 try: 0382 0383 _files=self.listfiles(_local_dir) 0384 except (com_brew.BrewNoSuchDirectoryException, 0385 com_brew.BrewBadPathnameException): 0386 pass 0387 try: 0388 if _rs_dir: 0389 _rs_files=self.listfiles(_rs_dir) 0390 0391 if type=='ringers': 0392 self._mark_files(_files, _rs_files, _local_dir) 0393 _files.update(_rs_files) 0394 except (com_brew.BrewNoSuchDirectoryException, 0395 com_brew.BrewBadPathnameException): 0396 # dir does not exist, no media files available 0397 pass 0398 # del all the markers (empty files) ringers 0399 if type=='ringers': 0400 _keys=_files.keys() 0401 for _key in _keys: 0402 if not _files[_key]['size']: 0403 del _files[_key] 0404 # dict of all indices 0405 _idx_keys={} 0406 for _i in xrange(_index, _index+_maxsize): 0407 _idx_keys[_i]=True 0408 # assign existing indices 0409 for _item in self.getindex(indexfile): 0410 if _files.has_key(_item.filename): 0411 0412 _files[_item.filename]['index']=_item.index 0413 _idx_keys[_item.index]=False 0414 # available new indices 0415 _idx_keys_list=[k for k,x in _idx_keys.items() if x] 0416 _idx_keys_list.sort() 0417 _idx_cnt=0 0418 # assign new indices 0419 _file_list=[x for x in _files if not _files[x].get('index', None)] 0420 _file_list.sort() 0421 0422 if len(_file_list)>len(_idx_keys_list): 0423 _file_list=_file_list[:len(_idx_keys_list)] 0424 for i in _file_list: 0425 _files[i]['index']=_idx_keys_list[_idx_cnt] 0426 _idx_cnt+=1 0427 # (index, file name) list for writing 0428 _res_list=[(x['index'],k) for k,x in _files.items() if x.get('index', None)] 0429 _res_list.sort() 0430 _res_list.reverse() 0431 0432 # writing the index file 0433 ifile=self.protocolclass.indexfile() 0434 _file_size=0 0435 for index,idx in _res_list: 0436 _fs_size=_files[idx]['size'] 0437 ie=self.protocolclass.indexentry() 0438 ie.index=index 0439 ie.type=_vtype 0440 ie.filename=idx 0441 if _need_date: 0442 # need to fill in the date value 0443 _stat=self.statfile(_files[idx]['name']) 0444 if _stat: 0445 ie.date=_stat['datevalue']-time.timezone 0446 ie.dunno=_dunno 0447 ie.dunno1=_dunno1 0448 ie.icon=_icon 0449 ie.size=_fs_size 0450 0451 ifile.items.append(ie) 0452 if not self._is_rs_file(idx): 0453 _file_size+=_fs_size 0454 buf=prototypes.buffer() 0455 0456 ifile.writetobuffer(buf, logtitle="Index file "+indexfile) 0457 self.log("Writing index file "+indexfile+" for type "+type+" with "+`len(_res_list)`+" entries.") 0458 self.writefile(indexfile, buf.getvalue()) 0459 # writing the size file 0460 if sizefile: 0461 szfile=self.protocolclass.sizefile() 0462 szfile.size=_file_size 0463 buf=prototypes.buffer() 0464 szfile.writetobuffer(buf, logtitle="Updated size file for "+type) 0465 self.log("You are using a total of "+`_file_size`+" bytes for "+type) 0466 self.writefile(sizefile, buf.getvalue()) 0467 0468 # Must be there since there are no msg ringtones on ax8600 0469 0470 def savephonebook(self, data): 0471 "Saves out the phonebook" 0472 0473 res=com_lgvx4400.Phone.savephonebook(self, data) 0474 # retrieve the phonebook entries 0475 0476 _buf=prototypes.buffer(self.getfilecontents(self.protocolclass.pb_file_name)) 0477 _pb_entries=self.protocolclass.pbfile() 0478 _pb_entries.readfrombuffer(_buf, logtitle="Read phonebook file "+self.protocolclass.pb_file_name) 0479 0480 # update info that the phone software failed to do!! 0481 self._update_pb_info(_pb_entries, data) 0482 0483 return res 0484 0485 # Misc Stuff---------------------------------------------------------------- 0486 def get_firmware_version(self): 0487 # return the firmware version 0488 req=p_brew.firmwarerequest() 0489 res=self.sendbrewcommand(req, self.protocolclass.firmwareresponse) 0490 return res.firmware 0491 0492 def _unlock_key(self): 0493 _req=self.protocolclass.LockKeyReq(lock=1) 0494 self.sendbrewcommand(_req, self.protocolclass.data) 0495 def _lock_key(self): 0496 _req=self.protocolclass.LockKeyReq() 0497 self.sendbrewcommand(_req, self.protocolclass.data) 0498 0499 def _press_key(self, keys): 0500 # simulate a series of keypress 0501 if not keys: 0502 return 0503 _req=self.protocolclass.KeyPressReq() 0504 for _k in keys: 0505 _req.key=_k 0506 self.sendbrewcommand(_req, self.protocolclass.data) 0507 0508 0509 #------------------------------------------------------------------------------- 0510 parentprofile=com_lgvx8100.Profile 0511 class Profile(parentprofile): 0512 protocolclass=Phone.protocolclass 0513 serialsname=Phone.serialsname 0514 0515 BP_Calendar_Version=3 0516 phone_manufacturer='LG Electronics Inc' 0517 phone_model='AX8600' 0518 # inside screen resoluation 0519 WALLPAPER_WIDTH=176 0520 WALLPAPER_HEIGHT=220 0521 0522 MAX_WALLPAPER_BASENAME_LENGTH=32 0523 WALLPAPER_FILENAME_CHARS="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_() ." 0524 WALLPAPER_CONVERT_FORMAT="jpg" 0525 0526 # the 8300 uses "W" for wait in the dialstring, it does not support "T" 0527 DIALSTRING_CHARS="[^0-9PW#*]" 0528 0529 MAX_RINGTONE_BASENAME_LENGTH=32 0530 RINGTONE_FILENAME_CHARS="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_() ." 0531 RINGTONE_LIMITS= { 0532 'MAXSIZE': 200000 0533 } 0534 # MSGRINGTONE=None 0535 0536 imageorigins={} 0537 imageorigins.update(common.getkv(parentprofile.stockimageorigins, "images")) 0538 # imageorigins.update(common.getkv(parentprofile.stockimageorigins, "video")) 0539 # imageorigins.update(common.getkv(parentprofile.stockimageorigins, "images(sd)")) 0540 # imageorigins.update(common.getkv(parentprofile.stockimageorigins, "video(sd)")) 0541 0542 # our targets are the same for all origins 0543 imagetargets={} 0544 ## imagetargets.update(common.getkv(parentprofile.stockimagetargets, "fullscreen", 0545 ## {'width': 176, 'height': 220, 'format': "JPEG"})) 0546 imagetargets.update(common.getkv(parentprofile.stockimagetargets, "wallpaper", 0547 {'width': 176, 'height': 220, 'format': "JPEG"})) 0548 # imagetargets.update(common.getkv(parentprofile.stockimagetargets, "outsidelcd", 0549 # {'width': 128, 'height': 160, 'format': "JPEG"})) 0550 ## imagetargets.update(common.getkv(parentprofile.stockimagetargets, "pictureid", 0551 ## {'width': 128, 'height': 142, 'format': "JPEG"})) 0552 0553 0554 def GetImageOrigins(self): 0555 return self.imageorigins 0556 0557 ringtoneorigins=('ringers', 'sounds') 0558 excluded_ringtone_origins=('ringers') 0559 excluded_wallpaper_origins=('video') 0560 0561 0562 def GetTargetsForImageOrigin(self, origin): 0563 return self.imagetargets 0564 0565 def QueryAudio(self, origin, currentextension, afi): 0566 _max_size=self.RINGTONE_LIMITS['MAXSIZE'] 0567 setattr(afi, 'MAXSIZE', _max_size) 0568 # we don't modify any of these 0569 if afi.format in ("MIDI", "QCP", "PMD", "WMA"): 0570 return currentextension, afi 0571 # examine mp3 0572 if afi.format=="MP3": 0573 if afi.channels==1 and 8<=afi.bitrate<=64 and 16000<=afi.samplerate<=22050: 0574 return currentextension, afi 0575 # convert it 0576 return ("mp3", fileinfo.AudioFileInfo(afi, **{'format': 'MP3', 0577 'channels': 2, 0578 'bitrate': 48, 0579 'samplerate': 44100, 0580 'MAXSIZE': _max_size })) 0581 0582 def __init__(self): 0583 parentprofile.__init__(self) 0584 0585 0586 _supportedsyncs=( 0587 ('phonebook', 'read', None), # all phonebook reading 0588 ('calendar', 'read', None), # all calendar reading 0589 ('wallpaper', 'read', None), # all wallpaper reading 0590 ('ringtone', 'read', None), # all ringtone reading 0591 ('call_history', 'read', None),# all call history list reading 0592 ## ('sms', 'read', None), # all SMS list reading 0593 ('memo', 'read', None), # all memo list reading 0594 ('phonebook', 'write', 'OVERWRITE'), # only overwriting phonebook 0595 ('calendar', 'write', 'OVERWRITE'), # only overwriting calendar 0596 ('wallpaper', 'write', 'MERGE'), # merge and overwrite wallpaper 0597 ('wallpaper', 'write', 'OVERWRITE'), 0598 ('ringtone', 'write', 'MERGE'), # merge and overwrite ringtone 0599 ('ringtone', 'write', 'OVERWRITE'), 0600 ## ('sms', 'write', 'OVERWRITE'), # all SMS list writing 0601 ('memo', 'write', 'OVERWRITE'), # all memo list writing 0602 ## ('t9_udb', 'read', 'OVERWRITE'), 0603 ## ('t9_udb', 'write', 'OVERWRITE'), 0604 ) 0605 0606 field_color_data={ 0607 'phonebook': { 0608 'name': { 0609 'first': 1, 'middle': 1, 'last': 1, 'full': 1, 0610 'nickname': 0, 'details': 1 }, 0611 'number': { 0612 'type': 5, 'speeddial': 5, 'number': 5, 'details': 5 }, 0613 'email': 2, 0614 'address': { 0615 'type': 0, 'company': 0, 'street': 0, 'street2': 0, 0616 'city': 0, 'state': 0, 'postalcode': 0, 'country': 0, 0617 'details': 0 }, 0618 'url': 0, 0619 'memo': 0, 0620 'category': 1, 0621 'wallpaper': 1, 0622 'ringtone': 2, 0623 'storage': 0, 0624 }, 0625 'calendar': { 0626 'description': True, 'location': False, 'allday': False, 0627 'start': True, 'end': True, 'priority': False, 0628 'alarm': True, 'vibrate': True, 0629 'repeat': True, 0630 'memo': False, 0631 'category': False, 0632 'wallpaper': False, 0633 'ringtone': True, 0634 }, 0635 'memo': { 0636 'subject': True, 0637 'date': True, 0638 'secret': False, 0639 'category': False, 0640 'memo': True, 0641 }, 0642 'todo': { 0643 'summary': False, 0644 'status': False, 0645 'due_date': False, 0646 'percent_complete': False, 0647 'completion_date': False, 0648 'private': False, 0649 'priority': False, 0650 'category': False, 0651 'memo': False, 0652 }, 0653 } 0654
Generated by PyXR 0.9.4