Package phones ::
Module com_audiovoxcdm8900
|
|
1
2
3
4
5
6
7
8
9
10 """Communicate with the Audiovox CDM 8900 cell phone"""
11
12
13 import sha
14 import re
15
16
17 import common
18 import com_phone
19 import com_brew
20 import prototypes
21 import p_audiovoxcdm8900
22
23 -class Phone(com_phone.Phone, com_brew.BrewProtocol):
24 "Talk to Audiovox CDM 8900 cell phone"
25
26 desc="Audiovox CDM8900"
27 protocolclass=p_audiovoxcdm8900
28 serialsname='audiovoxcdm8900'
29 pbterminator="~"
30
31 - def __init__(self, logtarget, commport):
37
39 """Gets information fundamental to interopating with the phone and UI.
40
41 Currently this is:
42
43 - 'uniqueserial' a unique serial number representing the phone
44 - 'groups' the phonebook groups
45 - 'wallpaper-index' map index numbers to names
46 - 'ringtone-index' map index numbers to ringtone names
47
48 This method is called before we read the phonebook data or before we
49 write phonebook data.
50 """
51
52 self.log("Retrieving fundamental phone information")
53 self.setmode(self.MODEBREW)
54 self.log("Phone serial number")
55 results['uniqueserial']=sha.new(self.getfilecontents("nvm/$SYS.ESN")).hexdigest()
56
57
58 self.log("Reading group information")
59 groups={}
60 for i in range(self.protocolclass._NUMGROUPS):
61 req=self.protocolclass.readgroupentryrequest()
62 req.number=i
63 res=self.sendpbcommand(req, self.protocolclass.readgroupentryresponse)
64 if res.number==self.protocolclass._ALLGROUP:
65 continue
66 if len(res.name)==0:
67 continue
68 groups[i]={'name': res.name}
69
70 results['groups']=groups
71
72 self.log("Fundamentals retrieved")
73 return results
74
76 raise NotImplementedError()
77
79 raise NotImplementedError()
80
82 raise NotImplementedError()
83
85 """Reads the phonebook data. The L{getfundamentals} information will
86 already be in result."""
87 pbook={}
88 req=self.protocolclass.readpbslotsrequest()
89 res=self.sendpbcommand(req, self.protocolclass.readpbslotsresponse)
90 slots=[x for x in range(len(res.present)) if ord(res.present[x])]
91 numentries=len(slots)
92 for i in range(numentries):
93 req=self.protocolclass.readpbentryrequest()
94 req.slotnumber=slots[i]
95 res=self.sendpbcommand(req, self.protocolclass.readpbentryresponse)
96 self.log("Read entry "+`i`+" - "+res.entry.name)
97 self.progress(i, numentries, res.entry.name)
98 entry=self.extractphonebookentry(slots[i], res.entry, result)
99 pbook[i]=entry
100 self.progress(i, numentries, res.entry.name)
101 self.progress(numentries, numentries, "Phone book read completed")
102 result['phonebook']=pbook
103
104 for i in range(0x1e):
105 req=self.protocolclass.dunnorequest()
106 req.which=i
107 self.sendpbcommand(req, self.protocolclass.dunnoresponse)
108
109 return pbook
110
112 """Return a phonebook entry in BitPim format. This is called from getphonebook."""
113 res={}
114
115 res['serials']=[ {'sourcetype': self.serialsname, 'slot': slotnumber,
116 'sourceuniqueid': result['uniqueserial']} ]
117
118 numbers=[]
119 for t, v in ( ('cell', entry.mobile), ('home', entry.home), ('office', entry.office),
120 ('pager', entry.pager), ('fax', entry.fax) ):
121 if len(v)==0:
122 continue
123 numbers.append( {'number': v, 'type': t} )
124 if len(numbers):
125 res['numbers']=numbers
126
127 if len(entry.name):
128 res['names']=[{'full': entry.name}]
129
130 emails=[]
131 if len(entry.email):
132 emails.append({'email': entry.email})
133 if len(entry.wireless):
134 emails.append({'email': entry.wireless})
135 if len(emails):
136 res['emails']=emails
137
138 if len(entry.memo):
139 res['memos']=[{'memo': entry.memo}]
140
141 if entry.secret:
142 res['flags']=[{'secret': True}]
143
144 if entry.group in result['groups']:
145 group=result['groups'][entry.group]['name']
146 if group!="Etc.":
147 res['categories']=[{'category': group}]
148
149 rt=[]
150 if entry.ringtone!=0xffff:
151 rt.append({'ringtone': 'avox '+`entry.ringtone`, 'use': 'call'})
152 if entry.msgringtone!=0xffff:
153 rt.append({'ringtone': 'avox '+`entry.msgringtone`, 'use': 'message'})
154 if len(rt):
155 res['ringtones']=rt
156 if entry.wallpaper!=0xffff:
157 res['wallpapers']=[{'wallpaper': 'avox '+`entry.wallpaper`, 'use': 'call'}]
158 return res
159
160 - def makephonebookentry(self, fields):
161 e=self.protocolclass.pbentry()
162
163 e.secret=0
164 e.previous=0xffff
165 e.next=0xffff
166 e.ringtone=0xffff
167 e.msgringtone=0xffff
168 e.wallpaper=0xffff
169 for f in fields:
170 setattr(e, f, fields[f])
171 if e.group==0:
172 raise Exception("Data error: The group cannot be zero or the phone crashes")
173 return e
174
176 self.log("Saving group information")
177
178 for gid in range(1, self.protocolclass._NUMGROUPS):
179 name=data['groups'].get(gid, {'name': ''})['name']
180 req=self.protocolclass.writegroupentryrequest()
181 req.number=gid
182 req.anothernumber=gid
183 req.name=name
184 req.nummembers=data['groups'].get(gid, {'members': 0})['members']
185 self.log("Group #%d %s - %d members" % (gid, `name`, req.nummembers))
186 self.sendpbcommand(req, self.protocolclass.writegroupentryresponse)
187
188
189 self.log("New phonebook\n"+common.prettyprintdict(data['phonebook']))
190
191
192
193 pb=data['phonebook']
194 keys=pb.keys()
195 keys.sort()
196 keys=keys[:self.protocolclass._NUMSLOTS]
197
198 slots=[]
199 for i in range(self.protocolclass._NUMSLOTS):
200 if i not in keys:
201 slots.append(0)
202 continue
203 bmp=0
204 e=pb[i]
205 if len(e['mobile']): bmp|=1
206 if len(e['home']): bmp|=2
207 if len(e['office']): bmp|=4
208 if len(e['pager']): bmp|=8
209 if len(e['fax']): bmp|=16
210 if len(e['email']): bmp|=32
211 if len(e['wireless']): bmp|=64
212 slots.append(bmp)
213 slots="".join([chr(x) for x in slots])
214 req=self.protocolclass.writepbslotsrequest()
215 req.present=slots
216 self.sendpbcommand(req, self.protocolclass.writepbslotsresponse)
217
218 for i in range(len(keys)):
219 slot=keys[i]
220 req=self.protocolclass.writepbentryrequest()
221 req.slotnumber=slot
222 req.entry=self.makephonebookentry(pb[slot])
223 self.log('Writing entry '+`slot`+" - "+req.entry.name)
224 self.progress(i, len(keys), "Writing "+req.entry.name)
225 self.sendpbcommand(req, self.protocolclass.writepbentryresponse)
226 self.progress(len(keys)+1, len(keys)+1, "Phone book write completed - phone will be rebooted")
227 data['rebootphone']=True
228 return data
229
230
232 self.setmode(self.MODEBREW)
233 buffer=prototypes.buffer()
234 request.writetobuffer(buffer, logtitle="audiovox cdm8900 phonebook request")
235 data=buffer.getvalue()
236 data=common.pppescape(data+common.crcs(data))+common.pppterminator
237 first=data[0]
238 try:
239 data=self.comm.writethenreaduntil(data, False, common.pppterminator, logreaduntilsuccess=False)
240 except com_phone.modeignoreerrortypes:
241 self.mode=self.MODENONE
242 self.raisecommsdnaexception("manipulating the phonebook")
243 self.comm.success=True
244
245 origdata=data
246
247
248
249
250 d=data.rfind(common.pppterminator,0,-1)
251 if d>=0:
252 self.log("Multiple PB packets in data - taking last one starting at "+`d+1`)
253 self.logdata("Original pb data", origdata, None)
254 data=data[d+1:]
255
256
257 data=common.pppunescape(data)
258
259
260 d=data.find(first)
261 if d>0:
262 self.log("Junk at begining of pb packet, data at "+`d`)
263 self.logdata("Original pb data", origdata, None)
264 self.logdata("Working on pb data", data, None)
265 data=data[d:]
266
267 crc=data[-3:-1]
268 data=data[:-3]
269 if common.crcs(data)!=crc:
270 self.logdata("Original pb data", origdata, None)
271 self.logdata("Working on pb data", data, None)
272 raise common.CommsDataCorruption("Audiovox phonebook packet failed CRC check", self.desc)
273
274
275 buffer=prototypes.buffer(data)
276 res=responseclass()
277 res.readfrombuffer(buffer, logtitle="Audiovox phonebook response")
278 return res
279
280
281
283
284 protocolclass=Phone.protocolclass
285 serialsname=Phone.serialsname
286
287 WALLPAPER_WIDTH=128
288 WALLPAPER_HEIGHT=145
289 WALLPAPER_CONVERT_FORMAT="jpg"
290
291 MAX_WALLPAPER_BASENAME_LENGTH=16
292 WALLPAPER_FILENAME_CHARS="abcdefghijklmnopqrstuvwxyz0123456789 ."
293
294 MAX_RINGTONE_BASENAME_LENGTH=16
295 RINGTONE_FILENAME_CHARS="abcdefghijklmnopqrstuvwxyz0123456789 ."
296
297
298 usbids=( (0x106c, 0x2101, 1),
299 )
300
301 deviceclasses=("modem",)
302
303
304 _supportedsyncs=(
305 ('phonebook', 'read', None),
306 ('phonebook', 'write', 'OVERWRITE'),
307 )
308
314
316 "Assigns groups based on category data"
317
318 keys=data['groups'].keys()
319 keys.sort()
320 pad=[data['groups'][k]['name'] for k in keys if k]
321
322 groups=helper.getmostpopularcategories(self.protocolclass._NUMGROUPS, data['phonebook'], ["All", "Business", "Personal", "Etc."],
323 self.protocolclass._MAXGROUPLEN, pad)
324
325
326 groups.sort()
327
328
329 newgroups={}
330
331
332 newgroups[0]={'name': 'All', 'members': 0}
333
334
335 for name in groups:
336
337 if name=="All": continue
338 key,value=self._getgroup(name, data['groups'])
339 if key is not None and key!=0:
340 newgroups[key]=value
341 newgroups[key]['members']=0
342
343
344 for name in groups:
345 key,value=self._getgroup(name, newgroups)
346 if key is None:
347 for key in range(1,10000):
348 if key not in newgroups:
349 newgroups[key]={'name': name, 'members': 0}
350 break
351
352 data['groups']=newgroups
353
355 """Converts the data to what will be used by the phone
356
357 @param data: contains the dict returned by getfundamentals
358 as well as where the results go"""
359 self.normalisegroups(helper, data)
360 results={}
361
362
363 pb=data['phonebook']
364
365 slots=[ (helper.getserial(pb[pbentry].get("serials", []), self.serialsname, data['uniqueserial'], "slot", None), pbentry)
366 for pbentry in pb]
367 slots.sort()
368
369 newones=[(pbentry,slot) for slot,pbentry in slots if slot is None]
370 existing=[(pbentry,slot) for slot,pbentry in slots if slot is not None]
371
372 for pbentry,slot in newones+existing:
373 if len(results)==self.protocolclass._NUMSLOTS:
374 break
375 try:
376 e={}
377 entry=data['phonebook'][pbentry]
378 e['mobile']=self.phonize(helper.getnumber(entry.get('numbers', []), 'cell'))
379 e['home']=self.phonize(helper.getnumber(entry.get('numbers', []), 'home'))
380 e['office']=self.phonize(helper.getnumber(entry.get('numbers', []), 'office'))
381 e['pager']=self.phonize(helper.getnumber(entry.get('numbers', []), 'pager'))
382 e['fax']=self.phonize(helper.getnumber(entry.get('numbers', []), 'fax'))
383 emails=helper.getemails(entry.get('emails', []), 0, 2, self.protocolclass._MAXEMAILLEN)
384 e['email']=""
385 e['wireless']=""
386 if len(emails)>=1:
387 e['email']=emails[0]
388 if len(emails)>=2:
389 e['wireless']=emails[1]
390
391
392 if max([len(e[field]) for field in e])==0:
393
394 continue
395
396 e['name']=helper.getfullname(entry.get('names', [ {'full': ''}]), 1, 1, self.protocolclass._MAXNAMELEN)[0]
397 e['memo']=helper.getmemos(entry.get('memos', [{'memo': ''}]), 1,1, self.protocolclass._MAXMEMOLEN)[0]
398
399 rt=helper.getringtone(entry.get('ringtones', []), 'call', "")
400 if rt.startswith("avox "):
401 e['ringtone']=int(rt[5:])
402
403 rt=helper.getringtone(entry.get('ringtones', []), 'message', "")
404 if rt.startswith("avox "):
405 e['msgringtone']=int(rt[5:])
406
407 wp=helper.getwallpaper(entry.get('wallpapers', []), 'call', "")
408 if wp.startswith("avox "):
409 e['wallpaper']=int(wp[5:])
410
411 e['secret']=helper.getflag(entry.get('flags',[]), 'secret', False)
412
413
414 group=helper.getcategory(entry.get('categories', [{'category': 'Etc.'}]),1,1,self.protocolclass._MAXGROUPLEN)[0]
415 gid,_=self._getgroup(group, data['groups'])
416 if gid is None or gid==0:
417 gid,_=self._getgroup("Etc.", data['groups'])
418 assert gid!=0
419 e['group']=gid
420 data['groups'][gid]['members']+=1
421
422 if slot is None or slot<0 or slot>=self.protocolclass._NUMSLOTS or slot in results:
423 for i in range(100000):
424 if i not in results:
425 slot=i
426 break
427 results[slot]=e
428 except helper.ConversionFailed:
429 continue
430 data['phonebook']=results
431 return data
432
433
435 """Convert the phone number into something the phone understands
436
437 All digits, P, T, *, # are kept, everything else is removed.
438 In theory the phone can store a dash in the phonebook, but that
439 is not normal."""
440 return re.sub("[^0-9PT#*]", "", str)[:self.protocolclass._MAXPHONENUMBERLEN]
441