0001 ### BITPIM 0002 ### 0003 ### Copyright (C) 2008 Joe Pham <djpham@bitpim.org> 0004 ### 0005 ### This program is free software; you can redistribute it and/or modify 0006 ### it under the terms of the BitPim license as detailed in the LICENSE file. 0007 ### 0008 ### $Id: com_lgvx9100.py 4693 2008-08-15 22:30:51Z djpham $ 0009 0010 """ 0011 Communicate with the LG VX9100 (enV2) cell phone. This is based on the enV model 0012 """ 0013 0014 # BitPim modules 0015 import common 0016 import com_brew 0017 import com_lg 0018 import com_lgvx8550 0019 import p_lgvx9100 0020 import prototypes 0021 import helpids 0022 import sms 0023 0024 DEBUG1=False 0025 DEBUG2=False 0026 #------------------------------------------------------------------------------- 0027 parentphone=com_lgvx8550.Phone 0028 class Phone(parentphone): 0029 "Talk to the LG VX9100 cell phone" 0030 0031 desc="LG-VX9100" 0032 helpid=helpids.ID_PHONE_LGVX9100 0033 protocolclass=p_lgvx9100 0034 serialsname='lgvx9100' 0035 my_model='VX9100' 0036 0037 # rintones and wallpaper info, copy from VX9900, may need to change to match 0038 # what the phone actually has 0039 external_storage_root='mmc1/' 0040 builtinringtones= ('Low Beep Once', 'Low Beeps', 'Loud Beep Once', 'Loud Beeps', 'Door Bell', 'VZW Default Tone') + \ 0041 tuple(['Ringtone '+`n` for n in range(1,17)]) + \ 0042 ('No Ring',) 0043 0044 ringtonelocations= ( 0045 # type index file default dir external dir max type Index 0046 ( 'ringers', 'dload/myringtone.dat','brew/mod/10889/ringtones','mmc1/ringers', 100, protocolclass.INDEX_RT_TYPE, 100), 0047 ( 'sounds', 'dload/mysound.dat', 'brew/mod/18067', '', 100, protocolclass.INDEX_SOUND_TYPE, None), 0048 ( 'sounds(sd)', 'dload/sd_sound.dat', 'mmc1/my_sounds', '', 100, protocolclass.INDEX_SDSOUND_TYPE, None), 0049 ## ( 'music', 'dload/efs_music.dat', 'my_music', '', 100, 0x104, None), 0050 ## ( 'music(sd)', 'dload/sd_music.dat', 'mmc1/my_music', '', 100, 0x14, None), 0051 ) 0052 0053 wallpaperlocations= ( 0054 # type index file default dir external dir max type Index 0055 ( 'images', 'dload/image.dat', 'brew/mod/10888', '', 100, protocolclass.INDEX_IMAGE_TYPE, 100), 0056 ( 'images(sd)', 'dload/sd_image.dat', 'mmc1/my_pix', '', 100, protocolclass.INDEX_SDIMAGE_TYPE, None), 0057 ( 'video', 'dload/video.dat', 'brew/mod/10890', '', 100, protocolclass.INDEX_VIDEO_TYPE, None), 0058 ( 'video(sd)', 'dload/sd_video.dat', 'mmc1/my_flix', '', 100, protocolclass.INDEX_SDVIDEO_TYPE, None), 0059 ) 0060 0061 def __init__(self, logtarget, commport): 0062 parentphone.__init__(self, logtarget, commport) 0063 0064 def setDMversion(self): 0065 self._DMv6=True 0066 self._DMv5=False 0067 0068 # Fundamentals: 0069 # - get_esn - same as LG VX-8300 0070 # - getgroups - same as LG VX-8100 0071 # - getwallpaperindices - LGUncountedIndexedMedia 0072 # - getrintoneindices - LGUncountedIndexedMedia 0073 # - DM Version - T99VZV01: N/A, T99VZV02: 5 0074 0075 # phonebook stuff----------------------------------------------------------- 0076 # This is essentially the same with the VX-8550 with a few tweaks. 0077 # These tweaks are probably applicable to the VX-8550 as well, but since 0078 # I can't test them on an actual VX-8550, I'll leave it alone. 0079 0080 # groups 0081 def getgroups(self, results): 0082 "Read groups" 0083 # Reads groups that use explicit IDs 0084 self.log("Reading group information") 0085 g=self.readobject(self.protocolclass.pb_group_filename, 0086 self.protocolclass.pbgroups, 0087 'Reading groups data') 0088 groups={} 0089 for _group in g.groups: 0090 if _group.name: 0091 groups[_group.groupid]= { 'name': _group.name, 0092 'user_added': _group.user_added } 0093 results['groups'] = groups 0094 return groups 0095 0096 def savegroups(self, data): 0097 groups=data.get('groups', {}) 0098 keys=groups.keys() 0099 keys.sort() 0100 keys.reverse() 0101 g=self.protocolclass.pbgroups() 0102 # write the No Group entry first 0103 g.groups.append(self.protocolclass.pbgroup(name='No Group')) 0104 # now write the rest in reverse ID order 0105 for k in keys: 0106 if not k: 0107 # already wrote this one out 0108 continue 0109 g.groups.append(self.protocolclass.pbgroup(name=groups[k]['name'], 0110 groupid=k, 0111 user_added=groups[k].get('user_added', 1))) 0112 self.writeobject(self.protocolclass.pb_group_filename, g, 0113 logtitle='Writing phonebook groups', 0114 uselocalfs=DEBUG1) 0115 0116 def _get_speeddials(self): 0117 """Return the speed dials dict""" 0118 speeds={} 0119 try: 0120 if self.protocolclass.NUMSPEEDDIALS: 0121 self.log("Reading speed dials") 0122 sd=self.readobject(self.protocolclass.speed_file_name, 0123 self.protocolclass.speeddials, 'Reading speed dials') 0124 for _idx,_entry in enumerate(sd.speeddials): 0125 if _entry.valid(): 0126 speeds.setdefault(_entry.entry, {}).update({ _entry.number: _idx }) 0127 except com_brew.BrewNoSuchFileException: 0128 pass 0129 return speeds 0130 0131 def _build_media_dict(self, fundamentals, media_data, index_name): 0132 """Build & return a dict with keys being the media filenames and 0133 values being the name of the index item (index['name']) 0134 """ 0135 _res={} 0136 _media_index=fundamentals.get(index_name, {}) 0137 for _item in media_data.items: 0138 _pathname=_item.pathname 0139 if _pathname and not _res.has_key(_pathname): 0140 # not already in dict, look up the name if any 0141 _res[_pathname]=None 0142 for _entry in _media_index.values(): 0143 if _entry.get('filename', None)==_pathname: 0144 _res[_pathname]=_entry['name'] 0145 break 0146 return _res 0147 0148 def _build_ice_dict(self): 0149 # Return an ICE dict for building phone entries 0150 _res={} 0151 _ice=self.readobject(self.protocolclass.pb_ice_file_name, 0152 self.protocolclass.iceentryfile, 0153 logtitle='Reading ICE entries') 0154 for _item in _ice.items: 0155 if _item.valid(): 0156 _res[_item.pb_index]=_item.entry_number 0157 return _res 0158 0159 def getphonebook (self, result): 0160 """Reads the phonebook data. The L{getfundamentals} information will 0161 already be in result.""" 0162 # Read speed dials first -- same file format as the VX-8100 0163 _speeds=self._get_speeddials() 0164 0165 # Read the emergency contacts list 0166 self.log("Reading ICE entries") 0167 _ices=self._build_ice_dict() 0168 0169 self.log("Reading phonebook entries") 0170 pb_entries=self.readobject(self.protocolclass.pb_file_name, 0171 self.protocolclass.pbfile, 0172 logtitle='Reading phonebook entries') 0173 0174 self.log("Reading phone numbers") 0175 pb_numbers=self.readobject(self.protocolclass.pn_file_name, 0176 self.protocolclass.pnfile, 0177 logtitle='Reading phonebook numbers') 0178 0179 self.log("Reading Ringtone IDs") 0180 ring_pathf=self._get_path_index(self.protocolclass.RTPathIndexFile) 0181 _rt_ids=self._build_media_dict(result, ring_pathf, 'ringtone-index') 0182 0183 self.log("Reading Picture IDs") 0184 picid_pathf=self._get_path_index(self.protocolclass.WPPathIndexFile) 0185 _wp_ids=self._build_media_dict(result, picid_pathf, 'wallpaper-index') 0186 0187 pbook={} 0188 for _cnt in range(self.protocolclass.NUMPHONEBOOKENTRIES): 0189 pb_entry=pb_entries.items[_cnt] 0190 if not pb_entry.valid(): 0191 continue 0192 try: 0193 self.log("Parse entry "+`_cnt`+" - " + pb_entry.name) 0194 pbook[_cnt]=self.extractphonebookentry(pb_entry, pb_numbers, 0195 _speeds, _ices, result, 0196 _rt_ids.get(ring_pathf.items[_cnt].pathname, None), 0197 _wp_ids.get(picid_pathf.items[_cnt].pathname, None)) 0198 0199 self.progress(_cnt, self.protocolclass.NUMPHONEBOOKENTRIES, pb_entry.name) 0200 except common.PhoneBookBusyException: 0201 raise 0202 except Exception, e: 0203 # Something's wrong with this entry, log it and skip 0204 self.log('Failed to parse entry %d'%_cnt) 0205 self.log('Exception %s raised'%`e`) 0206 if __debug__: 0207 raise 0208 0209 self.progress(self.protocolclass.NUMPHONEBOOKENTRIES, 0210 self.protocolclass.NUMPHONEBOOKENTRIES, 0211 "Phone book read completed") 0212 0213 result['phonebook']=pbook 0214 cats=[] 0215 for i in result['groups']: 0216 if result['groups'][i]['name']!='No Group': 0217 cats.append(result['groups'][i]['name']) 0218 result['categories']=cats 0219 return pbook 0220 0221 def extractphonebookentry(self, entry, numbers, speeds, ices, fundamentals, 0222 rt_name, wp_name): 0223 """Return a phonebook entry in BitPim format. This is called from getphonebook.""" 0224 res={} 0225 # serials 0226 res['serials']=[ {'sourcetype': self.serialsname, 0227 'sourceuniqueid': fundamentals['uniqueserial'], 0228 'serial1': entry.entry_number1, 0229 'serial2': entry.entry_number1 } ] 0230 0231 # only one name 0232 res['names']=[ {'full': entry.name} ] 0233 0234 # only one category 0235 cat=fundamentals['groups'].get(entry.group, {'name': "No Group"})['name'] 0236 if cat!="No Group": 0237 res['categories']=[ {'category': cat} ] 0238 0239 # emails 0240 res['emails']=[] 0241 for i in entry.emails: 0242 if len(i.email): 0243 res['emails'].append( {'email': i.email} ) 0244 if not len(res['emails']): del res['emails'] # it was empty 0245 0246 # wallpapers 0247 if entry.wallpaper!=self.protocolclass.NOWALLPAPER: 0248 try: 0249 if entry.wallpaper == 0x64: 0250 paper = wp_name 0251 else: 0252 paper = fundamentals['wallpaper-index'][entry.wallpaper]['name'] 0253 res['wallpapers']=[ {'wallpaper': paper, 'use': 'call'} ] 0254 except: 0255 print "can't find wallpaper for index",entry.wallpaper 0256 0257 # ringtones 0258 if entry.ringtone != self.protocolclass.NORINGTONE: 0259 try: 0260 if entry.ringtone == 0x64: 0261 tone = rt_name 0262 else: 0263 tone=fundamentals['ringtone-index'][entry.ringtone]['name'] 0264 if tone: 0265 res['ringtones']=[ {'ringtone': tone, 'use': 'call'} ] 0266 except: 0267 print "can't find ringtone for index",entry.ringtone 0268 # assume we are like the VX-8100 in this regard -- looks correct 0269 res=self._assignpbtypeandspeeddialsbytype(entry, numbers, speeds, res) 0270 0271 # assign the ICE entry to the associated contact to keep them in sync 0272 res=self._assigniceentry(entry, numbers, ices, res) 0273 0274 return res 0275 0276 def _assignpbtypeandspeeddialsbytype(self, entry, numbers, speeds, res): 0277 # for some phones (e.g. vx8100) the speeddial numberindex is really the numbertype (now why would LG want to change this!) 0278 res['numbers']=[] 0279 for i in range(self.protocolclass.NUMPHONENUMBERS): 0280 if entry.numberindices[i].numberindex>=\ 0281 self.protocolclass.NUMPHONENUMBERENTRIES: 0282 # invalid number 0283 continue 0284 _pnentry=numbers.items[entry.numberindices[i].numberindex] 0285 num=_pnentry.phone_number 0286 num_type=_pnentry.type 0287 if len(num): 0288 t=self.protocolclass.numbertypetab[num_type] 0289 if t[-1]=='2': 0290 t=t[:-1] 0291 res['numbers'].append({'number': num, 'type': t}) 0292 # if this is a speeddial number set it 0293 if speeds.has_key(entry.entry_number0) and \ 0294 speeds[entry.entry_number0].has_key(num_type): 0295 res['numbers'][i]['speeddial']=speeds[entry.entry_number0][num_type] 0296 return res 0297 0298 def _assigniceentry(self, entry, numbers, ices, res): 0299 if ices.has_key(entry.entry_number0): 0300 # this contact entry is an ICE entry 0301 res['ice']=[ { 'iceindex': ices[entry.entry_number0] } ] 0302 self.log('Entry %d is ICE %d'%(entry.entry_number0, 0303 ices[entry.entry_number0])) 0304 return res 0305 0306 def _get_next_pb_id(self): 0307 """Return the next available pbentry ID""" 0308 return self.readobject(self.protocolclass.pb_recordid_filename, 0309 self.protocolclass.RecordIdEntry, 0310 logtitle='Reading record_id').idnum 0311 def _save_next_pb_id(self, idnum): 0312 """Save the next pbentry ID""" 0313 self.writeobject(self.protocolclass.pb_recordid_filename, 0314 self.protocolclass.RecordIdEntry(idnum=idnum), 0315 logtitle='Writing record_id', 0316 uselocalfs=DEBUG1) 0317 def savephonebook (self, data): 0318 "Saves out the phonebook" 0319 self.savegroups (data) 0320 0321 ring_pathf=self.protocolclass.PathIndexFile() 0322 picid_pathf=self.protocolclass.PathIndexFile() 0323 0324 # the pbentry.dat will will be overwritten so there is no need to delete entries 0325 pbook = data.get('phonebook', {}) 0326 keys = pbook.keys () 0327 keys.sort () 0328 0329 _rt_index=data.get('ringtone-index', {}) 0330 _wp_index=data.get('wallpaper-index', {}) 0331 0332 entry_num0 = 0 0333 entry_num1=self._get_next_pb_id() 0334 pb_entries = self.protocolclass.pbfile() 0335 pn_entries=self.protocolclass.pnfile() 0336 ice_entries = self.protocolclass.iceentryfile() 0337 for i in range(self.protocolclass.NUMEMERGENCYCONTACTS): 0338 ice_entries.items.append (self.protocolclass.iceentry()) 0339 speeddials={} 0340 for i in keys: 0341 pb_entries.items.append(self.make_entry (pn_entries, speeddials, ice_entries, 0342 entry_num0, entry_num1, 0343 pbook[i], data, 0344 ring_pathf,_rt_index, 0345 picid_pathf, _wp_index)) 0346 entry_num0 += 1 0347 if entry_num0 >= self.protocolclass.NUMPHONEBOOKENTRIES: 0348 self.log ("Maximum number of phonebook entries reached") 0349 break 0350 if entry_num1==0xffffffff: 0351 entry_num1=0 0352 else: 0353 entry_num1+=1 0354 0355 # write phonebook entries 0356 self.log ("Writing phonebook entries") 0357 self.writeobject(self.protocolclass.pb_file_name, 0358 pb_entries, 0359 logtitle='Writing phonebook entries', 0360 uselocalfs=DEBUG1) 0361 # write phone numbers 0362 self.log ("Writing phone numbers") 0363 self.writeobject(self.protocolclass.pn_file_name, 0364 pn_entries, logtitle='Writing phonebook numbers', 0365 uselocalfs=DEBUG1) 0366 # write ringtone index 0367 self.log('Writing ringtone ID') 0368 self.writeobject(self.protocolclass.RTPathIndexFile, 0369 ring_pathf, logtitle='Writing ringtone paths', 0370 uselocalfs=DEBUG1) 0371 # write wallpaer index 0372 self.log('Writing pciture ID') 0373 self.writeobject(self.protocolclass.WPPathIndexFile, 0374 picid_pathf, logtitle='Writing wallpaper paths', 0375 uselocalfs=DEBUG1) 0376 # write ICE index 0377 self.log('Writing ICE entries') 0378 self.writeobject(self.protocolclass.pb_ice_file_name, 0379 ice_entries, logtitle='Writing ICE entries', 0380 uselocalfs=DEBUG1) 0381 0382 # update speed dials 0383 req=self.protocolclass.speeddials() 0384 # slot 0 is always unused 0385 req.speeddials.append(self.protocolclass.speeddial()) 0386 # if empty, slot 1 is for voicemail 0387 if speeddials.has_key(1): 0388 req.speeddials.append(self.protocolclass.speeddial(entry=speeddials[1]['entry'], 0389 number=speeddials[1]['type'])) 0390 else: 0391 req.speeddials.append(self.protocolclass.speeddial(entry=1000, 0392 number=6)) 0393 for i in range(2, self.protocolclass.NUMSPEEDDIALS): 0394 sd=self.protocolclass.speeddial() 0395 if speeddials.has_key(i): 0396 sd.entry=speeddials[i]['entry'] 0397 sd.number=speeddials[i]['type'] 0398 req.speeddials.append(sd) 0399 self.log('Writing speed dials') 0400 self.writeobject(self.protocolclass.speed_file_name, 0401 req, logtitle='Writing speed dials data', 0402 uselocalfs=DEBUG1) 0403 # update the next pbentries ID 0404 self._save_next_pb_id(entry_num1) 0405 data["rebootphone"]=True 0406 0407 return data 0408 0409 def make_pn_entry (self, phone_number, number_type, pn_id, pbpn_id, pe_id): 0410 """ Create a non-blank pnfileentry frome a phone number string """ 0411 if len(phone_number) == 0: 0412 raise 0413 0414 new_entry = self.protocolclass.pnfileentry(entry_tag=self.protocolclass.PB_NUMBER_SOR) 0415 new_entry.pn_id = pn_id 0416 new_entry.pe_id = pe_id 0417 new_entry.phone_number = phone_number 0418 new_entry.type = number_type 0419 new_entry.pn_order = pbpn_id 0420 0421 return new_entry 0422 0423 def make_ice_entry (self, ice_id, pb_id): 0424 """ Create a iceentry from a pb_id and ice_id """ 0425 new_entry = self.protocolclass.iceentry() 0426 0427 new_entry.entry_assigned = 1 0428 new_entry.entry_number = ice_id 0429 new_entry.pb_index = pb_id 0430 0431 return new_entry 0432 0433 def make_entry (self, pn_entries, speeddials, ice_entries, 0434 entry_num0, entry_num1, 0435 pb_entry, data, ring_pathf, 0436 rt_index, picid_pathf, wp_index): 0437 """ Create a pbfileentry from a bitpim phonebook entry """ 0438 new_entry = self.protocolclass.pbfileentry(entry_tag=self.protocolclass.PB_ENTRY_SOR) 0439 # entry IDs 0440 new_entry.entry_number0 = entry_num0 0441 new_entry.entry_number1 = entry_num1 0442 0443 for key in pb_entry: 0444 if key in ('emails', 'numbertypes'): 0445 l = getattr (new_entry, key) 0446 for item in pb_entry[key]: 0447 l.append(item) 0448 elif key == 'numbers': 0449 l = getattr (new_entry, 'numberindices') 0450 for i in range(0, self.protocolclass.NUMPHONENUMBERS): 0451 new_pn_id = len (pn_entries.items) 0452 if new_pn_id == self.protocolclass.NUMPHONENUMBERENTRIES: 0453 # this state should not be possible. should this raise an exception? 0454 self.log ("Maximum number of phone numbers reached") 0455 break 0456 0457 try: 0458 pn_entries.items.append(self.make_pn_entry (pb_entry[key][i],pb_entry['numbertypes'][i], new_pn_id, i, entry_num0)) 0459 l.append (new_pn_id) 0460 except: 0461 l.append (0xffff) 0462 elif key == 'speeddials': 0463 for _sd,_num_type in zip(pb_entry['speeddials'], pb_entry['numbertypes']): 0464 if _sd is not None: 0465 speeddials[_sd]={ 'entry': entry_num0, 0466 'type': _num_type } 0467 elif key == 'ice': 0468 # In Case of Emergency 0469 _ice = pb_entry['ice'] 0470 if _ice is not None and len(_ice) > 0: 0471 _ice_entry = _ice[0]['iceindex'] 0472 ice_entries.items[_ice_entry] = self.make_ice_entry (_ice_entry, entry_num0) 0473 elif key == 'ringtone': 0474 new_entry.ringtone = self._findmediainindex(data['ringtone-index'], pb_entry['ringtone'], pb_entry['name'], 'ringtone') 0475 try: 0476 _filename = rt_index[new_entry.ringtone]['filename'] 0477 ring_pathf.items.append(self.protocolclass.PathIndexEntry(pathname=_filename)) 0478 new_entry.ringtone = 0x64 0479 except: 0480 ring_pathf.items.append(self.protocolclass.PathIndexEntry()) 0481 elif key == 'wallpaper': 0482 new_entry.wallpaper = self._findmediainindex(data['wallpaper-index'], pb_entry['wallpaper'], pb_entry['name'], 'wallpaper') 0483 try: 0484 _filename = wp_index[new_entry.wallpaper]['filename'] 0485 picid_pathf.items.append(self.protocolclass.PathIndexEntry(pathname=_filename)) 0486 new_entry.wallpaper = 0x64 0487 except: 0488 picid_pathf.items.append(self.protocolclass.PathIndexEntry()) 0489 elif key in new_entry.getfields(): 0490 setattr (new_entry, key, pb_entry[key]) 0491 0492 return new_entry 0493 0494 0495 # Calendar stuff------------------------------------------------------------ 0496 def _scheduleextras(self, data, fwversion): 0497 data.serial_number = '000000d1-00000000-00000000-' + fwversion 0498 data.unknown3 = 0x01fc 0499 0500 0501 # ringtones and wallpapers stuff-------------------------------------------- 0502 def savewallpapers(self, results, merge): 0503 results['rebootphone']=True 0504 return self.savemedia('wallpapers', 'wallpaper-index', 0505 self.wallpaperlocations, results, merge, 0506 self.getwallpaperindices, True) 0507 0508 def saveringtones(self, results, merge): 0509 # Let the phone rebuild the index file, just need to reboot 0510 results['rebootphone']=True 0511 return self.savemedia('ringtone', 'ringtone-index', 0512 self.ringtonelocations, results, merge, 0513 self.getringtoneindices, True) 0514 0515 # SMS Stuff----------------------------------------------------------------- 0516 # Again, this is very similar to the 8800, just make it work with the 9100 0517 def getindex(self, filename): 0518 try: 0519 return self.readobject(filename, 0520 self.protocolclass.indexfile, 0521 logtitle='Reading index file', 0522 uselocalfs=DEBUG2).items 0523 except: 0524 return [] 0525 0526 def _readsms(self): 0527 res={} 0528 # The Voyager and Venus use index files to keep track of SMS messages 0529 for item in self.getindex(self.protocolclass.drafts_index): 0530 sf=self.readobject(item.filename, 0531 self.protocolclass.sms_saved, 0532 logtitle='SMS draft item', 0533 uselocalfs=DEBUG2) 0534 # The 9100 only has draft messages (saved outgoing messaged) 0535 entry=self._getoutboxmessage(sf.outbox) 0536 entry.folder=entry.Folder_Saved 0537 res[entry.id]=entry 0538 for item in self.getindex(self.protocolclass.inbox_index): 0539 sf=self.readobject(item.filename, 0540 self.protocolclass.sms_in, 0541 logtitle='SMS inbox item', 0542 uselocalfs=DEBUG2) 0543 entry=self._getinboxmessage(sf) 0544 res[entry.id]=entry 0545 for item in self.getindex(self.protocolclass.outbox_index): 0546 sf=self.readobject(item.filename, 0547 self.protocolclass.sms_out, 0548 logtitle='SMS outbox item', 0549 uselocalfs=DEBUG2) 0550 entry=self._getoutboxmessage(sf) 0551 res[entry.id]=entry 0552 return res 0553 0554 def _getinboxmessage(self, sf): 0555 entry=sms.SMSEntry() 0556 entry.folder=entry.Folder_Inbox 0557 entry.datetime="%d%02d%02dT%02d%02d%02d" % (sf.GPStime) 0558 entry._from=sf.sender if sf.sender else sf.sender_name 0559 entry.subject=sf.subject 0560 entry.locked=sf.locked 0561 if sf.priority==0: 0562 entry.priority=sms.SMSEntry.Priority_Normal 0563 else: 0564 entry.priority=sms.SMSEntry.Priority_High 0565 entry.read=sf.read 0566 txt="" 0567 _decode_func=self._get_text_from_sms_msg_with_header if \ 0568 sf.msgs[1].msg_length else \ 0569 self._get_text_from_sms_msg_without_header 0570 for _entry in sf.msgs: 0571 if _entry.msg_length: 0572 txt+=_decode_func(_entry.msg_data.msg, _entry.msg_length) 0573 entry.text=unicode(txt, errors='ignore') 0574 entry.callback=sf.callback 0575 return entry 0576 0577 0578 #------------------------------------------------------------------------------- 0579 parentprofile=com_lgvx8550.Profile 0580 class Profile(parentprofile): 0581 protocolclass=Phone.protocolclass 0582 serialsname=Phone.serialsname 0583 0584 BP_Calendar_Version=3 0585 phone_manufacturer='LG Electronics Inc' 0586 phone_model='VX9100' 0587 0588 WALLPAPER_WIDTH=320 0589 WALLPAPER_HEIGHT=240 0590 # outside LCD: 160x64 0591 0592 imageorigins={} 0593 imageorigins.update(common.getkv(parentprofile.stockimageorigins, "images")) 0594 imageorigins.update(common.getkv(parentprofile.stockimageorigins, "video")) 0595 imageorigins.update(common.getkv(parentprofile.stockimageorigins, "images(sd)")) 0596 imageorigins.update(common.getkv(parentprofile.stockimageorigins, "video(sd)")) 0597 def GetImageOrigins(self): 0598 return self.imageorigins 0599 0600 0601 ## ringtoneorigins=('ringers', 'sounds', 'sounds(sd)',' music', 'music(sd)') 0602 ## excluded_ringtone_origins=('sounds', 'sounds(sd)', 'music', 'music(sd)') 0603 ringtoneorigins=('ringers', 'sounds', 'sounds(sd)') 0604 excluded_ringtone_origins=('sounds', 'sounds(sd)') 0605 0606 # our targets are the same for all origins 0607 imagetargets={} 0608 imagetargets.update(common.getkv(parentprofile.stockimagetargets, "wallpaper", 0609 {'width': 320, 'height': 215, 'format': "JPEG"})) 0610 imagetargets.update(common.getkv(parentprofile.stockimagetargets, "outsidelcd", 0611 {'width': 160, 'height': 64, 'format': "JPEG"})) 0612 0613 def GetTargetsForImageOrigin(self, origin): 0614 return self.imagetargets 0615 0616 _supportedsyncs=( 0617 ('phonebook', 'read', None), # all phonebook reading 0618 ('calendar', 'read', None), # all calendar reading 0619 ('wallpaper', 'read', None), # all wallpaper reading 0620 ('ringtone', 'read', None), # all ringtone reading 0621 ('call_history', 'read', None),# all call history list reading 0622 ('sms', 'read', None), # all SMS list reading 0623 ('memo', 'read', None), # all memo list reading 0624 ('phonebook', 'write', 'OVERWRITE'), # only overwriting phonebook 0625 ('calendar', 'write', 'OVERWRITE'), # only overwriting calendar 0626 ('wallpaper', 'write', 'MERGE'), # merge and overwrite wallpaper 0627 ## ('wallpaper', 'write', 'OVERWRITE'), 0628 ('ringtone', 'write', 'MERGE'), # merge and overwrite ringtone 0629 ## ('ringtone', 'write', 'OVERWRITE'), 0630 #### ('sms', 'write', 'OVERWRITE'), # all SMS list writing 0631 ('memo', 'write', 'OVERWRITE'), # all memo list writing 0632 #### ('playlist', 'read', 'OVERWRITE'), 0633 #### ('playlist', 'write', 'OVERWRITE'), 0634 ) 0635 0636 def normalisegroups(self, helper, data): 0637 "Assigns groups based on category data" 0638 0639 pad=[] 0640 keys=data['groups'].keys() 0641 keys.sort() 0642 for k in keys: 0643 if k: # ignore key 0 which is 'No Group' 0644 name=data['groups'][k]['name'] 0645 pad.append(name) 0646 0647 groups=helper.getmostpopularcategories(self.protocolclass.MAX_PHONEBOOK_GROUPS, data['phonebook'], ["No Group"], 32, pad) 0648 0649 # alpha sort 0650 groups.sort() 0651 0652 # newgroups 0653 newgroups={} 0654 0655 # put in No group 0656 newgroups[0]={'name': 'No Group', 'user_added': 0} 0657 0658 # populate 0659 for name in groups: 0660 # existing entries remain unchanged 0661 if name=="No Group": continue 0662 key,value=self._getgroup(name, data['groups']) 0663 if key is not None and key!=0: 0664 newgroups[key]=value 0665 # new entries get whatever numbers are free 0666 for name in groups: 0667 key,value=self._getgroup(name, newgroups) 0668 if key is None: 0669 for key in range(1,100000): 0670 if key not in newgroups: 0671 newgroups[key]={'name': name, 'user_added': 1} 0672 break 0673 0674 # yay, done 0675 if data['groups']!=newgroups: 0676 data['groups']=newgroups 0677 data['rebootphone']=True 0678 0679 def convertphonebooktophone(self, helper, data): 0680 """Converts the data to what will be used by the phone 0681 0682 @param data: contains the dict returned by getfundamentals 0683 as well as where the results go""" 0684 results={} 0685 0686 self.normalisegroups(helper, data) 0687 0688 for pbentry in data['phonebook']: 0689 if len(results)==self.protocolclass.NUMPHONEBOOKENTRIES: 0690 break 0691 e={} # entry out 0692 entry=data['phonebook'][pbentry] # entry in 0693 try: 0694 # serials 0695 serial1=helper.getserial(entry.get('serials', []), self.serialsname, data['uniqueserial'], 'serial1', 0) 0696 serial2=helper.getserial(entry.get('serials', []), self.serialsname, data['uniqueserial'], 'serial2', serial1) 0697 0698 e['serial1']=serial1 0699 e['serial2']=serial2 0700 for ss in entry["serials"]: 0701 if ss["sourcetype"]=="bitpim": 0702 e['bitpimserial']=ss 0703 assert e['bitpimserial'] 0704 0705 # name 0706 e['name']=helper.getfullname(entry.get('names', []),1,1,32)[0] 0707 0708 # ice 0709 e['ice']=entry.get('ice', None) 0710 0711 # categories/groups 0712 cat=helper.makeone(helper.getcategory(entry.get('categories', []),0,1,32), None) 0713 if cat is None: 0714 e['group']=0 0715 else: 0716 key,value=self._getgroup(cat, data['groups']) 0717 if key is not None: 0718 e['group']=key 0719 else: 0720 # sorry no space for this category 0721 e['group']=0 0722 0723 # email addresses 0724 emails=helper.getemails(entry.get('emails', []) ,0,self.protocolclass.NUMEMAILS,48) 0725 e['emails']=helper.filllist(emails, self.protocolclass.NUMEMAILS, "") 0726 0727 # phone numbers 0728 # there must be at least one email address or phonenumber 0729 minnumbers=1 0730 if len(emails): minnumbers=0 0731 numbers=helper.getnumbers(entry.get('numbers', []),minnumbers,self.protocolclass.NUMPHONENUMBERS) 0732 e['numbertypes']=[] 0733 e['numbers']=[] 0734 e['speeddials']=[] 0735 for numindex in range(len(numbers)): 0736 num=numbers[numindex] 0737 # deal with type 0738 b4=len(e['numbertypes']) 0739 type=num['type'] 0740 for i,t in enumerate(self.protocolclass.numbertypetab): 0741 if type==t: 0742 # some voodoo to ensure the second home becomes home2 0743 if i in e['numbertypes'] and t[-1]!='2': 0744 type+='2' 0745 continue 0746 e['numbertypes'].append(i) 0747 break 0748 if t=='none': # conveniently last entry 0749 e['numbertypes'].append(i) 0750 break 0751 if len(e['numbertypes'])==b4: 0752 # we couldn't find a type for the number 0753 helper.add_error_message('Number %s (%s/%s) not supported and ignored.'% 0754 (num['number'], e['name'], num['type'])) 0755 continue 0756 # deal with number 0757 number=self.phonize(num['number']) 0758 if len(number)==0: 0759 # no actual digits in the number 0760 continue 0761 if len(number)>24: # get this number from somewhere sensible 0762 # ::TODO:: number is too long and we have to either truncate it or ignore it? 0763 number=number[:24] # truncate for moment 0764 e['numbers'].append(number) 0765 # deal with speed dial 0766 sd=num.get("speeddial", None) 0767 if sd is not None and \ 0768 sd>=self.protocolclass.FIRSTSPEEDDIAL and \ 0769 sd<=self.protocolclass.LASTSPEEDDIAL: 0770 e['speeddials'].append(sd) 0771 else: 0772 e['speeddials'].append(None) 0773 0774 if len(e['numbers'])<minnumbers: 0775 # we couldn't find any numbers 0776 # for this entry, so skip it, entries with no numbers cause error 0777 helper.add_error_message("Name: %s. No suitable numbers or emails found" % e['name']) 0778 continue 0779 e['numbertypes']=helper.filllist(e['numbertypes'], self.protocolclass.NUMPHONENUMBERS, 0) 0780 e['numbers']=helper.filllist(e['numbers'], self.protocolclass.NUMPHONENUMBERS, "") 0781 e['speeddials']=helper.filllist(e['speeddials'], self.protocolclass.NUMPHONENUMBERS, None) 0782 0783 # ringtones, wallpaper 0784 e['ringtone']=helper.getringtone(entry.get('ringtones', []), 'call', None) 0785 e['wallpaper']=helper.getwallpaper(entry.get('wallpapers', []), 'call', None) 0786 0787 results[pbentry]=e 0788 0789 except helper.ConversionFailed: 0790 continue 0791 0792 data['phonebook']=results 0793 return data 0794 # applicable fields for this model 0795 field_color_data={ 0796 'phonebook': { 0797 'name': { 0798 'first': 1, 'middle': 1, 'last': 1, 'full': 1, 0799 'nickname': 0, 'details': 1 }, 0800 'number': { 0801 'type': 5, 'speeddial': 5, 'number': 5, 'details': 5 }, 0802 'email': 2, 0803 'address': { 0804 'type': 0, 'company': 0, 'street': 0, 'street2': 0, 0805 'city': 0, 'state': 0, 'postalcode': 0, 'country': 0, 0806 'details': 0 }, 0807 'url': 0, 0808 'memo': 0, 0809 'category': 1, 0810 'wallpaper': 1, 0811 'ringtone': 2, 0812 'storage': 0, 0813 'secret': 0, 0814 'ICE': 1, 0815 }, 0816 'calendar': { 0817 'description': True, 'location': False, 'allday': False, 0818 'start': True, 'end': True, 'priority': False, 0819 'alarm': True, 'vibrate': True, 0820 'repeat': True, 0821 'memo': False, 0822 'category': False, 0823 'wallpaper': False, 0824 'ringtone': True, 0825 }, 0826 'memo': { 0827 'subject': True, 0828 'date': True, 0829 'secret': False, 0830 'category': False, 0831 'memo': True, 0832 }, 0833 'todo': { 0834 'summary': False, 0835 'status': False, 0836 'due_date': False, 0837 'percent_complete': False, 0838 'completion_date': False, 0839 'private': False, 0840 'priority': False, 0841 'category': False, 0842 'memo': False, 0843 }, 0844 } 0845
Generated by PyXR 0.9.4