Package phones ::
Module com_lgtm520
|
|
1
2
3
4
5
6
7
8
9
10
11
12 "Talk to the LG TM520/VX10 cell phone"
13
14
15 import re
16 import time
17 import cStringIO
18 import sha
19
20
21 import common
22 import p_lgtm520
23 import com_brew
24 import com_phone
25 import com_lg
26 import prototypes
27
28 typemap = {
29 'fwd': ( 'home', 'office', 'cell', 'pager', 'data' ),
30 'rev': { 'home': 0, 'office': 1, 'cell': 2, 'pager': 3, 'data': 4, 'fax': 4 }
31 }
32
33 -class Phone(com_phone.Phone,com_brew.BrewProtocol,com_lg.LGPhonebook):
34 "Talk to the LG TM520/VX10 cell phone"
35 desc="LG-TM520/VX10"
36 protocolclass=p_lgtm520
37 serialsname='lgtm520'
38
39 ringtonelocations=(
40
41
42 ( 0, "", "ringer", "ringers", 5),
43
44
45
46
47 )
48
49 builtinringtones=( 'Standard1', 'Standard2', 'Standard3', 'Standard4',
50 'Standard5', 'Radetzky March', 'Nocturn', 'Carmen',
51 'La Traviata', 'Liberty Bell', 'Semper Fidelis',
52 'Take Me Out', 'Turkey In The Straw', 'We Wish...',
53 'Csikos Post', 'Bumble Bee Twist', 'Badinerie',
54 'Silken Ladder', 'Chestnut' )
55
56
57
58 _tm520epochtounix=315532800+460800
59 _brewepochtounix=315532800+460800
60 _calrepeatvalues={ 0: None, 1: None, 2: 'daily' }
61
62 getwallpapers=None
63
64 - def __init__(self, logtarget, commport):
70
72 """Gets information fundamental to interopating with the phone and UI."""
73
74
75 self.log("Retrieving fundamental phone information")
76 self.log("Phone serial number")
77 results['uniqueserial']=sha.new(self.getfilecontents("nvm/$SYS.ESN")).hexdigest()
78 results['ringtone-index'] = {}
79 ringcount = 1
80 for r in self.builtinringtones:
81 results['ringtone-index'][ringcount] = {'name': r, 'origin': 'builtin'}
82 ringcount += 1
83
84 try:
85 ringers=self.getfilesystem('ringer')
86 for r in ringers.keys():
87 results['ringtone-index'][ringcount] = {'name': r[len('ringer/'):], 'origin': 'ringers'}
88 ringcount +=1
89 except com_brew.BrewNoSuchDirectoryException:
90 self.log("Ringer directory doesn't exist, firmware might not be download capable")
91 self.log("Fundamentals retrieved")
92 return results
93
102
106
121
122 - def postgetdb(self, result):
123
124
125
126
127
128 del result['intermediate']
129
131 """Reads the phonebook data. The L{getfundamentals} information will
132 already be in result."""
133 pbook={}
134
135
136
137
138
139
140 self.pregetpb(result)
141 self.log("Reading number of phonebook entries")
142
143 numentries=self.pbinit()
144 self.log("There are %d entries" % (numentries,))
145 for i in range(0, numentries):
146
147 req=self.protocolclass.pbreadentryrequest()
148 res=self.sendpbcommand(req, self.protocolclass.pbreadentryresponse)
149 self.log("Read entry "+`i`+" - "+res.entry.name)
150 entry=self.extractphonebookentry(res.entry, result)
151 pbook[i]=entry
152 self.progress(i, numentries, res.entry.name)
153
154 req=self.protocolclass.pbnextentryrequest()
155 self.sendpbcommand(req, self.protocolclass.pbnextentryresponse)
156
157 self.progress(numentries, numentries, "Phone book read completed")
158 result['phonebook']=pbook
159 self.pbend()
160 self.postgetdb(result)
161
162 print "returning keys",result.keys()
163 return pbook
164
166 """Return a phonebook entry in BitPim format"""
167 res={}
168
169 res['serials']=[ {'sourcetype': self.serialsname, 'serial1': entry.serial1, 'serial2': entry.serial2,
170 'sourceuniqueid': fundamentals['uniqueserial']} ]
171
172 res['names']=[ {'full': entry.name} ]
173
174 if len(entry.email) > 0: res['emails']=[ {'email': entry.email} ]
175 res['flags'] = []
176
177 if entry.secret: res['flags'].append({'secret': entry.secret })
178 if entry.voicetag: res['flags'].append({'voicetag': entry.voicetag })
179
180
181 res['ringtones'] = []
182 if entry.ringtone > 0:
183
184 if entry.ringtone > len(self.builtinringtones):
185
186 try:
187 res['ringtones'].append({'ringtone': fundamentals['intermediate'][entry.entrynumber], 'use': 'call'})
188 except:
189 self.log('Custom ringtone not properly assigned for '+entry.name)
190 else:
191
192 res['ringtones'].append({'ringtone': fundamentals['ringtone-index'][entry.ringtone]['name'], 'use': 'call'})
193
194 res['numbers']=[]
195 numbernumber=0
196 for type in typemap['fwd']:
197 item = entry.numbers[numbernumber]
198 if len(item.number) > 0:
199 res['numbers'].append({'number': item.number, 'type': type, 'sum': item.chksum })
200 if numbernumber == entry.default: res['numbers'][-1]['speeddial'] = entry.entrynumber
201 numbernumber+=1
202 return res
203
205
207 self.savegroups(data)
208
209
210
211
212
213 serialupdates=[]
214 existingpbook={}
215 ringindex = {}
216
217
218 pbook = data['phonebook']
219 for i in pbook.keys():
220 if not 'ringtone' in pbook[i]: continue
221 if not pbook[i]['ringtone'] is None and not pbook[i]['ringtone'] in self.builtinringtones:
222 ringindex[pbook[i]['entrynumber']] = pbook[i]['ringtone'];
223
224 ringidxfile=self.protocolclass.ringindex()
225 for i in range(1, 200):
226 ringerentry = self.protocolclass.ringentry()
227 ringerentry.index = i
228 ringerentry.name = ''
229 if i in ringindex: ringerentry.name = 'ringer/'+ringindex[i]
230 ringidxfile.items.append(ringerentry)
231 buf=prototypes.buffer()
232 ringidxfile.writetobuffer(buf, logtitle="Custom ringer index")
233
234
235
236
237 if len(ringindex) > 0:
238 self.writefile("pim/midiringer.dat", buf.getvalue())
239
240
241
242
243
244 numexistingentries=self.pbinit()
245 progressmax=numexistingentries+len(data['phonebook'].keys())
246 progresscur=0
247 self.log("There are %d existing entries" % (numexistingentries,))
248 for i in range(0, numexistingentries):
249
250 req=self.protocolclass.pbreadentryrequest()
251 res=self.sendpbcommand(req, self.protocolclass.pbreadentryresponse)
252
253 entry={ 'number': res.entry.entrynumber, 'serial1': res.entry.serial1,
254 'serial2': res.entry.serial2, 'name': res.entry.name}
255 assert entry['serial1']==entry['serial2']
256 self.log("Reading entry "+`i`+" - "+entry['name'])
257 existingpbook[i]=entry
258 self.progress(progresscur, progressmax, "existing "+entry['name'])
259
260 req=self.protocolclass.pbnextentryrequest()
261 self.sendpbcommand(req, self.protocolclass.pbnextentryresponse)
262 progresscur+=1
263
264
265
266 pbook=data['phonebook']
267 dellist=[]
268 for i in range(0, numexistingentries):
269 ii=existingpbook[i]
270 serial=ii['serial1']
271 item=self._findserial(serial, pbook)
272 if item is None:
273 dellist.append(i)
274
275 progressmax+=len(dellist)
276
277
278 for i in dellist:
279 progresscur+=1
280 numexistingentries-=1
281 ii=existingpbook[i]
282 self.log("Deleting entry "+`i`+" - "+ii['name'])
283 req=self.protocolclass.pbdeleteentryrequest()
284 req.serial1=ii['serial1']
285 req.serial2=ii['serial2']
286 req.entrynumber=ii['number']
287 self.sendpbcommand(req, self.protocolclass.pbdeleteentryresponse)
288 self.progress(progresscur, progressmax, "Deleting "+ii['name'])
289
290 del existingpbook[i]
291
292
293 counter=0
294
295 keys=existingpbook.keys()
296 existingserials=[]
297 keys.sort()
298 for i in keys:
299 progresscur+=1
300 ii=pbook[self._findserial(existingpbook[i]['serial1'], pbook)]
301 self.log("Rewriting entry "+`i`+" - "+ii['name'])
302 self.progress(progresscur, progressmax, "Rewriting "+ii['name'])
303 entry=self.makeentry(counter, ii, data)
304 counter+=1
305 existingserials.append(existingpbook[i]['serial1'])
306 req=self.protocolclass.pbupdateentryrequest()
307 req.entry=entry
308 res=self.sendpbcommand(req, self.protocolclass.pbupdateentryresponse)
309 serialupdates.append( ( ii["bitpimserial"],
310 {'sourcetype': self.serialsname, 'serial1': res.serial1, 'serial2': res.serial1,
311 'sourceuniqueid': data['uniqueserial']})
312 )
313 assert ii['serial1']==res.serial1
314
315
316 keys=pbook.keys()
317 keys.sort()
318 for i in keys:
319 ii=pbook[i]
320 if ii['serial1'] in existingserials:
321 continue
322 progresscur+=1
323 entry=self.makeentry(counter, ii, data)
324 counter+=1
325 self.log("Appending entry "+ii['name'])
326 self.progress(progresscur, progressmax, "Writing "+ii['name'])
327 req=self.protocolclass.pbappendentryrequest()
328 req.entry=entry
329 res=self.sendpbcommand(req, self.protocolclass.pbappendentryresponse)
330 serialupdates.append( ( ii["bitpimserial"],
331 {'sourcetype': self.serialsname, 'serial1': res.newserial, 'serial2': res.newserial,
332 'sourceuniqueid': data['uniqueserial']})
333 )
334
335 self.pbend()
336 data["serialupdates"]=serialupdates
337 if len(ringindex) == 0: return
338
339
341 """Searches dict to find entry with matching serial. If not found,
342 returns None"""
343 for i in dict:
344 if dict[i]['serial1']==serial:
345 return i
346 return None
347
378
461
472
496
498 """Unpack 32 bit value into date/time
499
500 @rtype: tuple
501 @return: (year, month, day, hour, minute)
502 """
503 return time.localtime(val)[:5]
504
506 tmp = []
507 for i in val: tmp.append(i)
508 tmp += [0, 0, 0, dst]
509 return time.mktime(tmp)
510
512 if name is None: return 0
513 for i in index:
514 if index[i]['name'] == name:
515 return i
516 self.log("%s: Unable to find ringtone %s in the index. Setting to default." % (pbentryname, name))
517 return 0
518
520 sumtbl = { '0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9,
521 'H': 24, 'T': 36, '#': -13, '*': -6 }
522 entry.number = number
523 entry.chksum = 0
524 lastseven = number
525 if len(lastseven) > 7: lastseven = lastseven[len(lastseven)-7:]
526 if len(lastseven) > 0:
527 for i in lastseven:
528 entry.chksum += sumtbl[i]
529 else: entry.chksum = 255
530
531 - def makeentry(self, counter, entry, dict):
532 e=self.protocolclass.pbentry()
533 e.entrynumber=counter
534
535 for k in entry:
536
537 if k == 'numbers':
538 l=getattr(e,k)
539 for item in entry[k]:
540 num=self.protocolclass.numentry()
541 self._calcnumsum(num, item)
542 l.append(num)
543 elif k == 'ringtone':
544 e.ringtone = self._findringtoneindex(dict['ringtone-index'], entry[k], entry['name'])
545 else:
546
547 setattr(e,k,entry[k])
548
549 return e
550
552 """Convert the phone number into something the phone understands
553
554 All digits, P, H, T, * and # are kept, everything else is removed"""
555 return re.sub("[^0-9HPT#*]", "", str)
556
557
559 serialsname='lgtm520'
560 WALLPAPER_WIDTH=100
561 WALLPAPER_HEIGHT=100
562 MAX_WALLPAPER_BASENAME_LENGTH=19
563 MAX_RINGTONE_BASENAME_LENGTH=19
564 WALLPAPER_FILENAME_CHARS="abcdefghijklmnopqrstuvwxyz0123456789 ."
565 RINGTONE_FILENAME_CHARS="abcdefghijklmnopqrstuvwxyz0123456789 ."
566 WALLPAPER_CONVERT_FORMAT="bmp"
567
568 usbids = ( )
569 deviceclasses = ("serial", )
570 _supportedsyncs=(
571 ('phonebook', 'read', None),
572 ('calendar', 'read', None),
573 ('ringtone', 'read', None),
574 ('phonebook', 'write', 'OVERWRITE'),
575 ('calendar', 'write', 'OVERWRITE'),
576 ('ringtone', 'write', 'MERGE'),
577 ('ringtone', 'write', 'OVERWRITE'),
578 )
579
581 "Converts the data to what will be used by the phone"
582
583 results = {}
584 speeddial = {}
585 entrynumber = 1
586
587 for pbentry in data['phonebook']:
588 e = {}
589 entry = data['phonebook'][pbentry]
590
591 try:
592 try:
593 e['name'] = helper.getfullname(entry.get('names', []),1,1,16)[0]
594 except IndexError: raise helper.ConversionFailed("No name assigned to entry")
595 try:
596 e['email']= helper.getemails(entry.get('emails', []),0,1,48)[0]
597 except IndexError: e['email'] = ""
598 e['ringtone'] = helper.getringtone(entry.get('ringtones', []), 'call', None)
599 e['secret'] = helper.getflag(entry.get('flags',[]), 'secret', False)
600 e['voicetag'] = helper.getflag(entry.get('flags',[]), 'voicetag', False)
601 e['default'] = 0
602
603 numbers = entry.get('numbers', [])
604 if len(numbers) < 1: raise helper.ConversionFailed("Too few numbers. Need at least 1 number")
605 e['numbers']=[ '', '', '', '', '' ]
606 available = 5
607 deferred = []
608 for num in numbers:
609 number=phonize(num['number'])
610 if len(number) == 0: continue
611 if len(number) > 32: number = number[:32]
612 if available == 0: break
613 if not 'type' in num:
614 deferred.append(num)
615 continue
616 elif not num['type'] in typemap['rev']:
617 deferred.append(num)
618 continue
619 else:
620 typeidx = typemap['rev'][num['type']]
621 if len(e['numbers'][typeidx]) == 0:
622 e['numbers'][typeidx] = number
623 if 'speeddial' in num and not 'entrynumber' in e:
624 if not num['speeddial'] in speeddial:
625 e['entrynumber'] = num['speeddial']
626 e['default'] = typeidx
627 available -= 1
628 if available > 0 and len(deferred) > 0:
629 for num in deferred:
630 if available == 0: break
631 number=phonize(num['number'])
632 if len(number) > 32: number = number[:32]
633 for slot in range(0, 5):
634 if len(e['numbers'][slot]) > 0: continue
635 e['numbers'][slot] = number
636 if 'speeddial' in num and not 'entrynumber' in e:
637 if not num['speeddial'] in speeddial:
638 e['entrynumber'] = num['speeddial']
639 e['default'] = slot
640 available -= 1
641 if available == 5:
642 raise helper.ConversionFailed("The phone numbers didn't have any digits for this entry")
643 if not 'entrynumber' in e:
644 while entrynumber in speedial:
645 entrynumber += 1
646 if entrynumber > 199:
647 self.log("Too many entries in phonebook, only 199 entries supported")
648 break
649 e['entrynumber'] = entrynumber
650 speeddial[e['entrynumber']] = pbentry
651
652 serial1 = helper.getserial(entry.get('serials', []), self.serialsname, data['uniqueserial'], 'serial1', 0)
653 serial2 = helper.getserial(entry.get('serials', []), self.serialsname, data['uniqueserial'], 'serial2', serial1)
654
655 e['serial1'] = serial1
656 e['serial2'] = serial2
657 for ss in entry["serials"]:
658 if ss["sourcetype"]=="bitpim":
659 e['bitpimserial']=ss
660 assert e['bitpimserial']
661
662 results[pbentry] = e
663
664 except helper.ConversionFailed: continue
665
666 data['phonebook'] = results
667 return data
668