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

Source Code for Module phones.com_lgvx9100

  1  ### BITPIM 
  2  ### 
  3  ### Copyright (C) 2008 Joe Pham <djpham@bitpim.org> 
  4  ### 
  5  ### This program is free software; you can redistribute it and/or modify 
  6  ### it under the terms of the BitPim license as detailed in the LICENSE file. 
  7  ### 
  8  ### $Id: com_lgvx9100.py 4681 2008-08-14 22:41:27Z djpham $ 
  9   
 10  """ 
 11  Communicate with the LG VX9100 (enV2) cell phone.  This is based on the enV model 
 12  """ 
 13   
 14  # BitPim modules 
 15  import common 
 16  import com_brew 
 17  import com_lg 
 18  import com_lgvx8550 
 19  import p_lgvx9100 
 20  import prototypes 
 21  import helpids 
 22  import sms 
 23   
 24  DEBUG1=False 
 25  DEBUG2=False 
 26  #------------------------------------------------------------------------------- 
 27  parentphone=com_lgvx8550.Phone 
28 -class Phone(parentphone):
29 "Talk to the LG VX9100 cell phone" 30 31 desc="LG-VX9100" 32 helpid=helpids.ID_PHONE_LGVX9100 33 protocolclass=p_lgvx9100 34 serialsname='lgvx9100' 35 my_model='VX9100' 36 37 # rintones and wallpaper info, copy from VX9900, may need to change to match 38 # what the phone actually has 39 external_storage_root='mmc1/' 40 builtinringtones= ('Low Beep Once', 'Low Beeps', 'Loud Beep Once', 'Loud Beeps', 'Door Bell', 'VZW Default Tone') + \ 41 tuple(['Ringtone '+`n` for n in range(1,17)]) + \ 42 ('No Ring',) 43 44 ringtonelocations= ( 45 # type index file default dir external dir max type Index 46 ( 'ringers', 'dload/myringtone.dat','brew/mod/10889/ringtones','mmc1/ringers', 100, protocolclass.INDEX_RT_TYPE, 100), 47 ( 'sounds', 'dload/mysound.dat', 'brew/mod/18067', '', 100, protocolclass.INDEX_SOUND_TYPE, None), 48 ( 'sounds(sd)', 'dload/sd_sound.dat', 'mmc1/my_sounds', '', 100, protocolclass.INDEX_SDSOUND_TYPE, None), 49 ## ( 'music', 'dload/efs_music.dat', 'my_music', '', 100, 0x104, None), 50 ## ( 'music(sd)', 'dload/sd_music.dat', 'mmc1/my_music', '', 100, 0x14, None), 51 ) 52 53 wallpaperlocations= ( 54 # type index file default dir external dir max type Index 55 ( 'images', 'dload/image.dat', 'brew/mod/10888', '', 100, protocolclass.INDEX_IMAGE_TYPE, 100), 56 ( 'images(sd)', 'dload/sd_image.dat', 'mmc1/my_pix', '', 100, protocolclass.INDEX_SDIMAGE_TYPE, None), 57 ( 'video', 'dload/video.dat', 'brew/mod/10890', '', 100, protocolclass.INDEX_VIDEO_TYPE, None), 58 ( 'video(sd)', 'dload/sd_video.dat', 'mmc1/my_flix', '', 100, protocolclass.INDEX_SDVIDEO_TYPE, None), 59 ) 60
61 - def __init__(self, logtarget, commport):
62 parentphone.__init__(self, logtarget, commport)
63
64 - def setDMversion(self):
65 self._DMv6=True 66 self._DMv5=False
67 68 # Fundamentals: 69 # - get_esn - same as LG VX-8300 70 # - getgroups - same as LG VX-8100 71 # - getwallpaperindices - LGUncountedIndexedMedia 72 # - getrintoneindices - LGUncountedIndexedMedia 73 # - DM Version - T99VZV01: N/A, T99VZV02: 5 74 75 # phonebook stuff----------------------------------------------------------- 76 # This is essentially the same with the VX-8550 with a few tweaks. 77 # These tweaks are probably applicable to the VX-8550 as well, but since 78 # I can't test them on an actual VX-8550, I'll leave it alone. 79 80 # groups
81 - def getgroups(self, results):
82 "Read groups" 83 # Reads groups that use explicit IDs 84 self.log("Reading group information") 85 g=self.readobject(self.protocolclass.pb_group_filename, 86 self.protocolclass.pbgroups, 87 'Reading groups data') 88 groups={} 89 for _group in g.groups: 90 if _group.name: 91 groups[_group.groupid]= { 'name': _group.name, 92 'user_added': _group.user_added } 93 results['groups'] = groups 94 return groups
95
96 - def savegroups(self, data):
97 groups=data.get('groups', {}) 98 keys=groups.keys() 99 keys.sort() 100 keys.reverse() 101 g=self.protocolclass.pbgroups() 102 # write the No Group entry first 103 g.groups.append(self.protocolclass.pbgroup(name='No Group')) 104 # now write the rest in reverse ID order 105 for k in keys: 106 if not k: 107 # already wrote this one out 108 continue 109 g.groups.append(self.protocolclass.pbgroup(name=groups[k]['name'], 110 groupid=k, 111 user_added=groups[k].get('user_added', 1))) 112 self.writeobject(self.protocolclass.pb_group_filename, g, 113 logtitle='Writing phonebook groups', 114 uselocalfs=DEBUG1)
115
116 - def _get_speeddials(self):
117 """Return the speed dials dict""" 118 speeds={} 119 try: 120 if self.protocolclass.NUMSPEEDDIALS: 121 self.log("Reading speed dials") 122 sd=self.readobject(self.protocolclass.speed_file_name, 123 self.protocolclass.speeddials, 'Reading speed dials') 124 for _idx,_entry in enumerate(sd.speeddials): 125 if _entry.valid(): 126 speeds.setdefault(_entry.entry, {}).update({ _entry.number: _idx }) 127 except com_brew.BrewNoSuchFileException: 128 pass 129 return speeds
130
131 - def _build_media_dict(self, fundamentals, media_data, index_name):
132 """Build & return a dict with keys being the media filenames and 133 values being the name of the index item (index['name']) 134 """ 135 _res={} 136 _media_index=fundamentals.get(index_name, {}) 137 for _item in media_data.items: 138 _pathname=_item.pathname 139 if _pathname and not _res.has_key(_pathname): 140 # not already in dict, look up the name if any 141 _res[_pathname]=None 142 for _entry in _media_index.values(): 143 if _entry.get('filename', None)==_pathname: 144 _res[_pathname]=_entry['name'] 145 break 146 return _res
147
148 - def _build_ice_dict(self):
149 # Return an ICE dict for building phone entries 150 _res={} 151 _ice=self.readobject(self.protocolclass.pb_ice_file_name, 152 self.protocolclass.iceentryfile, 153 logtitle='Reading ICE entries') 154 for _item in _ice.items: 155 if _item.valid(): 156 _res[_item.pb_index]=_item.entry_number 157 return _res
158
159 - def getphonebook (self, result):
160 """Reads the phonebook data. The L{getfundamentals} information will 161 already be in result.""" 162 # Read speed dials first -- same file format as the VX-8100 163 _speeds=self._get_speeddials() 164 165 # Read the emergency contacts list 166 self.log("Reading ICE entries") 167 _ices=self._build_ice_dict() 168 169 self.log("Reading phonebook entries") 170 pb_entries=self.readobject(self.protocolclass.pb_file_name, 171 self.protocolclass.pbfile, 172 logtitle='Reading phonebook entries') 173 174 self.log("Reading phone numbers") 175 pb_numbers=self.readobject(self.protocolclass.pn_file_name, 176 self.protocolclass.pnfile, 177 logtitle='Reading phonebook numbers') 178 179 self.log("Reading Ringtone IDs") 180 ring_pathf=self._get_path_index(self.protocolclass.RTPathIndexFile) 181 _rt_ids=self._build_media_dict(result, ring_pathf, 'ringtone-index') 182 183 self.log("Reading Picture IDs") 184 picid_pathf=self._get_path_index(self.protocolclass.WPPathIndexFile) 185 _wp_ids=self._build_media_dict(result, picid_pathf, 'wallpaper-index') 186 187 pbook={} 188 for _cnt in range(self.protocolclass.NUMPHONEBOOKENTRIES): 189 pb_entry=pb_entries.items[_cnt] 190 if not pb_entry.valid(): 191 continue 192 try: 193 self.log("Parse entry "+`_cnt`+" - " + pb_entry.name) 194 pbook[_cnt]=self.extractphonebookentry(pb_entry, pb_numbers, 195 _speeds, _ices, result, 196 _rt_ids.get(ring_pathf.items[_cnt].pathname, None), 197 _wp_ids.get(picid_pathf.items[_cnt].pathname, None)) 198 199 self.progress(_cnt, self.protocolclass.NUMPHONEBOOKENTRIES, pb_entry.name) 200 except common.PhoneBookBusyException: 201 raise 202 except Exception, e: 203 # Something's wrong with this entry, log it and skip 204 self.log('Failed to parse entry %d'%_cnt) 205 self.log('Exception %s raised'%`e`) 206 if __debug__: 207 raise 208 209 self.progress(self.protocolclass.NUMPHONEBOOKENTRIES, 210 self.protocolclass.NUMPHONEBOOKENTRIES, 211 "Phone book read completed") 212 213 result['phonebook']=pbook 214 cats=[] 215 for i in result['groups']: 216 if result['groups'][i]['name']!='No Group': 217 cats.append(result['groups'][i]['name']) 218 result['categories']=cats 219 return pbook
220
221 - def extractphonebookentry(self, entry, numbers, speeds, ices, fundamentals, 222 rt_name, wp_name):
223 """Return a phonebook entry in BitPim format. This is called from getphonebook.""" 224 res={} 225 # serials 226 res['serials']=[ {'sourcetype': self.serialsname, 227 'sourceuniqueid': fundamentals['uniqueserial'], 228 'serial1': entry.entry_number1, 229 'serial2': entry.entry_number1 } ] 230 231 # only one name 232 res['names']=[ {'full': entry.name} ] 233 234 # only one category 235 cat=fundamentals['groups'].get(entry.group, {'name': "No Group"})['name'] 236 if cat!="No Group": 237 res['categories']=[ {'category': cat} ] 238 239 # emails 240 res['emails']=[] 241 for i in entry.emails: 242 if len(i.email): 243 res['emails'].append( {'email': i.email} ) 244 if not len(res['emails']): del res['emails'] # it was empty 245 246 # wallpapers 247 if entry.wallpaper!=self.protocolclass.NOWALLPAPER: 248 try: 249 if entry.wallpaper == 0x64: 250 paper = wp_name 251 else: 252 paper = fundamentals['wallpaper-index'][entry.wallpaper]['name'] 253 res['wallpapers']=[ {'wallpaper': paper, 'use': 'call'} ] 254 except: 255 print "can't find wallpaper for index",entry.wallpaper 256 257 # ringtones 258 if entry.ringtone != self.protocolclass.NORINGTONE: 259 try: 260 if entry.ringtone == 0x64: 261 tone = rt_name 262 else: 263 tone=fundamentals['ringtone-index'][entry.ringtone]['name'] 264 if tone: 265 res['ringtones']=[ {'ringtone': tone, 'use': 'call'} ] 266 except: 267 print "can't find ringtone for index",entry.ringtone 268 # assume we are like the VX-8100 in this regard -- looks correct 269 res=self._assignpbtypeandspeeddialsbytype(entry, numbers, speeds, res) 270 271 # assign the ICE entry to the associated contact to keep them in sync 272 res=self._assigniceentry(entry, numbers, ices, res) 273 274 return res
275
276 - def _assignpbtypeandspeeddialsbytype(self, entry, numbers, speeds, res):
277 # for some phones (e.g. vx8100) the speeddial numberindex is really the numbertype (now why would LG want to change this!) 278 res['numbers']=[] 279 for i in range(self.protocolclass.NUMPHONENUMBERS): 280 if entry.numberindices[i].numberindex>=\ 281 self.protocolclass.NUMPHONENUMBERENTRIES: 282 # invalid number 283 continue 284 _pnentry=numbers.items[entry.numberindices[i].numberindex] 285 num=_pnentry.phone_number 286 num_type=_pnentry.type 287 if len(num): 288 t=self.protocolclass.numbertypetab[num_type] 289 if t[-1]=='2': 290 t=t[:-1] 291 res['numbers'].append({'number': num, 'type': t}) 292 # if this is a speeddial number set it 293 if speeds.has_key(entry.entry_number0) and \ 294 speeds[entry.entry_number0].has_key(num_type): 295 res['numbers'][i]['speeddial']=speeds[entry.entry_number0][num_type] 296 return res
297
298 - def _assigniceentry(self, entry, numbers, ices, res):
299 if ices.has_key(entry.entry_number0): 300 # this contact entry is an ICE entry 301 res['ice']=[ { 'iceindex': ices[entry.entry_number0] } ] 302 self.log('Entry %d is ICE %d'%(entry.entry_number0, 303 ices[entry.entry_number0])) 304 return res
305
306 - def _get_next_pb_id(self):
307 """Return the next available pbentry ID""" 308 return self.readobject(self.protocolclass.pb_recordid_filename, 309 self.protocolclass.RecordIdEntry, 310 logtitle='Reading record_id').idnum
311 - def _save_next_pb_id(self, idnum):
312 """Save the next pbentry ID""" 313 self.writeobject(self.protocolclass.pb_recordid_filename, 314 self.protocolclass.RecordIdEntry(idnum=idnum), 315 logtitle='Writing record_id', 316 uselocalfs=DEBUG1)
317 - def savephonebook (self, data):
318 "Saves out the phonebook" 319 self.savegroups (data) 320 321 ring_pathf=self.protocolclass.PathIndexFile() 322 picid_pathf=self.protocolclass.PathIndexFile() 323 324 # the pbentry.dat will will be overwritten so there is no need to delete entries 325 pbook = data.get('phonebook', {}) 326 keys = pbook.keys () 327 keys.sort () 328 329 _rt_index=data.get('ringtone-index', {}) 330 _wp_index=data.get('wallpaper-index', {}) 331 332 entry_num0 = 0 333 entry_num1=self._get_next_pb_id() 334 pb_entries = self.protocolclass.pbfile() 335 pn_entries=self.protocolclass.pnfile() 336 ice_entries = self.protocolclass.iceentryfile() 337 for i in range(self.protocolclass.NUMEMERGENCYCONTACTS): 338 ice_entries.items.append (self.protocolclass.iceentry()) 339 speeddials={} 340 for i in keys: 341 pb_entries.items.append(self.make_entry (pn_entries, speeddials, ice_entries, 342 entry_num0, entry_num1, 343 pbook[i], data, 344 ring_pathf,_rt_index, 345 picid_pathf, _wp_index)) 346 entry_num0 += 1 347 if entry_num0 >= self.protocolclass.NUMPHONEBOOKENTRIES: 348 self.log ("Maximum number of phonebook entries reached") 349 break 350 if entry_num1==0xffffffff: 351 entry_num1=0 352 else: 353 entry_num1+=1 354 355 # write phonebook entries 356 self.log ("Writing phonebook entries") 357 self.writeobject(self.protocolclass.pb_file_name, 358 pb_entries, 359 logtitle='Writing phonebook entries', 360 uselocalfs=DEBUG1) 361 # write phone numbers 362 self.log ("Writing phone numbers") 363 self.writeobject(self.protocolclass.pn_file_name, 364 pn_entries, logtitle='Writing phonebook numbers', 365 uselocalfs=DEBUG1) 366 # write ringtone index 367 self.log('Writing ringtone ID') 368 self.writeobject(self.protocolclass.RTPathIndexFile, 369 ring_pathf, logtitle='Writing ringtone paths', 370 uselocalfs=DEBUG1) 371 # write wallpaer index 372 self.log('Writing pciture ID') 373 self.writeobject(self.protocolclass.WPPathIndexFile, 374 picid_pathf, logtitle='Writing wallpaper paths', 375 uselocalfs=DEBUG1) 376 # write ICE index 377 self.log('Writing ICE entries') 378 self.writeobject(self.protocolclass.pb_ice_file_name, 379 ice_entries, logtitle='Writing ICE entries', 380 uselocalfs=DEBUG1) 381 382 # update speed dials 383 req=self.protocolclass.speeddials() 384 # slot 0 is always unused 385 req.speeddials.append(self.protocolclass.speeddial()) 386 # if empty, slot 1 is for voicemail 387 if speeddials.has_key(1): 388 req.speeddials.append(self.protocolclass.speeddial(entry=speeddials[1]['entry'], 389 number=speeddials[1]['type'])) 390 else: 391 req.speeddials.append(self.protocolclass.speeddial(entry=1000, 392 number=6)) 393 for i in range(2, self.protocolclass.NUMSPEEDDIALS): 394 sd=self.protocolclass.speeddial() 395 if speeddials.has_key(i): 396 sd.entry=speeddials[i]['entry'] 397 sd.number=speeddials[i]['type'] 398 req.speeddials.append(sd) 399 self.log('Writing speed dials') 400 self.writeobject(self.protocolclass.speed_file_name, 401 req, logtitle='Writing speed dials data', 402 uselocalfs=DEBUG1) 403 # update the next pbentries ID 404 self._save_next_pb_id(entry_num1) 405 data["rebootphone"]=True 406 407 return data
408
409 - def make_pn_entry (self, phone_number, number_type, pn_id, pbpn_id, pe_id):
410 """ Create a non-blank pnfileentry frome a phone number string """ 411 if len(phone_number) == 0: 412 raise 413 414 new_entry = self.protocolclass.pnfileentry(entry_tag=self.protocolclass.PB_NUMBER_SOR) 415 new_entry.pn_id = pn_id 416 new_entry.pe_id = pe_id 417 new_entry.phone_number = phone_number 418 new_entry.type = number_type 419 new_entry.pn_order = pbpn_id 420 421 return new_entry
422
423 - def make_ice_entry (self, ice_id, pb_id):
424 """ Create a iceentry from a pb_id and ice_id """ 425 new_entry = self.protocolclass.iceentry() 426 427 new_entry.entry_assigned = 1 428 new_entry.entry_number = ice_id 429 new_entry.pb_index = pb_id 430 431 return new_entry
432
433 - def make_entry (self, pn_entries, speeddials, ice_entries, 434 entry_num0, entry_num1, 435 pb_entry, data, ring_pathf, 436 rt_index, picid_pathf, wp_index):
437 """ Create a pbfileentry from a bitpim phonebook entry """ 438 new_entry = self.protocolclass.pbfileentry(entry_tag=self.protocolclass.PB_ENTRY_SOR) 439 # entry IDs 440 new_entry.entry_number0 = entry_num0 441 new_entry.entry_number1 = entry_num1 442 443 for key in pb_entry: 444 if key in ('emails', 'numbertypes'): 445 l = getattr (new_entry, key) 446 for item in pb_entry[key]: 447 l.append(item) 448 elif key == 'numbers': 449 l = getattr (new_entry, 'numberindices') 450 for i in range(0, self.protocolclass.NUMPHONENUMBERS): 451 new_pn_id = len (pn_entries.items) 452 if new_pn_id == self.protocolclass.NUMPHONENUMBERENTRIES: 453 # this state should not be possible. should this raise an exception? 454 self.log ("Maximum number of phone numbers reached") 455 break 456 457 try: 458 pn_entries.items.append(self.make_pn_entry (pb_entry[key][i],pb_entry['numbertypes'][i], new_pn_id, i, entry_num0)) 459 l.append (new_pn_id) 460 except: 461 l.append (0xffff) 462 elif key == 'speeddials': 463 for _sd,_num_type in zip(pb_entry['speeddials'], pb_entry['numbertypes']): 464 if _sd is not None: 465 speeddials[_sd]={ 'entry': entry_num0, 466 'type': _num_type } 467 elif key == 'ice': 468 # In Case of Emergency 469 _ice = pb_entry['ice'] 470 if _ice is not None and len(_ice) > 0: 471 _ice_entry = _ice[0]['iceindex'] 472 ice_entries.items[_ice_entry] = self.make_ice_entry (_ice_entry, entry_num0) 473 elif key == 'ringtone': 474 new_entry.ringtone = self._findmediainindex(data['ringtone-index'], pb_entry['ringtone'], pb_entry['name'], 'ringtone') 475 try: 476 _filename = rt_index[new_entry.ringtone]['filename'] 477 ring_pathf.items.append(self.protocolclass.PathIndexEntry(pathname=_filename)) 478 new_entry.ringtone = 0x64 479 except: 480 ring_pathf.items.append(self.protocolclass.PathIndexEntry()) 481 elif key == 'wallpaper': 482 new_entry.wallpaper = self._findmediainindex(data['wallpaper-index'], pb_entry['wallpaper'], pb_entry['name'], 'wallpaper') 483 try: 484 _filename = wp_index[new_entry.wallpaper]['filename'] 485 picid_pathf.items.append(self.protocolclass.PathIndexEntry(pathname=_filename)) 486 new_entry.wallpaper = 0x64 487 except: 488 picid_pathf.items.append(self.protocolclass.PathIndexEntry()) 489 elif key in new_entry.getfields(): 490 setattr (new_entry, key, pb_entry[key]) 491 492 return new_entry
493 494 495 # Calendar stuff------------------------------------------------------------
496 - def _scheduleextras(self, data, fwversion):
497 data.serial_number = '000000d1-00000000-00000000-' + fwversion 498 data.unknown3 = 0x01fc
499 500 501 # ringtones and wallpapers stuff--------------------------------------------
502 - def savewallpapers(self, results, merge):
503 results['rebootphone']=True 504 return self.savemedia('wallpapers', 'wallpaper-index', 505 self.wallpaperlocations, results, merge, 506 self.getwallpaperindices, True)
507
508 - def saveringtones(self, results, merge):
509 # Let the phone rebuild the index file, just need to reboot 510 results['rebootphone']=True 511 return self.savemedia('ringtone', 'ringtone-index', 512 self.ringtonelocations, results, merge, 513 self.getringtoneindices, True)
514 515 # SMS Stuff----------------------------------------------------------------- 516 # Again, this is very similar to the 8800, just make it work with the 9100
517 - def getindex(self, filename):
518 try: 519 return self.readobject(filename, 520 self.protocolclass.indexfile, 521 logtitle='Reading index file', 522 uselocalfs=DEBUG2).items 523 except: 524 return []
525
526 - def _readsms(self):
527 res={} 528 # The Voyager and Venus use index files to keep track of SMS messages 529 for item in self.getindex(self.protocolclass.drafts_index): 530 sf=self.readobject(item.filename, 531 self.protocolclass.sms_saved, 532 logtitle='SMS draft item', 533 uselocalfs=DEBUG2) 534 # The 9100 only has draft messages (saved outgoing messaged) 535 entry=self._getoutboxmessage(sf.outbox) 536 entry.folder=entry.Folder_Saved 537 res[entry.id]=entry 538 for item in self.getindex(self.protocolclass.inbox_index): 539 sf=self.readobject(item.filename, 540 self.protocolclass.sms_in, 541 logtitle='SMS inbox item', 542 uselocalfs=DEBUG2) 543 entry=self._getinboxmessage(sf) 544 res[entry.id]=entry 545 for item in self.getindex(self.protocolclass.outbox_index): 546 sf=self.readobject(item.filename, 547 self.protocolclass.sms_out, 548 logtitle='SMS outbox item', 549 uselocalfs=DEBUG2) 550 entry=self._getoutboxmessage(sf) 551 res[entry.id]=entry 552 return res
553
554 - def _getinboxmessage(self, sf):
555 entry=sms.SMSEntry() 556 entry.folder=entry.Folder_Inbox 557 entry.datetime="%d%02d%02dT%02d%02d%02d" % (sf.GPStime) 558 entry._from=sf.sender if sf.sender else sf.sender_name 559 entry.subject=sf.subject 560 entry.locked=sf.locked 561 if sf.priority==0: 562 entry.priority=sms.SMSEntry.Priority_Normal 563 else: 564 entry.priority=sms.SMSEntry.Priority_High 565 entry.read=sf.read 566 txt="" 567 _decode_func=self._get_text_from_sms_msg_with_header if \ 568 sf.msgs[1].msg_length else \ 569 self._get_text_from_sms_msg_without_header 570 for _entry in sf.msgs: 571 if _entry.msg_length: 572 txt+=_decode_func(_entry.msg_data.msg, _entry.msg_length) 573 entry.text=unicode(txt, errors='ignore') 574 entry.callback=sf.callback 575 return entry
576 577 578 #------------------------------------------------------------------------------- 579 parentprofile=com_lgvx8550.Profile
580 -class Profile(parentprofile):
581 protocolclass=Phone.protocolclass 582 serialsname=Phone.serialsname 583 584 BP_Calendar_Version=3 585 phone_manufacturer='LG Electronics Inc' 586 phone_model='VX9100' 587 588 WALLPAPER_WIDTH=320 589 WALLPAPER_HEIGHT=240 590 # outside LCD: 160x64 591 592 imageorigins={} 593 imageorigins.update(common.getkv(parentprofile.stockimageorigins, "images")) 594 imageorigins.update(common.getkv(parentprofile.stockimageorigins, "video")) 595 imageorigins.update(common.getkv(parentprofile.stockimageorigins, "images(sd)")) 596 imageorigins.update(common.getkv(parentprofile.stockimageorigins, "video(sd)"))
597 - def GetImageOrigins(self):
598 return self.imageorigins
599 600 601 ## ringtoneorigins=('ringers', 'sounds', 'sounds(sd)',' music', 'music(sd)') 602 ## excluded_ringtone_origins=('sounds', 'sounds(sd)', 'music', 'music(sd)') 603 ringtoneorigins=('ringers', 'sounds', 'sounds(sd)') 604 excluded_ringtone_origins=('sounds', 'sounds(sd)') 605 606 # our targets are the same for all origins 607 imagetargets={} 608 imagetargets.update(common.getkv(parentprofile.stockimagetargets, "wallpaper", 609 {'width': 320, 'height': 215, 'format': "JPEG"})) 610 imagetargets.update(common.getkv(parentprofile.stockimagetargets, "outsidelcd", 611 {'width': 160, 'height': 64, 'format': "JPEG"})) 612
613 - def GetTargetsForImageOrigin(self, origin):
614 return self.imagetargets
615 616 _supportedsyncs=( 617 ('phonebook', 'read', None), # all phonebook reading 618 ('calendar', 'read', None), # all calendar reading 619 ('wallpaper', 'read', None), # all wallpaper reading 620 ('ringtone', 'read', None), # all ringtone reading 621 ('call_history', 'read', None),# all call history list reading 622 ('sms', 'read', None), # all SMS list reading 623 ('memo', 'read', None), # all memo list reading 624 ('phonebook', 'write', 'OVERWRITE'), # only overwriting phonebook 625 ('calendar', 'write', 'OVERWRITE'), # only overwriting calendar 626 ('wallpaper', 'write', 'MERGE'), # merge and overwrite wallpaper 627 ## ('wallpaper', 'write', 'OVERWRITE'), 628 ('ringtone', 'write', 'MERGE'), # merge and overwrite ringtone 629 ## ('ringtone', 'write', 'OVERWRITE'), 630 #### ('sms', 'write', 'OVERWRITE'), # all SMS list writing 631 ('memo', 'write', 'OVERWRITE'), # all memo list writing 632 #### ('playlist', 'read', 'OVERWRITE'), 633 #### ('playlist', 'write', 'OVERWRITE'), 634 ) 635
636 - def normalisegroups(self, helper, data):
637 "Assigns groups based on category data" 638 639 pad=[] 640 keys=data['groups'].keys() 641 keys.sort() 642 for k in keys: 643 if k: # ignore key 0 which is 'No Group' 644 name=data['groups'][k]['name'] 645 pad.append(name) 646 647 groups=helper.getmostpopularcategories(self.protocolclass.MAX_PHONEBOOK_GROUPS, data['phonebook'], ["No Group"], 32, pad) 648 649 # alpha sort 650 groups.sort() 651 652 # newgroups 653 newgroups={} 654 655 # put in No group 656 newgroups[0]={'name': 'No Group', 'user_added': 0} 657 658 # populate 659 for name in groups: 660 # existing entries remain unchanged 661 if name=="No Group": continue 662 key,value=self._getgroup(name, data['groups']) 663 if key is not None and key!=0: 664 newgroups[key]=value 665 # new entries get whatever numbers are free 666 for name in groups: 667 key,value=self._getgroup(name, newgroups) 668 if key is None: 669 for key in range(1,100000): 670 if key not in newgroups: 671 newgroups[key]={'name': name, 'user_added': 1} 672 break 673 674 # yay, done 675 if data['groups']!=newgroups: 676 data['groups']=newgroups 677 data['rebootphone']=True
678
679 - def convertphonebooktophone(self, helper, data):
680 """Converts the data to what will be used by the phone 681 682 @param data: contains the dict returned by getfundamentals 683 as well as where the results go""" 684 results={} 685 686 self.normalisegroups(helper, data) 687 688 for pbentry in data['phonebook']: 689 if len(results)==self.protocolclass.NUMPHONEBOOKENTRIES: 690 break 691 e={} # entry out 692 entry=data['phonebook'][pbentry] # entry in 693 try: 694 # serials 695 serial1=helper.getserial(entry.get('serials', []), self.serialsname, data['uniqueserial'], 'serial1', 0) 696 serial2=helper.getserial(entry.get('serials', []), self.serialsname, data['uniqueserial'], 'serial2', serial1) 697 698 e['serial1']=serial1 699 e['serial2']=serial2 700 for ss in entry["serials"]: 701 if ss["sourcetype"]=="bitpim": 702 e['bitpimserial']=ss 703 assert e['bitpimserial'] 704 705 # name 706 e['name']=helper.getfullname(entry.get('names', []),1,1,32)[0] 707 708 # ice 709 e['ice']=entry.get('ice', None) 710 711 # categories/groups 712 cat=helper.makeone(helper.getcategory(entry.get('categories', []),0,1,32), None) 713 if cat is None: 714 e['group']=0 715 else: 716 key,value=self._getgroup(cat, data['groups']) 717 if key is not None: 718 e['group']=key 719 else: 720 # sorry no space for this category 721 e['group']=0 722 723 # email addresses 724 emails=helper.getemails(entry.get('emails', []) ,0,self.protocolclass.NUMEMAILS,48) 725 e['emails']=helper.filllist(emails, self.protocolclass.NUMEMAILS, "") 726 727 # phone numbers 728 # there must be at least one email address or phonenumber 729 minnumbers=1 730 if len(emails): minnumbers=0 731 numbers=helper.getnumbers(entry.get('numbers', []),minnumbers,self.protocolclass.NUMPHONENUMBERS) 732 e['numbertypes']=[] 733 e['numbers']=[] 734 e['speeddials']=[] 735 for numindex in range(len(numbers)): 736 num=numbers[numindex] 737 # deal with type 738 b4=len(e['numbertypes']) 739 type=num['type'] 740 for i,t in enumerate(self.protocolclass.numbertypetab): 741 if type==t: 742 # some voodoo to ensure the second home becomes home2 743 if i in e['numbertypes'] and t[-1]!='2': 744 type+='2' 745 continue 746 e['numbertypes'].append(i) 747 break 748 if t=='none': # conveniently last entry 749 e['numbertypes'].append(i) 750 break 751 if len(e['numbertypes'])==b4: 752 # we couldn't find a type for the number 753 helper.add_error_message('Number %s (%s/%s) not supported and ignored.'% 754 (num['number'], e['name'], num['type'])) 755 continue 756 # deal with number 757 number=self.phonize(num['number']) 758 if len(number)==0: 759 # no actual digits in the number 760 continue 761 if len(number)>24: # get this number from somewhere sensible 762 # ::TODO:: number is too long and we have to either truncate it or ignore it? 763 number=number[:24] # truncate for moment 764 e['numbers'].append(number) 765 # deal with speed dial 766 sd=num.get("speeddial", None) 767 if sd is not None and \ 768 sd>=self.protocolclass.FIRSTSPEEDDIAL and \ 769 sd<=self.protocolclass.LASTSPEEDDIAL: 770 e['speeddials'].append(sd) 771 else: 772 e['speeddials'].append(None) 773 774 if len(e['numbers'])<minnumbers: 775 # we couldn't find any numbers 776 # for this entry, so skip it, entries with no numbers cause error 777 helper.add_error_message("Name: %s. No suitable numbers or emails found" % e['name']) 778 continue 779 e['numbertypes']=helper.filllist(e['numbertypes'], self.protocolclass.NUMPHONENUMBERS, 0) 780 e['numbers']=helper.filllist(e['numbers'], self.protocolclass.NUMPHONENUMBERS, "") 781 e['speeddials']=helper.filllist(e['speeddials'], self.protocolclass.NUMPHONENUMBERS, None) 782 783 # ringtones, wallpaper 784 e['ringtone']=helper.getringtone(entry.get('ringtones', []), 'call', None) 785 e['wallpaper']=helper.getwallpaper(entry.get('wallpapers', []), 'call', None) 786 787 results[pbentry]=e 788 789 except helper.ConversionFailed: 790 continue 791 792 data['phonebook']=results 793 return data
794 # applicable fields for this model 795 field_color_data={ 796 'phonebook': { 797 'name': { 798 'first': 1, 'middle': 1, 'last': 1, 'full': 1, 799 'nickname': 0, 'details': 1 }, 800 'number': { 801 'type': 5, 'speeddial': 5, 'number': 5, 'details': 5 }, 802 'email': 2, 803 'address': { 804 'type': 0, 'company': 0, 'street': 0, 'street2': 0, 805 'city': 0, 'state': 0, 'postalcode': 0, 'country': 0, 806 'details': 0 }, 807 'url': 0, 808 'memo': 0, 809 'category': 1, 810 'wallpaper': 1, 811 'ringtone': 2, 812 'storage': 0, 813 'secret': 0, 814 'ICE': 1, 815 }, 816 'calendar': { 817 'description': True, 'location': False, 'allday': False, 818 'start': True, 'end': True, 'priority': False, 819 'alarm': True, 'vibrate': True, 820 'repeat': True, 821 'memo': False, 822 'category': False, 823 'wallpaper': False, 824 'ringtone': True, 825 }, 826 'memo': { 827 'subject': True, 828 'date': True, 829 'secret': False, 830 'category': False, 831 'memo': True, 832 }, 833 'todo': { 834 'summary': False, 835 'status': False, 836 'due_date': False, 837 'percent_complete': False, 838 'completion_date': False, 839 'private': False, 840 'priority': False, 841 'category': False, 842 'memo': False, 843 }, 844 }
845