Package phones ::
Module com_moto
|
|
1
2
3
4
5
6
7
8
9
10 """Communicate with Motorola phones using AT commands. This code is for all Motorola phones
11 with specific subclasses for CDMA and GSM variants"""
12
13
14 import sha
15
16
17 import commport
18 import com_etsi
19 import phoneinfo
20 import prototypes
21 import p_moto
22 import sms
23
24 -class Phone(com_etsi.Phone):
25 """Talk to a generic Motorola phone.
26 """
27 desc='Motorola'
28 protocolclass=p_moto
29 MODEPHONEBOOK="modephonebook"
30
31 - def __init__(self, logtarget, commport):
34
35
42
48
54
60
62 """convert an UCS-2 to ASCII string"""
63 return v.decode('hex').decode('utf_16be')
65 """convert an ascii string to UCS-2"""
66 return v.encode('utf_16be').encode('hex').upper()
67
72
81
86
91
93 """Decode a Motorola unicode string"""
94
95 _idx=v.find('\x00\x00')
96
97 if _idx==-1:
98 return v.decode('utf_16_le')
99 else:
100 return v[:_idx+1].decode('utf_16_le')
102 """Encode a unicode/string into a Motorola unicode"""
103 return (v+'\x00').encode('utf_16_le')
104
105
138
139
141 """Gets information fundamental to interopating with the phone and UI.
142
143 Currently this is:
144
145 - 'uniqueserial' a unique serial number representing the phone
146 - 'groups' the phonebook groups
147 - 'wallpaper-index' map index numbers to names
148 - 'ringtone-index' map index numbers to ringtone names
149
150 This method is called before we read the phonebook data or before we
151 write phonebook data.
152 """
153 self.log("Retrieving fundamental phone information")
154 self.progress(0, 100, 'Retrieving fundamental phone information')
155 self.setmode(self.MODEPHONEBOOK)
156 self.charset_ascii()
157 self.log("Phone serial number")
158 results['uniqueserial']=sha.new(self.get_esn()).hexdigest()
159
160 self.log("Reading group information")
161 results['groups']=self._get_groups()
162
163 self.setmode(self.MODEBREW)
164 self.log('Reading Ringtone Index')
165 results['ringtone-index']=self._get_ringtone_index()
166
167 self.log('Reading Wallpaper Index')
168 results['wallpaper-index']=self._get_wallpaper_index()
169
170 self._update_group_ringtone(results)
171
172 self.log("Fundamentals retrieved")
173 self.setmode(self.MODEMODEM)
174 return results
175
177 _ringtone_index=results.get('ringtone-index', {})
178 _groups=results.get('groups', {})
179 for _key,_entry in _groups.items():
180 _rt_idx=_entry['ringtone']
181 _groups[_key]['ringtone']=_ringtone_index.get(_rt_idx, {}).get('name', None)
182 results['groups']=_groups
184 """Create a new ringtone dict keyed by name for lookup"""
185 _rt_index=fundamentals.get('ringtone-index', {})
186 _rt_name_index={}
187 for _key,_entry in _rt_index.items():
188 _rt_name_index[_entry['name']]=_key
189 return _rt_name_index
191 """Create a new group dict keyed by name for lookup"""
192 _grp_name_index={}
193 for _key,_entry in fundamentals.get('groups', {}).items():
194 _grp_name_index[_entry['name']]=_key
195 return _grp_name_index
196
197
199 """Mark the speed dial slots being used"""
200 for _key,_entry in enumerate(entries):
201 _sd=_entry.get('speeddial', None)
202 if _sd is not None:
203 if sd_slots[_sd]:
204 entries[_key]['speeddial']=None
205 else:
206 sd_slots[_sd]=_entry[key_name]
207
209 """Populate the next available speed dial"""
210 for _index,_entry in enumerate(entries):
211 if _entry.get('speeddial', None) is None:
212 try:
213 _new_sd=sd_slots.index(False)
214 entries[_index]['speeddial']=_new_sd
215 sd_slots[_new_sd]=_entry[key_name]
216 except ValueError:
217 self.log('Failed to allocate speed dial value')
218
220 """Make sure that each and every number/email/mail list has a
221 speed dial, which is being used as the slot/index number
222 """
223 _pb_book=fundamentals.get('phonebook', {})
224 _sd_slots=[False]*(self.protocolclass.PB_TOTAL_ENTRIES+1)
225 _sd_slots[0]=True
226
227 for _key,_pb_entry in _pb_book.items():
228 self._mark_used_slots(_pb_entry.get('numbers', []), _sd_slots,
229 'number')
230 self._mark_used_slots(_pb_entry.get('emails', []), _sd_slots,
231 'email')
232 self._mark_used_slots(_pb_entry.get('maillist', []), _sd_slots,
233 'entry')
234
235 for _key, _pb_entry in _pb_book.items():
236 self._get_sd_slot(_pb_entry.get('numbers', []), _sd_slots,
237 'number')
238 self._get_sd_slot(_pb_entry.get('emails', []), _sd_slots,
239 'email')
240 self._get_sd_slot(_pb_entry.get('maillist', []), _sd_slots,
241 'entry')
242 return _sd_slots
243
244
246 raise NotImplementedError
248 raise NotImplementedError
250 raise NotImplementedError
252 raise NotImplementedError
253 - def _build_pb_entry(self, entry, pb_book, fundamentals):
254 raise NotImplementedError
255
256
257 - def _build_pb_entry(self, entry, pb_book, fundamentals):
258 """Build a BitPim phonebook entry based on phone data.
259 Need to to implement in subclass for each phone
260 """
261 raise NotImplementedError
263 raise NotImplementedError
264
266 """Reads the phonebook data. The L{getfundamentals} information will
267 already be in result."""
268 self.log('Getting phonebook')
269 self.setmode(self.MODEPHONEBOOK)
270
271 self.select_phonebook()
272
273 pb_book={}
274 result['pb_list']=[]
275 result['sd_dict']={}
276
277 _total_entries=self.protocolclass.PB_TOTAL_ENTRIES
278 _req=self.protocolclass.read_pb_req()
279 for _start_idx in range(1, _total_entries+1, 10):
280 _end_idx=min(_start_idx+9, _total_entries)
281 _req.start_index=_start_idx
282 _req.end_index=_end_idx
283 for _retry_cnt in range(2):
284 try:
285 self.progress(_end_idx, _total_entries,
286 'Reading contact entry %d to %d'%(_start_idx, _end_idx))
287 _res=self.sendATcommand(_req, self.protocolclass.read_pb_resp)
288 for _entry in _res:
289 self._build_pb_entry(_entry, pb_book, result)
290 break
291 except:
292 if _retry_cnt:
293 self.log('Failed to read phonebook data')
294 else:
295 self.log('Failed to read phonebook data, retrying...')
296 self._update_mail_list(pb_book, result)
297 self.setmode(self.MODEMODEM)
298 del result['pb_list'], result['sd_dict']
299 _keys=result['groups'].keys()
300 result['categories']=[x['name'] for _,x in result['groups'].items()]
301 result['phonebook']=pb_book
302 return pb_book
303
320
321
322 - def _build_cal_entry(self, entry, calendar, fundamentals):
323 """Build a BitPim calendar object from phonebook data"""
324 raise NotImplementedError
325
326 - def del_calendar_entry(self, index):
327 _req=self.protocolclass.calendar_write_ex_req()
328 _req.index=index
329 _req.nth_event=0
330 _req.ex_event_flag=0
331 self.sendATcommand(_req, None)
332
341
343 """Read all calendars from the phone"""
344 self.log('Reading calendar entries')
345 self.setmode(self.MODEPHONEBOOK)
346 self.lock_calendar()
347 _total_entries=self.protocolclass.CAL_TOTAL_ENTRIES
348 _max_entry=self.protocolclass.CAL_MAX_ENTRY
349 _req=self.protocolclass.calendar_read_req()
350 _calendar={ 'exceptions': [] }
351 for _start_idx in range(0, _total_entries, 10):
352 _end_idx=min(_start_idx+9, _max_entry)
353 _req.start_index=_start_idx
354 _req.end_index=_end_idx
355 for _retry in range(2):
356 try:
357 self.progress(_end_idx, _total_entries,
358 'Reading calendar entry %d to %d'%(_start_idx, _end_idx))
359 _res=self.sendATcommand(_req, self.protocolclass.calendar_req_resp)
360 for _entry in _res:
361 self._build_cal_entry(_entry, _calendar, result)
362 except:
363 if _retry:
364 self.log('Failed to read calendar data')
365 else:
366 self.log('Failed to read calendar data, retrying ...')
367 self._process_exceptions(_calendar)
368 del _calendar['exceptions']
369 self.lock_calendar(False)
370 self.setmode(self.MODEMODEM)
371 result['calendar']=_calendar
372 return result
373
383
384
389
408
409 - def _process_sms_text(self, res, entry):
410 _s=res[1]
411 _open_p=_s.find('(')
412 _close_p=_s.find(')')
413 if _open_p==0 and _close_p!=-1:
414
415 entry.subject=_s[1:_close_p]
416 res[1]=_s[_close_p+1:]
417 entry.text='\n'.join(res[1:])
418
431
432 - def getsms(self, fundamentals):
460
461
462 parentprofile=com_etsi.Profile
465