Package phones :: Module com_lgvx8550
[hide private]
[frames] | no frames]

Source Code for Module phones.com_lgvx8550

  1  #!/usr/bin/env python 
  2   
  3  ### BITPIM 
  4  ### 
  5  ### Copyright (C) 2007-2008 Nathan Hjelm <hjelmn@users.sourceforge.net> 
  6  ### 
  7  ### This program is free software; you can redistribute it and/or modify 
  8  ### it under the terms of the BitPim license as detailed in the LICENSE file. 
  9  ### $Id: com_lgvx8550.py 4712 2008-10-07 14:00:07Z hjelmn $ 
 10   
 11   
 12  """ 
 13  Communicate with the LG VX8550 cell phone. 
 14  """ 
 15   
 16  # BitPim modules 
 17  import common 
 18  import com_brew 
 19  import bpcalendar 
 20  import prototypes 
 21  import com_lgvx8700 
 22  import com_lgvx8500 
 23  import p_lgvx8550 
 24  import p_brew 
 25  import helpids 
 26  import copy 
 27  import time 
 28  import os.path 
 29   
 30  DEBUG1=False 
 31  #------------------------------------------------------------------------------- 
 32  parentphone=com_lgvx8700.Phone 
33 -class Phone(parentphone):
34 desc="LG-VX8550" 35 helpid=None 36 protocolclass=p_lgvx8550 37 serialsname='lgvx8550' 38 39 my_model='VX8550' 40 41 calendarringerlocation='sch/toolsRinger.dat' 42
43 - def setDMversion(self):
44 _fw_version=self.get_firmware_version()[-1] 45 if self.my_model=='VX8550' and _fw_version>'3': 46 # VX855V04 47 self._DMv5 = False 48 self._DMv6 = True 49 else: 50 self._DMv5 = True 51 self._DMv6 = False
52 53 54 # Fundamentals: 55 # - get_esn - same as LG VX-8300 56 # - getgroups - same as LG VX-8700 57 # - getwallpaperindices - LGUncountedIndexedMedia 58 # - getringtoneindices - LGUncountedIndexedMedia 59 # - DM Version - 5 (VX855V03 or older), 6 (VX855V04) 60
61 - def _get_speeddials(self):
62 """Return the speed dials dict""" 63 speeds={} 64 try: 65 if self.protocolclass.NUMSPEEDDIALS: 66 self.log("Reading speed dials") 67 sd=self.readobject(self.protocolclass.speed_file_name, 68 self.protocolclass.speeddials, 'Reading speed dials') 69 for _idx,_entry in enumerate(sd.speeddials): 70 if _entry.valid(): 71 speeds.setdefault(_entry.entry, {}).update({ _entry.number: _idx }) 72 except com_brew.BrewNoSuchFileException: 73 pass 74 return speeds
75
76 - def _build_media_dict(self, fundamentals, media_data, index_name):
77 """Build & return a dict with keys being the media filenames and 78 values being the name of the index item (index['name']) 79 """ 80 _res={} 81 _media_index=fundamentals.get(index_name, {}) 82 for _item in media_data.items: 83 _pathname=_item.pathname 84 if _pathname and not _res.has_key(_pathname): 85 # not already in dict, look up the name if any 86 _res[_pathname]=None 87 for _entry in _media_index.values(): 88 if _entry.get('filename', None)==_pathname: 89 _res[_pathname]=_entry['name'] 90 break 91 return _res
92
93 - def _get_path_index(self, index_file):
94 buf = prototypes.buffer(self.getfilecontents(index_file)) 95 _path_file=self.protocolclass.PathIndexFile() 96 _path_file.readfrombuffer(buf, logtitle="Read path index: " + index_file) 97 return _path_file
98
99 - def _build_ice_dict(self):
100 # Return an ICE dict for building phone entries 101 _res={} 102 _ice=self.readobject(self.protocolclass.ice_file_name, 103 self.protocolclass.iceentryfile, 104 logtitle='Reading ICE entries') 105 for _item in _ice.items: 106 if _item.valid(): 107 _res[_item.pb_index]=_item.entry_number 108 return _res
109
110 - def getphonebook (self, result):
111 """Reads the phonebook data. The L{getfundamentals} information will 112 already be in result.""" 113 # Read speed dials first -- same file format as the VX-8100 114 _speeds=self._get_speeddials() 115 116 # Read the emergency contacts list 117 self.log("Reading ICE entries") 118 _ices=self._build_ice_dict() 119 120 self.log("Reading phonebook entries") 121 pb_entries=self.readobject(self.protocolclass.pb_file_name, 122 self.protocolclass.pbfile, 123 logtitle='Reading phonebook entries') 124 125 self.log("Reading phone numbers") 126 pb_numbers=self.readobject(self.protocolclass.pn_file_name, 127 self.protocolclass.pnfile, 128 logtitle='Reading phonebook numbers') 129 130 self.log("Reading Ringtone IDs") 131 ring_pathf=self._get_path_index(self.protocolclass.RTPathIndexFile) 132 _rt_ids=self._build_media_dict(result, ring_pathf, 'ringtone-index') 133 134 self.log("Reading Picture IDs") 135 picid_pathf=self._get_path_index(self.protocolclass.WPPathIndexFile) 136 _wp_ids=self._build_media_dict(result, picid_pathf, 'wallpaper-index') 137 138 pbook={} 139 for _cnt in range(self.protocolclass.NUMPHONEBOOKENTRIES): 140 pb_entry=pb_entries.items[_cnt] 141 if not pb_entry.valid(): 142 continue 143 try: 144 self.log("Parse entry "+`_cnt`+" - " + pb_entry.name) 145 pbook[_cnt]=self.extractphonebookentry(pb_entry, pb_numbers, 146 _speeds, _ices, result, 147 _rt_ids.get(ring_pathf.items[_cnt].pathname, None), 148 _wp_ids.get(picid_pathf.items[_cnt].pathname, None)) 149 150 self.progress(_cnt, self.protocolclass.NUMPHONEBOOKENTRIES, pb_entry.name) 151 except common.PhoneBookBusyException: 152 raise 153 except Exception, e: 154 # Something's wrong with this entry, log it and skip 155 self.log('Failed to parse entry %d'%_cnt) 156 self.log('Exception %s raised'%`e`) 157 if __debug__: 158 raise 159 160 self.progress(self.protocolclass.NUMPHONEBOOKENTRIES, 161 self.protocolclass.NUMPHONEBOOKENTRIES, 162 "Phone book read completed") 163 164 result['phonebook']=pbook 165 cats=[] 166 for i in result['groups']: 167 if result['groups'][i]['name']!='No Group': 168 cats.append(result['groups'][i]['name']) 169 result['categories']=cats 170 return pbook
171
172 - def extractphonebookentry(self, entry, numbers, speeds, ices, fundamentals, 173 rt_name, wp_name):
174 """Return a phonebook entry in BitPim format. This is called from getphonebook.""" 175 res={} 176 # serials 177 res['serials']=[ {'sourcetype': self.serialsname, 178 'sourceuniqueid': fundamentals['uniqueserial'], 179 'serial1': entry.entry_number1, 180 'serial2': entry.entry_number1 } ] 181 182 # only one name 183 res['names']=[ {'full': entry.name} ] 184 185 # only one category 186 cat=fundamentals['groups'].get(entry.group, {'name': "No Group"})['name'] 187 if cat!="No Group": 188 res['categories']=[ {'category': cat} ] 189 190 # emails 191 res['emails']=[] 192 for i in entry.emails: 193 if len(i.email): 194 res['emails'].append( {'email': i.email} ) 195 if not len(res['emails']): del res['emails'] # it was empty 196 197 # wallpapers 198 if entry.wallpaper!=self.protocolclass.NOWALLPAPER: 199 try: 200 if entry.wallpaper == 0x64: 201 paper = wp_name 202 else: 203 paper = fundamentals['wallpaper-index'][entry.wallpaper]['name'] 204 205 if paper is None: 206 raise 207 208 res['wallpapers']=[ {'wallpaper': paper, 'use': 'call'} ] 209 except: 210 print "can't find wallpaper for index",entry.wallpaper 211 212 # ringtones 213 if entry.ringtone != self.protocolclass.NORINGTONE: 214 try: 215 if entry.ringtone == 0x64: 216 tone = rt_name 217 else: 218 tone = fundamentals['ringtone-index'][entry.ringtone]['name'] 219 220 if tone is None: 221 raise 222 223 res['ringtones']=[ {'ringtone': tone, 'use': 'call'} ] 224 except: 225 print "can't find ringtone for index",entry.ringtone 226 # assume we are like the VX-8100 in this regard -- looks correct 227 res=self._assignpbtypeandspeeddialsbytype(entry, numbers, speeds, res) 228 229 # assign the ICE entry to the associated contact to keep them in sync 230 res=self._assigniceentry(entry, numbers, ices, res) 231 232 return res
233
234 - def _assignpbtypeandspeeddialsbytype(self, entry, numbers, speeds, res):
235 # for some phones (e.g. vx8100) the speeddial numberindex is really the numbertype (now why would LG want to change this!) 236 res['numbers']=[] 237 238 for i in range(self.protocolclass.NUMPHONENUMBERS): 239 if entry.numberindices[i].numberindex >= self.protocolclass.NUMPHONENUMBERENTRIES: 240 # invalid number 241 continue 242 _pnentry=numbers.items[entry.numberindices[i].numberindex] 243 num=_pnentry.phone_number 244 245 if len(num): 246 if _pnentry.malformed(): 247 print "malformed phone number entry encountered" 248 249 # use the type from the phonebook entry 250 num_type = entry.numbertypes[i].numbertype 251 252 t = self.protocolclass.numbertypetab[num_type] 253 if t[-1]=='2': 254 t=t[:-1] 255 res['numbers'].append({'number': num, 'type': t}) 256 # if this is a speeddial number set it 257 if speeds.has_key(entry.entry_number0) and \ 258 speeds[entry.entry_number0].has_key(num_type): 259 res['numbers'][i]['speeddial']=speeds[entry.entry_number0][num_type] 260 return res
261
262 - def _assigniceentry(self, entry, numbers, ices, res):
263 if ices.has_key(entry.entry_number0): 264 # this contact entry is an ICE entry 265 res['ice']=[ { 'iceindex': ices[entry.entry_number0] } ] 266 return res
267
268 - def _get_next_pb_id(self):
269 """Return the next available pbentry ID""" 270 return self.readobject(self.protocolclass.pb_recordid_filename, 271 self.protocolclass.RecordIdEntry, 272 logtitle='Reading record_id').idnum
273
274 - def _save_next_pb_id(self, idnum):
275 """Save the next pbentry ID""" 276 self.writeobject(self.protocolclass.pb_recordid_filename, 277 self.protocolclass.RecordIdEntry(idnum=idnum), 278 logtitle='Writing record_id', 279 uselocalfs=DEBUG1)
280
281 - def savephonebook (self, data):
282 "Saves out the phonebook" 283 self.savegroups (data) 284 285 ring_pathf=self.protocolclass.PathIndexFile() 286 picid_pathf=self.protocolclass.PathIndexFile() 287 288 # the pbentry.dat will be overwritten so there is no need to delete entries 289 pbook = data.get('phonebook', {}) 290 keys = pbook.keys () 291 keys.sort () 292 293 _rt_index=data.get('ringtone-index', {}) 294 _wp_index=data.get('wallpaper-index', {}) 295 296 entry_num0 = 0 297 entry_num1 = self._get_next_pb_id() 298 pb_entries = self.protocolclass.pbfile(model_name=self.my_model) 299 pn_entries = self.protocolclass.pnfile() 300 301 ice_entries = self.protocolclass.iceentryfile() 302 for i in range(self.protocolclass.NUMEMERGENCYCONTACTS): 303 ice_entries.items.append (self.protocolclass.iceentry()) 304 305 speeddials={} 306 307 for i in keys: 308 pb_entries.items.append(self.make_entry (pn_entries, speeddials, ice_entries, 309 entry_num0, entry_num1, pbook[i], 310 data, ring_pathf,_rt_index, 311 picid_pathf, _wp_index)) 312 entry_num0 += 1 313 if entry_num0 >= self.protocolclass.NUMPHONEBOOKENTRIES: 314 self.log ("Maximum number of phonebook entries reached") 315 break 316 if entry_num1==0xffffffff: 317 entry_num1=0 318 else: 319 entry_num1+=1 320 321 # write phonebook entries 322 self.log ("Writing phonebook entries") 323 self.writeobject(self.protocolclass.pb_file_name, 324 pb_entries, 325 logtitle='Writing phonebook entries', 326 uselocalfs=DEBUG1) 327 # write phone numbers 328 self.log ("Writing phone numbers") 329 self.writeobject(self.protocolclass.pn_file_name, 330 pn_entries, logtitle='Writing phonebook numbers', 331 uselocalfs=DEBUG1) 332 # write ringtone index 333 self.log('Writing ringtone ID') 334 self.writeobject(self.protocolclass.RTPathIndexFile, 335 ring_pathf, logtitle='Writing ringtone paths', 336 uselocalfs=DEBUG1) 337 # write wallpaper index 338 self.log('Writing picture ID') 339 self.writeobject(self.protocolclass.WPPathIndexFile, 340 picid_pathf, logtitle='Writing wallpaper paths', 341 uselocalfs=DEBUG1) 342 343 # write ICE index 344 self.log('Writing ICE entries') 345 self.writeobject(self.protocolclass.ice_file_name, 346 ice_entries, logtitle='Writing ICE entries', 347 uselocalfs=DEBUG1) 348 349 # update speed dials 350 req=self.protocolclass.speeddials() 351 # slot 0 is always unused 352 req.speeddials.append(self.protocolclass.speeddial()) 353 # if empty, slot 1 is for voicemail 354 if speeddials.has_key(1): 355 req.speeddials.append(self.protocolclass.speeddial(entry=speeddials[1]['entry'], 356 number=speeddials[1]['type'])) 357 else: 358 req.speeddials.append(self.protocolclass.speeddial(entry=1000, 359 number=6)) 360 for i in range(2, self.protocolclass.NUMSPEEDDIALS): 361 sd=self.protocolclass.speeddial() 362 if speeddials.has_key(i): 363 sd.entry=speeddials[i]['entry'] 364 sd.number=speeddials[i]['type'] 365 req.speeddials.append(sd) 366 367 self.log('Writing speed dials') 368 self.writeobject(self.protocolclass.speed_file_name, 369 req, logtitle='Writing speed dials data', 370 uselocalfs=DEBUG1) 371 372 # update the next pbentries ID 373 self._save_next_pb_id(entry_num1) 374 data["rebootphone"]=True 375 376 return data
377
378 - def make_pn_entry (self, phone_number, number_type, pn_id, pbpn_id, pe_id):
379 """ Create a non-blank pnfileentry frome a phone number string """ 380 if len(phone_number) == 0: 381 raise 382 383 new_entry = self.protocolclass.pnfileentry(entry_tag=self.protocolclass.PB_NUMBER_SOR) 384 new_entry.pn_id = pn_id 385 new_entry.pe_id = pe_id 386 new_entry.phone_number = phone_number 387 new_entry.ntype = number_type 388 new_entry.pn_order = pbpn_id 389 390 return new_entry
391
392 - def make_ice_entry (self, ice_id, pb_id):
393 """ Create a iceentry from a pb_id and ice_id """ 394 new_entry = self.protocolclass.iceentry() 395 396 new_entry.entry_assigned = 1 397 new_entry.entry_number = ice_id 398 new_entry.pb_index = pb_id 399 400 return new_entry
401
402 - def make_entry (self, pn_entries, speeddials, ice_entries, 403 entry_num0, entry_num1, pb_entry, data, 404 ring_pathf, rt_index, picid_pathf, wp_index):
405 """ Create a pbfileentry from a bitpim phonebook entry """ 406 new_entry = self.protocolclass.pbfileentry(entry_tag=self.protocolclass.PB_ENTRY_SOR) 407 # entry IDs 408 new_entry.entry_number0 = entry_num0 409 new_entry.entry_number1 = entry_num1 410 411 for key in pb_entry: 412 if key in ('emails', 'numbertypes'): 413 l = getattr (new_entry, key) 414 for item in pb_entry[key]: 415 l.append(item) 416 elif key == 'numbers': 417 l = getattr (new_entry, 'numberindices') 418 for i in range(0, self.protocolclass.NUMPHONENUMBERS): 419 new_pn_id = len (pn_entries.items) 420 if new_pn_id == self.protocolclass.NUMPHONENUMBERENTRIES: 421 # this state should not be possible. should this raise an exception? 422 self.log ("Maximum number of phone numbers reached") 423 break 424 425 try: 426 pn_entries.items.append(self.make_pn_entry (pb_entry[key][i],pb_entry['numbertypes'][i], new_pn_id, i, entry_num0)) 427 l.append (new_pn_id) 428 except: 429 l.append (0xffff) 430 elif key == 'speeddials': 431 for _sd,_num_type in zip(pb_entry['speeddials'], pb_entry['numbertypes']): 432 if _sd is not None: 433 speeddials[_sd]={ 'entry': entry_num0, 434 'type': _num_type } 435 elif key == 'ice': 436 # In Case of Emergency 437 _ice = pb_entry['ice'] 438 if _ice is not None and len(_ice) > 0: 439 _ice_entry = _ice[0]['iceindex'] 440 ice_entries.items[_ice_entry] = self.make_ice_entry (_ice_entry, entry_num0) 441 elif key == 'ringtone': 442 new_entry.ringtone = self._findmediainindex(data['ringtone-index'], pb_entry['ringtone'], pb_entry['name'], 'ringtone') 443 try: 444 _filename = rt_index[new_entry.ringtone]['filename'] 445 ring_pathf.items.append(self.protocolclass.PathIndexEntry(pathname=_filename)) 446 new_entry.ringtone = 0x64 447 except: 448 ring_pathf.items.append(self.protocolclass.PathIndexEntry()) 449 elif key == 'wallpaper': 450 new_entry.wallpaper = self._findmediainindex(data['wallpaper-index'], pb_entry['wallpaper'], pb_entry['name'], 'wallpaper') 451 try: 452 _filename = wp_index[new_entry.wallpaper]['filename'] 453 picid_pathf.items.append(self.protocolclass.PathIndexEntry(pathname=_filename)) 454 new_entry.wallpaper = 0x64 455 except: 456 picid_pathf.items.append(self.protocolclass.PathIndexEntry()) 457 elif key in new_entry.getfields(): 458 setattr (new_entry, key, pb_entry[key]) 459 460 return new_entry
461
462 - def getcalendar(self,result):
463 res={} 464 # Read exceptions file first 465 exceptions = self.getexceptions() 466 467 try: 468 buf = prototypes.buffer(self.getfilecontents(self.calendarringerlocation)) 469 ringersf = self.protocolclass.scheduleringerfile() 470 ringersf.readfrombuffer (buf) 471 except: 472 self.log ("unable to read schedule ringer path file") 473 474 # Now read schedule 475 try: 476 buf=prototypes.buffer(self.getfilecontents(self.calendarlocation)) 477 if len(buf.getdata())<3: 478 # file is empty, and hence same as non-existent 479 raise com_brew.BrewNoSuchFileException() 480 sc=self.protocolclass.schedulefile() 481 sc.readfrombuffer(buf, logtitle="Calendar") 482 for event in sc.events: 483 # the vx8100 has a bad entry when the calender is empty 484 # stop processing the calender when we hit this record 485 if event.pos==0: #invalid entry 486 continue 487 entry=bpcalendar.CalendarEntry() 488 try: # delete events are still in the calender file but have garbage dates 489 self.getcalendarcommon(entry, event) 490 except ValueError: 491 continue 492 try: 493 if (event.ringtone >= 100): # MIC Ringer is downloaded to phone or microSD 494 entry.ringtone = common.basename(ringersf.ringerpaths[event.ringtone-100].path) 495 else: # MIC Ringer is built-in 496 entry.ringtone=self.builtinringtones[event.ringtone] 497 except: 498 self.log ("Setting default ringer for event\n") 499 # hack, not having a phone makes it hard to figure out the best approach 500 if entry.alarm==None: 501 entry.ringtone='No Ring' 502 else: 503 entry.ringtone='Loud Beeps' 504 # check for exceptions and remove them 505 if event.repeat[3] and exceptions.has_key(event.pos): 506 for year, month, day in exceptions[event.pos]: 507 entry.suppress_repeat_entry(year, month, day) 508 res[entry.id]=entry 509 510 assert sc.numactiveitems==len(res) 511 except com_brew.BrewNoSuchFileException: 512 pass # do nothing if file doesn't exist 513 result['calendar']=res 514 return result
515
516 - def _scheduleextras(self, data, fwversion):
517 data.serial_number = '000000ca-00000000-00000000-' + fwversion 518 data.unknown3 = 0x01fb
519
520 - def savecalendar(self, dict, merge):
521 # ::TODO:: 522 # what will be written to the files 523 eventsf = self.protocolclass.schedulefile() 524 exceptionsf = self.protocolclass.scheduleexceptionfile() 525 ringersf = self.protocolclass.scheduleringerfile() 526 # what are we working with 527 cal=dict['calendar'] 528 newcal={} 529 #sort into start order, makes it possible to see if the calendar has changed 530 keys=[(x.start, k) for k,x in cal.items()] 531 keys.sort() 532 # apply limiter 533 keys=keys[:self.protocolclass.NUMCALENDARENTRIES] 534 # number of entries 535 eventsf.numactiveitems=len(keys) 536 ringersf.numringers = 0 537 pos = 0 538 # get phone firmware version for serial number 539 try: 540 req = p_brew.firmwarerequest() 541 res = self.sendbrewcommand(req, self.protocolclass.firmwareresponse) 542 _fwversion = res.firmware 543 except: 544 _fwversion = '00000000' 545 546 # play with each entry 547 for (_,k) in keys: 548 # entry is what we will return to user 549 entry=cal[k] 550 data=self.protocolclass.scheduleevent() 551 # using the packetsize() method here will fill the LIST with default entries 552 data.pos = pos * data.packet_size + 2 553 self._schedulecommon(entry, data) 554 alarm_set=self.setalarm(entry, data) 555 if alarm_set: 556 if entry.ringtone=="No Ring" and not entry.vibrate: 557 alarm_name="Low Beep Once" 558 else: 559 alarm_name=entry.ringtone 560 else: # set alarm to "No Ring" gets rid of alarm icon on phone 561 alarm_name="No Ring" 562 for i in dict['ringtone-index']: 563 self.log ('ringtone ' + str(i) + ': ' + dict['ringtone-index'][i]['name'] + ' alarm-name = ' + alarm_name) 564 if dict['ringtone-index'][i]['name']==alarm_name: 565 if dict['ringtone-index'][i].get('filename', None): 566 data.ringtone = 100 + ringersf.numringers 567 ringersf.ringerpaths.append(dict['ringtone-index'][i]['filename']) 568 ringersf.numringers = ringersf.numringers + 1 569 else: 570 # builtin ringer 571 data.ringtone=i # Set to proper index 572 break 573 # check for exceptions and add them to the exceptions list 574 self._scheduleexceptions(entry, data, exceptionsf) 575 self._scheduleextras(data, _fwversion) 576 # put entry in nice shiny new dict we are building 577 entry=copy.copy(entry) 578 newcal[data.pos]=entry 579 eventsf.events.append(data) 580 pos = pos + 1 581 582 buf=prototypes.buffer() 583 eventsf.writetobuffer(buf, logtitle="New Calendar") 584 self.writefile(self.calendarlocation, buf.getvalue()) 585 self.log("Your phone has to be rebooted due to the calendar changing") 586 dict["rebootphone"]=True 587 588 buf=prototypes.buffer() 589 exceptionsf.writetobuffer(buf, logtitle="Writing calendar exceptions") 590 self.writefile(self.calendarexceptionlocation, buf.getvalue()) 591 592 buf = prototypes.buffer() 593 ringersf.writetobuffer(buf, logtitle="Writing calendar ringers") 594 self.writefile(self.calendarringerlocation, buf.getvalue()) 595 596 # fix passed in dict 597 dict['calendar']=newcal 598 599 return dict
600 601 #------------------------------------------------------------------------------- 602 parentprofile=com_lgvx8500.Profile
603 -class Profile(parentprofile):
604 protocolclass=Phone.protocolclass 605 serialsname=Phone.serialsname 606 607 BP_Calendar_Version=3 608 phone_manufacturer='LG Electronics Inc' 609 phone_model='VX8550' 610 # inside screen resoluation 611 WALLPAPER_WIDTH=176 612 WALLPAPER_HEIGHT=220 613 614 imageorigins={} 615 imageorigins.update(common.getkv(parentprofile.stockimageorigins, "images")) 616 imageorigins.update(common.getkv(parentprofile.stockimageorigins, "video")) 617 imageorigins.update(common.getkv(parentprofile.stockimageorigins, "images(sd)")) 618 imageorigins.update(common.getkv(parentprofile.stockimageorigins, "video(sd)")) 619 620 # our targets are the same for all origins 621 imagetargets={} 622 imagetargets.update(common.getkv(parentprofile.stockimagetargets, "fullscreen", 623 {'width': 238, 'height': 246, 'format': "JPEG"})) 624 imagetargets.update(common.getkv(parentprofile.stockimagetargets, "wallpaper", 625 {'width': 240, 'height': 274, 'format': "JPEG"})) 626 imagetargets.update(common.getkv(parentprofile.stockimagetargets, "pictureid", 627 {'width': 120, 'height': 100, 'format': "JPEG"})) 628 629 _supportedsyncs=( 630 ('phonebook', 'read', None), # all phonebook reading 631 ('calendar', 'read', None), # all calendar reading 632 ('wallpaper', 'read', None), # all wallpaper reading 633 ('ringtone', 'read', None), # all ringtone reading 634 ('call_history', 'read', None),# all call history list reading 635 ('sms', 'read', None), # all SMS list reading 636 ('memo', 'read', None), # all memo list reading 637 ('phonebook', 'write', 'OVERWRITE'), # only overwriting phonebook 638 ('calendar', 'write', 'OVERWRITE'), # only overwriting calendar 639 ('wallpaper', 'write', 'MERGE'), # merge and overwrite wallpaper 640 ('wallpaper', 'write', 'OVERWRITE'), 641 ('ringtone', 'write', 'MERGE'), # merge and overwrite ringtone 642 ('ringtone', 'write', 'OVERWRITE'), 643 ('sms', 'write', 'OVERWRITE'), # all SMS list writing 644 ('memo', 'write', 'OVERWRITE'), # all memo list writing 645 ('t9_udb', 'write', 'OVERWRITE'), 646 ) 647 if __debug__: 648 _supportedsyncs+=( 649 ('t9_udb', 'read', 'OVERWRITE'), 650 ) 651 652
653 - def convertphonebooktophone(self, helper, data):
654 """Converts the data to what will be used by the phone 655 656 @param data: contains the dict returned by getfundamentals 657 as well as where the results go""" 658 results={} 659 660 self.normalisegroups(helper, data) 661 662 for pbentry in data['phonebook']: 663 if len(results)==self.protocolclass.NUMPHONEBOOKENTRIES: 664 break 665 e={} # entry out 666 entry=data['phonebook'][pbentry] # entry in 667 try: 668 # serials 669 serial1=helper.getserial(entry.get('serials', []), self.serialsname, data['uniqueserial'], 'serial1', 0) 670 serial2=helper.getserial(entry.get('serials', []), self.serialsname, data['uniqueserial'], 'serial2', serial1) 671 672 e['serial1']=serial1 673 e['serial2']=serial2 674 for ss in entry["serials"]: 675 if ss["sourcetype"]=="bitpim": 676 e['bitpimserial']=ss 677 assert e['bitpimserial'] 678 679 # name 680 e['name']=helper.getfullname(entry.get('names', []),1,1,32)[0] 681 682 # ice 683 e['ice']=entry.get('ice', None) 684 685 # categories/groups 686 cat=helper.makeone(helper.getcategory(entry.get('categories', []),0,1,32), None) 687 if cat is None: 688 e['group']=0 689 else: 690 key,value=self._getgroup(cat, data['groups']) 691 if key is not None: 692 e['group']=key 693 else: 694 # sorry no space for this category 695 e['group']=0 696 697 # email addresses 698 emails=helper.getemails(entry.get('emails', []) ,0,self.protocolclass.NUMEMAILS,48) 699 e['emails']=helper.filllist(emails, self.protocolclass.NUMEMAILS, "") 700 701 # phone numbers 702 # there must be at least one email address or phonenumber 703 minnumbers=1 704 if len(emails): minnumbers=0 705 numbers=helper.getnumbers(entry.get('numbers', []),minnumbers,self.protocolclass.NUMPHONENUMBERS) 706 e['numbertypes']=[] 707 e['numbers']=[] 708 e['speeddials']=[] 709 for numindex in range(len(numbers)): 710 num=numbers[numindex] 711 # deal with type 712 b4=len(e['numbertypes']) 713 type=num['type'] 714 for i,t in enumerate(self.protocolclass.numbertypetab): 715 if type==t: 716 # some voodoo to ensure the second home becomes home2 717 if i in e['numbertypes'] and t[-1]!='2': 718 type+='2' 719 continue 720 e['numbertypes'].append(i) 721 break 722 if t=='none': # conveniently last entry 723 e['numbertypes'].append(i) 724 break 725 if len(e['numbertypes'])==b4: 726 # we couldn't find a type for the number 727 helper.add_error_message('Number %s (%s/%s) not supported and ignored.'% 728 (num['number'], e['name'], num['type'])) 729 continue 730 # deal with number 731 number=self.phonize(num['number']) 732 if len(number)==0: 733 # no actual digits in the number 734 continue 735 if len(number) > 48: # get this number from somewhere sensible 736 # ::TODO:: number is too long and we have to either truncate it or ignore it? 737 number=number[:48] # truncate for moment 738 e['numbers'].append(number) 739 # deal with speed dial 740 sd=num.get("speeddial", None) 741 if sd is not None and \ 742 sd>=self.protocolclass.FIRSTSPEEDDIAL and \ 743 sd<=self.protocolclass.LASTSPEEDDIAL: 744 e['speeddials'].append(sd) 745 else: 746 e['speeddials'].append(None) 747 748 if len(e['numbers'])<minnumbers: 749 # we couldn't find any numbers 750 # for this entry, so skip it, entries with no numbers cause error 751 helper.add_error_message("Name: %s. No suitable numbers or emails found" % e['name']) 752 continue 753 e['numbertypes']=helper.filllist(e['numbertypes'], self.protocolclass.NUMPHONENUMBERS, 0) 754 e['numbers']=helper.filllist(e['numbers'], self.protocolclass.NUMPHONENUMBERS, "") 755 e['speeddials']=helper.filllist(e['speeddials'], self.protocolclass.NUMPHONENUMBERS, None) 756 757 # ringtones, wallpaper 758 e['ringtone']=helper.getringtone(entry.get('ringtones', []), 'call', None) 759 e['wallpaper']=helper.getwallpaper(entry.get('wallpapers', []), 'call', None) 760 761 results[pbentry]=e 762 763 except helper.ConversionFailed: 764 continue 765 766 data['phonebook']=results 767 return data
768