Package phones ::
Module com_lgvx9100
|
|
1
2
3
4
5
6
7
8
9
10 """
11 Communicate with the LG VX9100 (enV2) cell phone. This is based on the enV model
12 """
13
14
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
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
38
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
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
50
51 )
52
53 wallpaperlocations= (
54
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):
63
65 self._DMv6=True
66 self._DMv5=False
67
68
69
70
71
72
73
74
75
76
77
78
79
80
95
115
130
147
158
160 """Reads the phonebook data. The L{getfundamentals} information will
161 already be in result."""
162
163 _speeds=self._get_speeddials()
164
165
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
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
223 """Return a phonebook entry in BitPim format. This is called from getphonebook."""
224 res={}
225
226 res['serials']=[ {'sourcetype': self.serialsname,
227 'sourceuniqueid': fundamentals['uniqueserial'],
228 'serial1': entry.entry_number1,
229 'serial2': entry.entry_number1 } ]
230
231
232 res['names']=[ {'full': entry.name} ]
233
234
235 cat=fundamentals['groups'].get(entry.group, {'name': "No Group"})['name']
236 if cat!="No Group":
237 res['categories']=[ {'category': cat} ]
238
239
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']
245
246
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
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
269 res=self._assignpbtypeandspeeddialsbytype(entry, numbers, speeds, res)
270
271
272 res=self._assigniceentry(entry, numbers, ices, res)
273
274 return res
275
277
278 res['numbers']=[]
279 for i in range(self.protocolclass.NUMPHONENUMBERS):
280 if entry.numberindices[i].numberindex>=\
281 self.protocolclass.NUMPHONENUMBERENTRIES:
282
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
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
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
318 "Saves out the phonebook"
319 self.savegroups (data)
320
321 ring_pathf=self.protocolclass.PathIndexFile()
322 picid_pathf=self.protocolclass.PathIndexFile()
323
324
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
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
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
367 self.log('Writing ringtone ID')
368 self.writeobject(self.protocolclass.RTPathIndexFile,
369 ring_pathf, logtitle='Writing ringtone paths',
370 uselocalfs=DEBUG1)
371
372 self.log('Writing pciture ID')
373 self.writeobject(self.protocolclass.WPPathIndexFile,
374 picid_pathf, logtitle='Writing wallpaper paths',
375 uselocalfs=DEBUG1)
376
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
383 req=self.protocolclass.speeddials()
384
385 req.speeddials.append(self.protocolclass.speeddial())
386
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
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
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
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
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
497 data.serial_number = '000000d1-00000000-00000000-' + fwversion
498 data.unknown3 = 0x01fc
499
500
501
507
514
515
516
525
553
576
577
578
579 parentprofile=com_lgvx8550.Profile
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
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)"))
599
600
601
602
603 ringtoneorigins=('ringers', 'sounds', 'sounds(sd)')
604 excluded_ringtone_origins=('sounds', 'sounds(sd)')
605
606
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
615
616 _supportedsyncs=(
617 ('phonebook', 'read', None),
618 ('calendar', 'read', None),
619 ('wallpaper', 'read', None),
620 ('ringtone', 'read', None),
621 ('call_history', 'read', None),
622 ('sms', 'read', None),
623 ('memo', 'read', None),
624 ('phonebook', 'write', 'OVERWRITE'),
625 ('calendar', 'write', 'OVERWRITE'),
626 ('wallpaper', 'write', 'MERGE'),
627
628 ('ringtone', 'write', 'MERGE'),
629
630
631 ('memo', 'write', 'OVERWRITE'),
632
633
634 )
635
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:
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
650 groups.sort()
651
652
653 newgroups={}
654
655
656 newgroups[0]={'name': 'No Group', 'user_added': 0}
657
658
659 for name in groups:
660
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
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
675 if data['groups']!=newgroups:
676 data['groups']=newgroups
677 data['rebootphone']=True
678
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={}
692 entry=data['phonebook'][pbentry]
693 try:
694
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
706 e['name']=helper.getfullname(entry.get('names', []),1,1,32)[0]
707
708
709 e['ice']=entry.get('ice', None)
710
711
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
721 e['group']=0
722
723
724 emails=helper.getemails(entry.get('emails', []) ,0,self.protocolclass.NUMEMAILS,48)
725 e['emails']=helper.filllist(emails, self.protocolclass.NUMEMAILS, "")
726
727
728
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
738 b4=len(e['numbertypes'])
739 type=num['type']
740 for i,t in enumerate(self.protocolclass.numbertypetab):
741 if type==t:
742
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':
749 e['numbertypes'].append(i)
750 break
751 if len(e['numbertypes'])==b4:
752
753 helper.add_error_message('Number %s (%s/%s) not supported and ignored.'%
754 (num['number'], e['name'], num['type']))
755 continue
756
757 number=self.phonize(num['number'])
758 if len(number)==0:
759
760 continue
761 if len(number)>24:
762
763 number=number[:24]
764 e['numbers'].append(number)
765
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
776
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
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
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