0001 #!/usr/bin/env python 0002 0003 ### BITPIM 0004 ### 0005 ### Copyright (C) 2007-2008 Nathan Hjelm <hjelmn@users.sourceforge.net> 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 ### $Id: com_lgvx8550.py 4679 2008-08-14 01:01:22Z hjelmn $ 0010 0011 0012 """ 0013 Communicate with the LG VX8550 cell phone. 0014 """ 0015 0016 # BitPim modules 0017 import common 0018 import com_brew 0019 import bpcalendar 0020 import prototypes 0021 import com_lgvx8700 0022 import com_lgvx8500 0023 import p_lgvx8550 0024 import p_brew 0025 import helpids 0026 import copy 0027 import time 0028 import os.path 0029 0030 DEBUG1=False 0031 #------------------------------------------------------------------------------- 0032 parentphone=com_lgvx8700.Phone 0033 class Phone(parentphone): 0034 desc="LG-VX8550" 0035 helpid=None 0036 protocolclass=p_lgvx8550 0037 serialsname='lgvx8550' 0038 0039 my_model='VX8550' 0040 0041 calendarringerlocation='sch/toolsRinger.dat' 0042 0043 def setDMversion(self): 0044 _fw_version=self.get_firmware_version()[-1] 0045 if self.my_model=='VX8550' and _fw_version>'3': 0046 # VX855V04 0047 self._DMv5 = False 0048 self._DMv6 = True 0049 else: 0050 self._DMv5 = True 0051 self._DMv6 = False 0052 0053 0054 # Fundamentals: 0055 # - get_esn - same as LG VX-8300 0056 # - getgroups - same as LG VX-8700 0057 # - getwallpaperindices - LGUncountedIndexedMedia 0058 # - getringtoneindices - LGUncountedIndexedMedia 0059 # - DM Version - 5 (VX855V03 or older), 6 (VX855V04) 0060 0061 def _get_speeddials(self): 0062 """Return the speed dials dict""" 0063 speeds={} 0064 try: 0065 if self.protocolclass.NUMSPEEDDIALS: 0066 self.log("Reading speed dials") 0067 sd=self.readobject(self.protocolclass.speed_file_name, 0068 self.protocolclass.speeddials, 'Reading speed dials') 0069 for _idx,_entry in enumerate(sd.speeddials): 0070 if _entry.valid(): 0071 speeds.setdefault(_entry.entry, {}).update({ _entry.number: _idx }) 0072 except com_brew.BrewNoSuchFileException: 0073 pass 0074 return speeds 0075 0076 def _build_media_dict(self, fundamentals, media_data, index_name): 0077 """Build & return a dict with keys being the media filenames and 0078 values being the name of the index item (index['name']) 0079 """ 0080 _res={} 0081 _media_index=fundamentals.get(index_name, {}) 0082 for _item in media_data.items: 0083 _pathname=_item.pathname 0084 if _pathname and not _res.has_key(_pathname): 0085 # not already in dict, look up the name if any 0086 _res[_pathname]=None 0087 for _entry in _media_index.values(): 0088 if _entry.get('filename', None)==_pathname: 0089 _res[_pathname]=_entry['name'] 0090 break 0091 return _res 0092 0093 def _get_path_index(self, index_file): 0094 buf = prototypes.buffer(self.getfilecontents(index_file)) 0095 _path_file=self.protocolclass.PathIndexFile() 0096 _path_file.readfrombuffer(buf, logtitle="Read path index: " + index_file) 0097 return _path_file 0098 0099 def _build_ice_dict(self): 0100 # Return an ICE dict for building phone entries 0101 _res={} 0102 _ice=self.readobject(self.protocolclass.ice_file_name, 0103 self.protocolclass.iceentryfile, 0104 logtitle='Reading ICE entries') 0105 for _item in _ice.items: 0106 if _item.valid(): 0107 _res[_item.pb_index]=_item.entry_number 0108 return _res 0109 0110 def getphonebook (self, result): 0111 """Reads the phonebook data. The L{getfundamentals} information will 0112 already be in result.""" 0113 # Read speed dials first -- same file format as the VX-8100 0114 _speeds=self._get_speeddials() 0115 0116 # Read the emergency contacts list 0117 self.log("Reading ICE entries") 0118 _ices=self._build_ice_dict() 0119 0120 self.log("Reading phonebook entries") 0121 pb_entries=self.readobject(self.protocolclass.pb_file_name, 0122 self.protocolclass.pbfile, 0123 logtitle='Reading phonebook entries') 0124 0125 self.log("Reading phone numbers") 0126 pb_numbers=self.readobject(self.protocolclass.pn_file_name, 0127 self.protocolclass.pnfile, 0128 logtitle='Reading phonebook numbers') 0129 0130 self.log("Reading Ringtone IDs") 0131 ring_pathf=self._get_path_index(self.protocolclass.RTPathIndexFile) 0132 _rt_ids=self._build_media_dict(result, ring_pathf, 'ringtone-index') 0133 0134 self.log("Reading Picture IDs") 0135 picid_pathf=self._get_path_index(self.protocolclass.WPPathIndexFile) 0136 _wp_ids=self._build_media_dict(result, picid_pathf, 'wallpaper-index') 0137 0138 pbook={} 0139 for _cnt in range(self.protocolclass.NUMPHONEBOOKENTRIES): 0140 pb_entry=pb_entries.items[_cnt] 0141 if not pb_entry.valid(): 0142 continue 0143 try: 0144 self.log("Parse entry "+`_cnt`+" - " + pb_entry.name) 0145 pbook[_cnt]=self.extractphonebookentry(pb_entry, pb_numbers, 0146 _speeds, _ices, result, 0147 _rt_ids.get(ring_pathf.items[_cnt].pathname, None), 0148 _wp_ids.get(picid_pathf.items[_cnt].pathname, None)) 0149 0150 self.progress(_cnt, self.protocolclass.NUMPHONEBOOKENTRIES, pb_entry.name) 0151 except common.PhoneBookBusyException: 0152 raise 0153 except Exception, e: 0154 # Something's wrong with this entry, log it and skip 0155 self.log('Failed to parse entry %d'%_cnt) 0156 self.log('Exception %s raised'%`e`) 0157 if __debug__: 0158 raise 0159 0160 self.progress(self.protocolclass.NUMPHONEBOOKENTRIES, 0161 self.protocolclass.NUMPHONEBOOKENTRIES, 0162 "Phone book read completed") 0163 0164 result['phonebook']=pbook 0165 cats=[] 0166 for i in result['groups']: 0167 if result['groups'][i]['name']!='No Group': 0168 cats.append(result['groups'][i]['name']) 0169 result['categories']=cats 0170 return pbook 0171 0172 def extractphonebookentry(self, entry, numbers, speeds, ices, fundamentals, 0173 rt_name, wp_name): 0174 """Return a phonebook entry in BitPim format. This is called from getphonebook.""" 0175 res={} 0176 # serials 0177 res['serials']=[ {'sourcetype': self.serialsname, 0178 'sourceuniqueid': fundamentals['uniqueserial'], 0179 'serial1': entry.entry_number1, 0180 'serial2': entry.entry_number1 } ] 0181 0182 # only one name 0183 res['names']=[ {'full': entry.name} ] 0184 0185 # only one category 0186 cat=fundamentals['groups'].get(entry.group, {'name': "No Group"})['name'] 0187 if cat!="No Group": 0188 res['categories']=[ {'category': cat} ] 0189 0190 # emails 0191 res['emails']=[] 0192 for i in entry.emails: 0193 if len(i.email): 0194 res['emails'].append( {'email': i.email} ) 0195 if not len(res['emails']): del res['emails'] # it was empty 0196 0197 # wallpapers 0198 if entry.wallpaper!=self.protocolclass.NOWALLPAPER: 0199 try: 0200 if entry.wallpaper == 0x64: 0201 paper = wp_name 0202 else: 0203 paper = fundamentals['wallpaper-index'][entry.wallpaper]['name'] 0204 0205 if paper is None: 0206 raise 0207 0208 res['wallpapers']=[ {'wallpaper': paper, 'use': 'call'} ] 0209 except: 0210 print "can't find wallpaper for index",entry.wallpaper 0211 0212 # ringtones 0213 if entry.ringtone != self.protocolclass.NORINGTONE: 0214 try: 0215 if entry.ringtone == 0x64: 0216 tone = rt_name 0217 else: 0218 tone = fundamentals['ringtone-index'][entry.ringtone]['name'] 0219 0220 if tone is None: 0221 raise 0222 0223 res['ringtones']=[ {'ringtone': tone, 'use': 'call'} ] 0224 except: 0225 print "can't find ringtone for index",entry.ringtone 0226 # assume we are like the VX-8100 in this regard -- looks correct 0227 res=self._assignpbtypeandspeeddialsbytype(entry, numbers, speeds, res) 0228 0229 # assign the ICE entry to the associated contact to keep them in sync 0230 res=self._assigniceentry(entry, numbers, ices, res) 0231 0232 return res 0233 0234 def _assignpbtypeandspeeddialsbytype(self, entry, numbers, speeds, res): 0235 # for some phones (e.g. vx8100) the speeddial numberindex is really the numbertype (now why would LG want to change this!) 0236 res['numbers']=[] 0237 0238 for i in range(self.protocolclass.NUMPHONENUMBERS): 0239 if entry.numberindices[i].numberindex >= self.protocolclass.NUMPHONENUMBERENTRIES: 0240 # invalid number 0241 continue 0242 _pnentry=numbers.items[entry.numberindices[i].numberindex] 0243 num=_pnentry.phone_number 0244 0245 if len(num): 0246 if _pnentry.malformed(): 0247 print "malformed phone number entry encountered" 0248 0249 # use the type from the phonebook entry 0250 num_type = entry.numbertypes[i].numbertype 0251 0252 t = self.protocolclass.numbertypetab[num_type] 0253 if t[-1]=='2': 0254 t=t[:-1] 0255 res['numbers'].append({'number': num, 'type': t}) 0256 # if this is a speeddial number set it 0257 if speeds.has_key(entry.entry_number0) and \ 0258 speeds[entry.entry_number0].has_key(num_type): 0259 res['numbers'][i]['speeddial']=speeds[entry.entry_number0][num_type] 0260 return res 0261 0262 def _assigniceentry(self, entry, numbers, ices, res): 0263 if ices.has_key(entry.entry_number0): 0264 # this contact entry is an ICE entry 0265 res['ice']=[ { 'iceindex': ices[entry.entry_number0] } ] 0266 return res 0267 0268 def _get_next_pb_id(self): 0269 """Return the next available pbentry ID""" 0270 return self.readobject(self.protocolclass.pb_recordid_filename, 0271 self.protocolclass.RecordIdEntry, 0272 logtitle='Reading record_id').idnum 0273 0274 def _save_next_pb_id(self, idnum): 0275 """Save the next pbentry ID""" 0276 self.writeobject(self.protocolclass.pb_recordid_filename, 0277 self.protocolclass.RecordIdEntry(idnum=idnum), 0278 logtitle='Writing record_id', 0279 uselocalfs=DEBUG1) 0280 0281 def savephonebook (self, data): 0282 "Saves out the phonebook" 0283 self.savegroups (data) 0284 0285 ring_pathf=self.protocolclass.PathIndexFile() 0286 picid_pathf=self.protocolclass.PathIndexFile() 0287 0288 # the pbentry.dat will be overwritten so there is no need to delete entries 0289 pbook = data.get('phonebook', {}) 0290 keys = pbook.keys () 0291 keys.sort () 0292 0293 _rt_index=data.get('ringtone-index', {}) 0294 _wp_index=data.get('wallpaper-index', {}) 0295 0296 entry_num0 = 0 0297 entry_num1 = self._get_next_pb_id() 0298 pb_entries = self.protocolclass.pbfile(model_name=self.my_model) 0299 pn_entries = self.protocolclass.pnfile() 0300 0301 ice_entries = self.protocolclass.iceentryfile() 0302 for i in range(self.protocolclass.NUMEMERGENCYCONTACTS): 0303 ice_entries.items.append (self.protocolclass.iceentry()) 0304 0305 speeddials={} 0306 0307 for i in keys: 0308 pb_entries.items.append(self.make_entry (pn_entries, speeddials, ice_entries, 0309 entry_num0, entry_num1, pbook[i], 0310 data, ring_pathf,_rt_index, 0311 picid_pathf, _wp_index)) 0312 entry_num0 += 1 0313 if entry_num0 >= self.protocolclass.NUMPHONEBOOKENTRIES: 0314 self.log ("Maximum number of phonebook entries reached") 0315 break 0316 if entry_num1==0xffffffff: 0317 entry_num1=0 0318 else: 0319 entry_num1+=1 0320 0321 # write phonebook entries 0322 self.log ("Writing phonebook entries") 0323 self.writeobject(self.protocolclass.pb_file_name, 0324 pb_entries, 0325 logtitle='Writing phonebook entries', 0326 uselocalfs=DEBUG1) 0327 # write phone numbers 0328 self.log ("Writing phone numbers") 0329 self.writeobject(self.protocolclass.pn_file_name, 0330 pn_entries, logtitle='Writing phonebook numbers', 0331 uselocalfs=DEBUG1) 0332 # write ringtone index 0333 self.log('Writing ringtone ID') 0334 self.writeobject(self.protocolclass.RTPathIndexFile, 0335 ring_pathf, logtitle='Writing ringtone paths', 0336 uselocalfs=DEBUG1) 0337 # write wallpaper index 0338 self.log('Writing picture ID') 0339 self.writeobject(self.protocolclass.WPPathIndexFile, 0340 picid_pathf, logtitle='Writing wallpaper paths', 0341 uselocalfs=DEBUG1) 0342 0343 # write ICE index 0344 self.log('Writing ICE entries') 0345 self.writeobject(self.protocolclass.ice_file_name, 0346 ice_entries, logtitle='Writing ICE entries', 0347 uselocalfs=DEBUG1) 0348 0349 # update speed dials 0350 req=self.protocolclass.speeddials() 0351 # slot 0 is always unused 0352 req.speeddials.append(self.protocolclass.speeddial()) 0353 # if empty, slot 1 is for voicemail 0354 if speeddials.has_key(1): 0355 req.speeddials.append(self.protocolclass.speeddial(entry=speeddials[1]['entry'], 0356 number=speeddials[1]['type'])) 0357 else: 0358 req.speeddials.append(self.protocolclass.speeddial(entry=1000, 0359 number=6)) 0360 for i in range(2, self.protocolclass.NUMSPEEDDIALS): 0361 sd=self.protocolclass.speeddial() 0362 if speeddials.has_key(i): 0363 sd.entry=speeddials[i]['entry'] 0364 sd.number=speeddials[i]['type'] 0365 req.speeddials.append(sd) 0366 0367 self.log('Writing speed dials') 0368 self.writeobject(self.protocolclass.speed_file_name, 0369 req, logtitle='Writing speed dials data', 0370 uselocalfs=DEBUG1) 0371 0372 # update the next pbentries ID 0373 self._save_next_pb_id(entry_num1) 0374 data["rebootphone"]=True 0375 0376 return data 0377 0378 def make_pn_entry (self, phone_number, number_type, pn_id, pbpn_id, pe_id): 0379 """ Create a non-blank pnfileentry frome a phone number string """ 0380 if len(phone_number) == 0: 0381 raise 0382 0383 new_entry = self.protocolclass.pnfileentry(entry_tag=self.protocolclass.PB_NUMBER_SOR) 0384 new_entry.pn_id = pn_id 0385 new_entry.pe_id = pe_id 0386 new_entry.phone_number = phone_number 0387 new_entry.ntype = number_type 0388 new_entry.pn_order = pbpn_id 0389 0390 return new_entry 0391 0392 def make_ice_entry (self, ice_id, pb_id): 0393 """ Create a iceentry from a pb_id and ice_id """ 0394 new_entry = self.protocolclass.iceentry() 0395 0396 new_entry.entry_assigned = 1 0397 new_entry.entry_number = ice_id 0398 new_entry.pb_index = pb_id 0399 0400 return new_entry 0401 0402 def make_entry (self, pn_entries, speeddials, ice_entries, 0403 entry_num0, entry_num1, pb_entry, data, 0404 ring_pathf, rt_index, picid_pathf, wp_index): 0405 """ Create a pbfileentry from a bitpim phonebook entry """ 0406 new_entry = self.protocolclass.pbfileentry(entry_tag=self.protocolclass.PB_ENTRY_SOR) 0407 # entry IDs 0408 new_entry.entry_number0 = entry_num0 0409 new_entry.entry_number1 = entry_num1 0410 0411 for key in pb_entry: 0412 if key in ('emails', 'numbertypes'): 0413 l = getattr (new_entry, key) 0414 for item in pb_entry[key]: 0415 l.append(item) 0416 elif key == 'numbers': 0417 l = getattr (new_entry, 'numberindices') 0418 for i in range(0, self.protocolclass.NUMPHONENUMBERS): 0419 new_pn_id = len (pn_entries.items) 0420 if new_pn_id == self.protocolclass.NUMPHONENUMBERENTRIES: 0421 # this state should not be possible. should this raise an exception? 0422 self.log ("Maximum number of phone numbers reached") 0423 break 0424 0425 try: 0426 pn_entries.items.append(self.make_pn_entry (pb_entry[key][i],pb_entry['numbertypes'][i], new_pn_id, i, entry_num0)) 0427 l.append (new_pn_id) 0428 except: 0429 l.append (0xffff) 0430 elif key == 'speeddials': 0431 for _sd,_num_type in zip(pb_entry['speeddials'], pb_entry['numbertypes']): 0432 if _sd is not None: 0433 speeddials[_sd]={ 'entry': entry_num0, 0434 'type': _num_type } 0435 elif key == 'ice': 0436 # In Case of Emergency 0437 _ice = pb_entry['ice'] 0438 if _ice is not None and len(_ice) > 0: 0439 _ice_entry = _ice[0]['iceindex'] 0440 ice_entries.items[_ice_entry] = self.make_ice_entry (_ice_entry, entry_num0) 0441 elif key == 'ringtone': 0442 new_entry.ringtone = self._findmediainindex(data['ringtone-index'], pb_entry['ringtone'], pb_entry['name'], 'ringtone') 0443 try: 0444 _filename = rt_index[new_entry.ringtone]['filename'] 0445 ring_pathf.items.append(self.protocolclass.PathIndexEntry(pathname=_filename)) 0446 new_entry.ringtone = 0x64 0447 except: 0448 ring_pathf.items.append(self.protocolclass.PathIndexEntry()) 0449 elif key == 'wallpaper': 0450 new_entry.wallpaper = self._findmediainindex(data['wallpaper-index'], pb_entry['wallpaper'], pb_entry['name'], 'wallpaper') 0451 try: 0452 _filename = wp_index[new_entry.wallpaper]['filename'] 0453 picid_pathf.items.append(self.protocolclass.PathIndexEntry(pathname=_filename)) 0454 new_entry.wallpaper = 0x64 0455 except: 0456 picid_pathf.items.append(self.protocolclass.PathIndexEntry()) 0457 elif key in new_entry.getfields(): 0458 setattr (new_entry, key, pb_entry[key]) 0459 0460 return new_entry 0461 0462 def getcalendar(self,result): 0463 res={} 0464 # Read exceptions file first 0465 exceptions = self.getexceptions() 0466 0467 try: 0468 buf = prototypes.buffer(self.getfilecontents(self.calendarringerlocation)) 0469 ringersf = self.protocolclass.scheduleringerfile() 0470 ringersf.readfrombuffer (buf) 0471 except: 0472 self.log ("unable to read schedule ringer path file") 0473 0474 # Now read schedule 0475 try: 0476 buf=prototypes.buffer(self.getfilecontents(self.calendarlocation)) 0477 if len(buf.getdata())<3: 0478 # file is empty, and hence same as non-existent 0479 raise com_brew.BrewNoSuchFileException() 0480 sc=self.protocolclass.schedulefile() 0481 sc.readfrombuffer(buf, logtitle="Calendar") 0482 for event in sc.events: 0483 # the vx8100 has a bad entry when the calender is empty 0484 # stop processing the calender when we hit this record 0485 if event.pos==0: #invalid entry 0486 continue 0487 entry=bpcalendar.CalendarEntry() 0488 try: # delete events are still in the calender file but have garbage dates 0489 self.getcalendarcommon(entry, event) 0490 except ValueError: 0491 continue 0492 try: 0493 if (event.ringtone >= 100): # MIC Ringer is downloaded to phone or microSD 0494 entry.ringtone = common.basename(ringersf.ringerpaths[event.ringtone-100].path) 0495 else: # MIC Ringer is built-in 0496 entry.ringtone=self.builtinringtones[event.ringtone] 0497 except: 0498 self.log ("Setting default ringer for event\n") 0499 # hack, not having a phone makes it hard to figure out the best approach 0500 if entry.alarm==None: 0501 entry.ringtone='No Ring' 0502 else: 0503 entry.ringtone='Loud Beeps' 0504 # check for exceptions and remove them 0505 if event.repeat[3] and exceptions.has_key(event.pos): 0506 for year, month, day in exceptions[event.pos]: 0507 entry.suppress_repeat_entry(year, month, day) 0508 res[entry.id]=entry 0509 0510 assert sc.numactiveitems==len(res) 0511 except com_brew.BrewNoSuchFileException: 0512 pass # do nothing if file doesn't exist 0513 result['calendar']=res 0514 return result 0515 0516 def _scheduleextras(self, data, fwversion): 0517 data.serial_number = '000000ca-00000000-00000000-' + fwversion 0518 data.unknown3 = 0x01fb 0519 0520 def savecalendar(self, dict, merge): 0521 # ::TODO:: 0522 # what will be written to the files 0523 eventsf = self.protocolclass.schedulefile() 0524 exceptionsf = self.protocolclass.scheduleexceptionfile() 0525 ringersf = self.protocolclass.scheduleringerfile() 0526 # what are we working with 0527 cal=dict['calendar'] 0528 newcal={} 0529 #sort into start order, makes it possible to see if the calendar has changed 0530 keys=[(x.start, k) for k,x in cal.items()] 0531 keys.sort() 0532 # apply limiter 0533 keys=keys[:self.protocolclass.NUMCALENDARENTRIES] 0534 # number of entries 0535 eventsf.numactiveitems=len(keys) 0536 ringersf.numringers = 0 0537 pos = 0 0538 # get phone firmware version for serial number 0539 try: 0540 req = p_brew.firmwarerequest() 0541 res = self.sendbrewcommand(req, self.protocolclass.firmwareresponse) 0542 _fwversion = res.firmware 0543 except: 0544 _fwversion = '00000000' 0545 0546 # play with each entry 0547 for (_,k) in keys: 0548 # entry is what we will return to user 0549 entry=cal[k] 0550 data=self.protocolclass.scheduleevent() 0551 # using the packetsize() method here will fill the LIST with default entries 0552 data.pos = pos * data.packet_size + 2 0553 self._schedulecommon(entry, data) 0554 alarm_set=self.setalarm(entry, data) 0555 if alarm_set: 0556 if entry.ringtone=="No Ring" and not entry.vibrate: 0557 alarm_name="Low Beep Once" 0558 else: 0559 alarm_name=entry.ringtone 0560 else: # set alarm to "No Ring" gets rid of alarm icon on phone 0561 alarm_name="No Ring" 0562 for i in dict['ringtone-index']: 0563 self.log ('ringtone ' + str(i) + ': ' + dict['ringtone-index'][i]['name'] + ' alarm-name = ' + alarm_name) 0564 if dict['ringtone-index'][i]['name']==alarm_name: 0565 if dict['ringtone-index'][i].get('filename', None): 0566 data.ringtone = 100 + ringersf.numringers 0567 ringersf.ringerpaths.append(dict['ringtone-index'][i]['filename']) 0568 ringersf.numringers = ringersf.numringers + 1 0569 else: 0570 # builtin ringer 0571 data.ringtone=i # Set to proper index 0572 break 0573 # check for exceptions and add them to the exceptions list 0574 self._scheduleexceptions(entry, data, exceptionsf) 0575 self._scheduleextras(data, _fwversion) 0576 # put entry in nice shiny new dict we are building 0577 entry=copy.copy(entry) 0578 newcal[data.pos]=entry 0579 eventsf.events.append(data) 0580 pos = pos + 1 0581 0582 buf=prototypes.buffer() 0583 eventsf.writetobuffer(buf, logtitle="New Calendar") 0584 self.writefile(self.calendarlocation, buf.getvalue()) 0585 self.log("Your phone has to be rebooted due to the calendar changing") 0586 dict["rebootphone"]=True 0587 0588 buf=prototypes.buffer() 0589 exceptionsf.writetobuffer(buf, logtitle="Writing calendar exceptions") 0590 self.writefile(self.calendarexceptionlocation, buf.getvalue()) 0591 0592 buf = prototypes.buffer() 0593 ringersf.writetobuffer(buf, logtitle="Writing calendar ringers") 0594 self.writefile(self.calendarringerlocation, buf.getvalue()) 0595 0596 # fix passed in dict 0597 dict['calendar']=newcal 0598 0599 return dict 0600 0601 #------------------------------------------------------------------------------- 0602 parentprofile=com_lgvx8500.Profile 0603 class Profile(parentprofile): 0604 protocolclass=Phone.protocolclass 0605 serialsname=Phone.serialsname 0606 0607 BP_Calendar_Version=3 0608 phone_manufacturer='LG Electronics Inc' 0609 phone_model='VX8550' 0610 # inside screen resoluation 0611 WALLPAPER_WIDTH=176 0612 WALLPAPER_HEIGHT=220 0613 0614 imageorigins={} 0615 imageorigins.update(common.getkv(parentprofile.stockimageorigins, "images")) 0616 imageorigins.update(common.getkv(parentprofile.stockimageorigins, "video")) 0617 imageorigins.update(common.getkv(parentprofile.stockimageorigins, "images(sd)")) 0618 imageorigins.update(common.getkv(parentprofile.stockimageorigins, "video(sd)")) 0619 0620 # our targets are the same for all origins 0621 imagetargets={} 0622 imagetargets.update(common.getkv(parentprofile.stockimagetargets, "fullscreen", 0623 {'width': 238, 'height': 246, 'format': "JPEG"})) 0624 imagetargets.update(common.getkv(parentprofile.stockimagetargets, "wallpaper", 0625 {'width': 240, 'height': 274, 'format': "JPEG"})) 0626 imagetargets.update(common.getkv(parentprofile.stockimagetargets, "pictureid", 0627 {'width': 120, 'height': 100, 'format': "JPEG"})) 0628 0629 _supportedsyncs=( 0630 ('phonebook', 'read', None), # all phonebook reading 0631 ('calendar', 'read', None), # all calendar reading 0632 ('wallpaper', 'read', None), # all wallpaper reading 0633 ('ringtone', 'read', None), # all ringtone reading 0634 ('call_history', 'read', None),# all call history list reading 0635 ('sms', 'read', None), # all SMS list reading 0636 ('memo', 'read', None), # all memo list reading 0637 ('phonebook', 'write', 'OVERWRITE'), # only overwriting phonebook 0638 ('calendar', 'write', 'OVERWRITE'), # only overwriting calendar 0639 ('wallpaper', 'write', 'MERGE'), # merge and overwrite wallpaper 0640 ('wallpaper', 'write', 'OVERWRITE'), 0641 ('ringtone', 'write', 'MERGE'), # merge and overwrite ringtone 0642 ('ringtone', 'write', 'OVERWRITE'), 0643 ('sms', 'write', 'OVERWRITE'), # all SMS list writing 0644 ('memo', 'write', 'OVERWRITE'), # all memo list writing 0645 ('t9_udb', 'write', 'OVERWRITE'), 0646 ) 0647 if __debug__: 0648 _supportedsyncs+=( 0649 ('t9_udb', 'read', 'OVERWRITE'), 0650 ) 0651 0652 0653 def convertphonebooktophone(self, helper, data): 0654 """Converts the data to what will be used by the phone 0655 0656 @param data: contains the dict returned by getfundamentals 0657 as well as where the results go""" 0658 results={} 0659 0660 self.normalisegroups(helper, data) 0661 0662 for pbentry in data['phonebook']: 0663 if len(results)==self.protocolclass.NUMPHONEBOOKENTRIES: 0664 break 0665 e={} # entry out 0666 entry=data['phonebook'][pbentry] # entry in 0667 try: 0668 # serials 0669 serial1=helper.getserial(entry.get('serials', []), self.serialsname, data['uniqueserial'], 'serial1', 0) 0670 serial2=helper.getserial(entry.get('serials', []), self.serialsname, data['uniqueserial'], 'serial2', serial1) 0671 0672 e['serial1']=serial1 0673 e['serial2']=serial2 0674 for ss in entry["serials"]: 0675 if ss["sourcetype"]=="bitpim": 0676 e['bitpimserial']=ss 0677 assert e['bitpimserial'] 0678 0679 # name 0680 e['name']=helper.getfullname(entry.get('names', []),1,1,32)[0] 0681 0682 # ice 0683 e['ice']=entry.get('ice', None) 0684 0685 # categories/groups 0686 cat=helper.makeone(helper.getcategory(entry.get('categories', []),0,1,32), None) 0687 if cat is None: 0688 e['group']=0 0689 else: 0690 key,value=self._getgroup(cat, data['groups']) 0691 if key is not None: 0692 e['group']=key 0693 else: 0694 # sorry no space for this category 0695 e['group']=0 0696 0697 # email addresses 0698 emails=helper.getemails(entry.get('emails', []) ,0,self.protocolclass.NUMEMAILS,48) 0699 e['emails']=helper.filllist(emails, self.protocolclass.NUMEMAILS, "") 0700 0701 # phone numbers 0702 # there must be at least one email address or phonenumber 0703 minnumbers=1 0704 if len(emails): minnumbers=0 0705 numbers=helper.getnumbers(entry.get('numbers', []),minnumbers,self.protocolclass.NUMPHONENUMBERS) 0706 e['numbertypes']=[] 0707 e['numbers']=[] 0708 e['speeddials']=[] 0709 for numindex in range(len(numbers)): 0710 num=numbers[numindex] 0711 # deal with type 0712 b4=len(e['numbertypes']) 0713 type=num['type'] 0714 for i,t in enumerate(self.protocolclass.numbertypetab): 0715 if type==t: 0716 # some voodoo to ensure the second home becomes home2 0717 if i in e['numbertypes'] and t[-1]!='2': 0718 type+='2' 0719 continue 0720 e['numbertypes'].append(i) 0721 break 0722 if t=='none': # conveniently last entry 0723 e['numbertypes'].append(i) 0724 break 0725 if len(e['numbertypes'])==b4: 0726 # we couldn't find a type for the number 0727 helper.add_error_message('Number %s (%s/%s) not supported and ignored.'% 0728 (num['number'], e['name'], num['type'])) 0729 continue 0730 # deal with number 0731 number=self.phonize(num['number']) 0732 if len(number)==0: 0733 # no actual digits in the number 0734 continue 0735 if len(number)>24: # get this number from somewhere sensible 0736 # ::TODO:: number is too long and we have to either truncate it or ignore it? 0737 number=number[:24] # truncate for moment 0738 e['numbers'].append(number) 0739 # deal with speed dial 0740 sd=num.get("speeddial", None) 0741 if sd is not None and \ 0742 sd>=self.protocolclass.FIRSTSPEEDDIAL and \ 0743 sd<=self.protocolclass.LASTSPEEDDIAL: 0744 e['speeddials'].append(sd) 0745 else: 0746 e['speeddials'].append(None) 0747 0748 if len(e['numbers'])<minnumbers: 0749 # we couldn't find any numbers 0750 # for this entry, so skip it, entries with no numbers cause error 0751 helper.add_error_message("Name: %s. No suitable numbers or emails found" % e['name']) 0752 continue 0753 e['numbertypes']=helper.filllist(e['numbertypes'], self.protocolclass.NUMPHONENUMBERS, 0) 0754 e['numbers']=helper.filllist(e['numbers'], self.protocolclass.NUMPHONENUMBERS, "") 0755 e['speeddials']=helper.filllist(e['speeddials'], self.protocolclass.NUMPHONENUMBERS, None) 0756 0757 # ringtones, wallpaper 0758 e['ringtone']=helper.getringtone(entry.get('ringtones', []), 'call', None) 0759 e['wallpaper']=helper.getwallpaper(entry.get('wallpapers', []), 'call', None) 0760 0761 results[pbentry]=e 0762 0763 except helper.ConversionFailed: 0764 continue 0765 0766 data['phonebook']=results 0767 return data 0768
Generated by PyXR 0.9.4