Package phones ::
Module com_samsungscha650
|
|
1
2
3
4
5
6
7
8
9
10
11 """Communicate with a Samsung SCH-A650"""
12
13
14 import copy
15 import re
16 import sha
17
18
19
20 import common
21 import commport
22 import com_brew
23 import com_samsung
24 import com_phone
25 import conversions
26 import fileinfo
27 import memo
28 import nameparser
29 import p_samsungscha650
30 import prototypes
31
32 import call_history
33
34
35 -class Phone(com_samsung.Phone):
36
37 "Talk to the Samsung SCH-A650 Cell Phone"
38
39 desc="SCH-A650"
40 serialsname='scha650'
41 protocolclass=p_samsungscha650
42 parent_phone=com_samsung.Phone
43
44 __groups_range=xrange(5)
45 __phone_entries_range=xrange(1,501)
46 __pb_max_entries=25
47 __pb_max_speeddials=500
48 __pb_entry=0
49 __pb_mem_loc=1
50 __pb_group=2
51 __pb_ringtone=3
52 __pb_name=4
53 __pb_speed_dial=5
54 __pb_home_num=7
55 __pb_office_num=9
56 __pb_mobile_num=11
57 __pb_pager_num=13
58 __pb_fax_num=15
59 __pb_alias=17
60 __pb_email=21
61 __pb_four=22
62 __pb_blanks=(19, 20)
63 __pb_date_time_stamp=24
64 __pb_numbers= ({'home': __pb_home_num},
65 {'office': __pb_office_num},
66 {'cell': __pb_mobile_num},
67 {'pager': __pb_pager_num},
68 {'fax': __pb_fax_num})
69 __pb_max_name_len=22
70 __pb_max_number_len=32
71 __pb_max_emails=1
72
73
74 __ringtone_info=('ringtone', 'ringtone-index', 'ringtone', 'user/sound/ringer', 17, 20)
75 __wallpaper_info=('wallpapers', 'wallpaper-index', 'images', 'nvm/brew/shared', 17, 10)
76
77 - def __init__(self, logtarget, commport):
82
84
85 """Gets information fundamental to interopating with the phone and UI.
86
87 Currently this is:
88
89 - 'uniqueserial' a unique serial number representing the phone
90 - 'groups' the phonebook groups
91 - 'wallpaper-index' map index numbers to names
92 - 'ringtone-index' map index numbers to ringtone names
93
94 This method is called before we read the phonebook data or before we
95 write phonebook data.
96 """
97
98 self.setmode(self.MODEPHONEBOOK)
99
100
101
102 self.log("Retrieving fundamental phone information")
103 self.log("Reading phone serial number")
104 results['uniqueserial']=sha.new(self.get_esn()).hexdigest()
105
106
107
108 self.log("Reading group information")
109 g=self.get_groups(self.__groups_range)
110 groups={}
111 for i, g_i in enumerate(g):
112 if len(g_i):
113 groups[i]={ 'name': g_i }
114 results['groups']=groups
115
116
117 self.setmode(self.MODEBREW)
118 rt_index=RingtoneIndex(self)
119 results['ringtone-index']=rt_index.get()
120
121
122 img_index=ImageIndex(self)
123 results['wallpaper-index']=img_index.get()
124
125 self.setmode(self.MODEMODEM)
126 self.log("Fundamentals retrieved")
127
128 return results
129
131 """Reads the phonebook data. The L{getfundamentals} information will
132 already be in result."""
133 self.setmode(self.MODEBREW)
134 pb=PhoneBook(self)
135 pb.read()
136 pb_book=pb.get_dict(result)
137 result['phonebook']=pb_book
138 self.setmode(self.MODEMODEM)
139 return pb_book
140
142 "Saves out the phonebook"
143
144 pb_book=data['phonebook']
145 pb_groups=data['groups']
146 ringtone_index=data.get('ringtone-index', {})
147 self.log('Validating phonebook entries.')
148 del_entries=[]
149 for k in pb_book:
150 if not self.__validate_entry(pb_book[k], pb_groups, ringtone_index):
151 self.log('Invalid entry, entry will be not be sent.')
152 del_entries.append(k)
153 for k in del_entries:
154 self.log('Deleting entry '+\
155 nameparser.getfullname(pb_book[k]['names'][0]))
156 del pb_book[k]
157 self._has_duplicate_speeddial(pb_book)
158 self.log('All entries validated')
159
160 pb_locs=[False]*(len(self.__phone_entries_range)+1)
161 pb_mem=[False]*len(pb_locs)
162
163
164 self.log("Getting current phonebook from the phone")
165 self.setmode(self.MODEBREW)
166 phone_book=PhoneBook(self)
167 phone_book.read()
168 current_pb=phone_book.get_dict(data)
169 self.setmode(self.MODEMODEM)
170
171
172 self.log("Processing speeddial data")
173 for k in pb_book:
174 self._update_speeddial(pb_book[k])
175
176
177 self.setmode(self.MODEPHONEBOOK)
178 self.log("Processing deleted entries")
179
180 for k1 in current_pb:
181 s1=current_pb[k1]['serials'][0]['serial1']
182 found=False
183 for k2 in pb_book:
184 if self._same_serial1(s1, pb_book[k2]):
185 found=True
186 break
187 if found:
188 pb_locs[int(current_pb[k1]['serials'][0]['serial1'])]=True
189 pb_mem[int(current_pb[k1]['serials'][0]['serial2'])]=True
190 else:
191 self.log("Deleted item: "+\
192 nameparser.getfullname(current_pb[k1]['names'][0]))
193
194 self.progress(0, 10, "Deleting "+\
195 nameparser.getfullname(\
196 current_pb[k1]['names'][0]))
197 self._del_phone_entry(current_pb[k1])
198 mem_idx, loc_idx = self.__pb_max_speeddials, 1
199
200
201 self.log("Processing new & updated entries")
202 serials_update=[]
203 progresscur, progressmax=1,len(pb_book)
204 for k in pb_book:
205 if progresscur>len(self.__phone_entries_range):
206 self.log('Max phone entries exceeded: '+str(progresscur))
207 break
208 e=pb_book[k]
209 if not self._has_serial1(e):
210 while pb_locs[loc_idx]:
211 loc_idx += 1
212 pb_locs[loc_idx]=True
213 sd=self._get_speeddial(e)
214 if sd:
215 mem_index=sd
216 pb_mem[sd]=True
217 else:
218 while pb_mem[mem_idx]:
219 mem_idx -= 1
220 pb_mem[mem_idx]=True
221 mem_index=mem_idx
222 self._set_speeddial(e, mem_idx)
223 s1={ 'sourcetype': self.serialsname,
224 'sourceuniqueid': data['uniqueserial'],
225 'serial1': `loc_idx`,
226 'serial2': `mem_index` }
227 e['serials'].append(s1)
228 self.log("New entries: Name: "+\
229 nameparser.getfullname(e['names'][0])+\
230 ", s1: "+`loc_idx`+", s2: "+`mem_index`)
231 serials_update.append((self._bitpim_serials(e), s1))
232 self.progress(progresscur, progressmax, "Updating "+\
233 nameparser.getfullname(e['names'][0]))
234 if not self._write_phone_entry(e, pb_groups, ringtone_index,
235 phone_book):
236 self.log("Failed to save entry: "+\
237 nameparser.getfullname(e['names'][0]))
238 progresscur += 1
239
240 data["serialupdates"]=serials_update
241 self.log("Done")
242 self.setmode(self.MODEMODEM)
243 return data
244
245
246 - def __validate_entry(self, pb_entry, pb_groups, ringtone_index):
247 try:
248
249 name=nameparser.getfullname(pb_entry['names'][0]).replace('"', '')
250 if len(name)>self.__pb_max_name_len:
251 name=name[:self.__pb_max_name_len]
252 pb_entry['names'][0].setdefault('full', name)
253 if pb_entry['names'][0].has_key('nickname'):
254 name=re.sub('[,"]', '', pb_entry['names'][0]['nickname'])
255 if len(name)>self.__pb_max_name_len:
256 name=name[:self.__pb_max_name_len]
257 if pb_entry['names'][0]['nickname']!=name:
258 pb_entry['names'][0]['nickname']=name
259
260 has_number_or_email=False
261 if pb_entry.has_key('numbers'):
262 for n in pb_entry['numbers']:
263 num=self.phonize(n['number'])
264 if len(num)>self.__pb_max_number_len:
265 num=num[:self.__pb_max_number_len]
266 if num != n['number']:
267 self.log('Updating number from '+n['number']+' to '+num)
268 n['number']=num
269 try:
270 self._get_number_type(n['type'])
271 except:
272 self.log(n['number']+': setting type to home.')
273 n['type']='home'
274 has_number_or_email=True
275
276 if pb_entry.has_key('emails'):
277 if len(pb_entry['emails'])>self.__pb_max_emails:
278 self.log(name+': Each entry can only have %s emails. The rest will be ignored.'%str(self.__pb_max_emails))
279 email=pb_entry['emails'][0]['email'].replace('"', '')
280 if len(email)>self.__pb_max_number_len:
281 email=email[:self.__pb_max_number_len]
282 if email!=pb_entry['emails'][0]['email']:
283 pb_entry['emails'][0]['email']=email
284 has_number_or_email=True
285 if not has_number_or_email:
286 self.log(name+': Entry has no numbers or emails')
287
288 return False
289
290 found=False
291 if pb_entry.has_key('categories') and len(pb_entry['categories']):
292 pb_cat=pb_entry['categories'][0]['category']
293 for k in pb_groups:
294 if pb_groups[k]['name']==pb_cat:
295 found=True
296 break
297 if not found:
298 self.log(name+': category set to '+pb_groups[0]['name'])
299 pb_entry['categories']=[{'category': pb_groups[0]['name']}]
300
301 found=False
302 if pb_entry.has_key('ringtones') and len(pb_entry['ringtones']):
303 pb_rt=pb_entry['ringtones'][0]['ringtone']
304
305 for k, rt in ringtone_index.items():
306 if pb_rt==rt['name']:
307 found=True
308 break
309 if not found:
310 rt=ringtone_index[0]['name']
311 self.log(name+': ringtone set to '+rt)
312 pb_entry['ringtones']=[{'ringtone': rt,
313 'use': 'call' }]
314
315 return True
316 except:
317 raise
318
320 b=[False]*(self.__pb_max_speeddials+1)
321 for k in pb_book:
322 try:
323 for k1, kk in enumerate(pb_book[k]['numbers']):
324 sd=kk['speeddial']
325 if sd and b[sd]:
326
327 del pb_book[k]['numbers'][k1]['speeddial']
328 self.log('speeddial %d exists, deleted'%sd)
329 else:
330 b[sd]=True
331 except:
332 pass
333 return False
334
348
350 n=pb_entry.get('numbers', [])
351 for k in n:
352 try:
353 if k['speeddial']:
354 return k['speeddial']
355 except:
356 pass
357 return 0
358
360 if not pb_entry.has_key('numbers'):
361
362 return
363 for k in pb_entry['numbers']:
364 if k.has_key('speeddial'):
365 k['speeddial']=sd
366 return
367 pb_entry['numbers'][0]['speeddial']=sd
368
369 - def _del_phone_entry(self, pb_entry):
370 try:
371 return self.save_phone_entry(self._my_serials(pb_entry)['serial1'])
372 except:
373 return False
374
376 for k in pb_entry['serials']:
377 if k['sourcetype']==self.serialsname and k.has_key('serial1'):
378 return k['serial1']==s1
379 return False
380
382 for k in pb_entry['serials']:
383 if k['sourcetype']==self.serialsname and k.has_key('serial1'):
384 return True
385 return False
386
388 for k in pb_entry['serials']:
389 if k['sourcetype']=="bitpim":
390 return k
391 return {}
392
394 for k in range(len(pb_entry['serials'])):
395 if pb_entry['serials'][k]['sourcetype']==self.serialsname:
396 del pb_entry['serials'][k]
397 return
398
400 for k in pb_entry['serials']:
401 if k['sourcetype']==self.serialsname:
402 return k
403 return {}
404
411
412
413 - def _write_phone_entry(self, pb_entry, groups, ringtone_index, phone_book):
414
415
416 e=['0']*self.__pb_max_entries
417
418
419 serials=self._my_serials(pb_entry)
420 e[self.__pb_entry]=serials['serial1']
421 e[self.__pb_mem_loc]=serials['serial2']
422
423
424 grp=0
425 try:
426 grp_name=pb_entry['categories'][0]['category']
427 for k in range(len(groups)):
428 if groups[k]['name']==grp_name:
429 grp=k
430 break
431
432 except:
433
434 grp, pb_entry['categories']=0, [{'category': groups[0]['name']}]
435 e[self.__pb_group]=`grp`
436
437
438 e[self.__pb_ringtone]='0'
439 try:
440 rt=pb_entry['ringtones'][0]['ringtone']
441 for k, n in ringtone_index.items():
442 if rt==n['name']:
443 e[self.__pb_ringtone]=`k`
444 break
445 except:
446 pass
447
448
449 e[self.__pb_name]='"'+nameparser.getfullname(pb_entry['names'][0])+'"'
450 nick_name=''
451 try:
452 nick_name=pb_entry['names'][0]['nickname']
453 except:
454 pass
455
456 e[self.__pb_alias]=nick_name
457 if len(nick_name):
458 e[self.__pb_alias+1]='0'
459 else:
460 e[self.__pb_alias+1]=''
461
462
463
464
465
466 for k in range(len(self.__pb_numbers)):
467 for kk in self.__pb_numbers[k]:
468 e[self.__pb_numbers[k][kk]]=''
469 e[self.__pb_numbers[k][kk]+1]=''
470 speed_dial='0'
471 n=pb_entry.get('numbers', [])
472 for k in range(len(n)):
473 try:
474 nk=n[k]
475 kkk, kk=self._get_number_type(nk['type'])
476 except:
477
478 nk['type']='home'
479 kkk, kk=0, self.__pb_home_num
480 e[kk],e[kk+1]=self.phonize(nk['number']),'0'
481 try:
482 if nk['speeddial']:
483 speed_dial=`kkk`
484 except:
485 pass
486 e[self.__pb_speed_dial]=speed_dial
487
488
489 email=''
490 try:
491 email=pb_entry['emails'][0]['email']
492 except:
493 pass
494
495 e[self.__pb_email]='"'+email+'"'
496 e[self.__pb_four]='4'
497 for k in self.__pb_blanks:
498 e[k]=''
499
500 e[self.__pb_date_time_stamp]=self.get_time_stamp()
501
502
503
504 ee=self.get_phone_entry(int(e[self.__pb_entry]),
505 self.__pb_alias, self.__pb_max_entries)
506 if len(ee)==self.__pb_max_entries:
507
508 ee[self.__pb_name]='"'+ee[self.__pb_name]+'"'
509 ee[self.__pb_email]='"'+ee[self.__pb_email]+'"'
510
511 ee[self.__pb_ringtone]=str(phone_book.get_ringtone(\
512 int(e[self.__pb_mem_loc])))
513 k=self.__pb_max_entries-2
514 if e[0:k]==ee[0:k]:
515 return True
516 return self.save_phone_entry('0,'+','.join(e))
517
525
533
541
549
550 getmemo=parent_phone._getmemo
551 savememo=parent_phone._savememo
552
553 gettodo=parent_phone._gettodo
554 savetodo=parent_phone._savetodo
555
556 getsms=parent_phone._getsms
557 savesms=parent_phone._savesms
558
559 getphoneinfo=parent_phone._getphoneinfo
560
561 getmedia=None
562
563
564 -class Profile(com_samsung.Profile):
565
566 serialsname='scha650'
567
568 WALLPAPER_WIDTH=128
569 WALLPAPER_HEIGHT=160
570 MAX_WALLPAPER_BASENAME_LENGTH=17
571 WALLPAPER_FILENAME_CHARS="abcdefghijklmnopqrstuvwxyz0123456789_*[]=<>;|?:% ."
572 WALLPAPER_CONVERT_FORMAT="png"
573
574 MAX_RINGTONE_BASENAME_LENGTH=17
575 RINGTONE_FILENAME_CHARS="abcdefghijklmnopqrstuvwxyz0123456789_*[]=<>;|?:% ."
576 RINGTONE_LIMITS= {
577 'MAXSIZE': 30000
578 }
579
580 phone_manufacturer='SAMSUNG ELECTRONICS'
581 phone_model='SCH-A650/163'
582
585
586 _supportedsyncs=(
587 ('phonebook', 'read', None),
588 ('phonebook', 'write', 'OVERWRITE'),
589 ('calendar', 'read', None),
590 ('calendar', 'write', 'OVERWRITE'),
591 ('ringtone', 'read', None),
592 ('ringtone', 'write', 'OVERWRITE'),
593 ('wallpaper', 'read', None),
594 ('wallpaper', 'write', 'OVERWRITE'),
595 ('memo', 'read', None),
596 ('memo', 'write', 'OVERWRITE'),
597 ('todo', 'read', None),
598 ('todo', 'write', 'OVERWRITE'),
599 ('sms', 'read', None),
600 )
601
602 if __debug__:
603 _supportedsyncs+=(('sms', 'write', 'OVERWRITE'),)
604
607
608 __audio_ext={ 'MIDI': 'mid', 'QCP': 'qcp', 'PMD': 'pmd' }
609 - def QueryAudio(self, origin, currentextension, afi):
618
619
620
621 imageorigins={}
622 imageorigins.update(common.getkv(com_samsung.Profile.stockimageorigins, "images"))
623
624 imagetargets={}
625 imagetargets.update(common.getkv(com_samsung.Profile.stockimagetargets, "wallpaper",
626 {'width': 128, 'height': 128, 'format': "PNG"}))
627 imagetargets.update(common.getkv(com_samsung.Profile.stockimagetargets, "fullscreen",
628 {'width': 128, 'height': 160, 'format': "PNG"}))
629
633
637
638
641 self.__phone=phone
642 self.__file_type, self.__index_type, self.__origin, self.__path, self.__max_file_len, self.__max_file_count=info
643
650
677
691
745
746
748 __builtin_ringtones=( 'Inactive',
749 'Bell 1', 'Bell 2', 'Bell 3', 'Bell 4', 'Bell 5',
750 'Melody 1', 'Melody 2', 'Melody 3', 'Melody 4', 'Melody 5',
751 'Melody 6', 'Melody 7', 'Melody 8', 'Melody 9', 'Melody 10')
752
755
757 r={}
758 for k, n in enumerate(self.__builtin_ringtones):
759 r[k]={ 'name': n, 'origin': 'builtin' }
760 return r
761
779
784
800
801
803 __builtin_images=( 'Clock1', 'Dual Clock', 'Calendar', 'Aquarium',
804 'Landscape', 'Water Drop' )
805
808
810 r={}
811 for k, n in enumerate(self.__builtin_images):
812 r[k]={ 'name': n, 'origin': 'builtin' }
813 return r
814
832
837
853
854
857 self.__phone=phone
858 self.__numbers=None
859
869
870 - def get(self, index, default=None):
877
878
880
881 __pb_numbers= ({'home': 'home_num_index' },
882 {'office': 'office_num_index' },
883 {'cell': 'mobile_num_index' },
884 {'pager': 'pager_num_index' },
885 {'fax': 'fax_num_index' })
887 self.__phone=phone
888 self.__pb=None
889 self.__numbers=None
890 self.__groups=None
891 self.__rt_index=None
892 self.__id=None
893 self.__slots=None
894
904
906 """
907 Return the ringtone index of this entry.
908 """
909 if self.__pb is None:
910 self.read()
911 rt=self.__pb.entry[index].ringer_type
912 if rt:
913 rt-=71
914 return rt
915
917 res={}
918
919 res['serials']=[ {'sourcetype': self.__phone.serialsname,
920 'sourceuniqueid': self.__id,
921 'serial1': `pb_cnt`,
922 'serial2': `mem_index` }]
923
924 res['names']=[ {'full': e.name } ]
925 if e.alias_num_index:
926 res['names'][0]['nickname']=self.__numbers.get(e.alias_num_index, '')
927
928
929 res['categories']=[ {'category': self.__groups[e.group_num]['name'] } ]
930
931
932 if e.email_index:
933 res['emails']=[ { 'email': self.__numbers.get(e.email_index, '') } ]
934
935
936
937
938
939
940
941 rt=e.ringer_type
942 if rt:
943 rt-=71
944 res['ringtones']=[ { 'ringtone': self.__rt_index[rt]['name'],
945 'use': 'call' } ]
946
947
948 speed_dial=e.speed_dial_index
949 res['numbers']=[]
950 for k, a in enumerate(self.__pb_numbers):
951 for key, attr in a.items():
952 idx=getattr(e, attr, 0)
953 if idx:
954 num=self.__numbers.get(idx, '')
955 if idx==speed_dial:
956 res['numbers'].append({ 'number': num,
957 'type': key,
958 'speeddial': mem_index } )
959 else:
960 res['numbers'].append({ 'number': num,
961 'type': key })
962
963 return res
964
966
967 if self.__pb is None:
968 self.read()
969
970 if self.__numbers is None:
971 self.__numbers=PhoneNumbers(self.__phone)
972 self.__numbers.read()
973
974 if self.__slots is None:
975 self.__slots=PBSlot(self.__phone)
976 self.__slots.read()
977
978 self.__groups=result.get('groups', {})
979 self.__rt_index=result.get('ringtone-index', {})
980 self.__id=result.get('uniqueserial', '')
981
982 r={}
983 for pb_cnt, i in enumerate(self.__slots):
984 if i==0:
985
986 continue
987 e=self.__pb.entry[i]
988 if e.mem_index:
989 if i != e.mem_index:
990 self.__phone.log('i: %d, mem_index: %d'%(i, e.mem_index))
991 r[pb_cnt]=self.__extract_entry(e, pb_cnt, i)
992 return r
993
994
996 """ Class to handle Phonebook entry slot -> memory slot """
998 self.__phone=phone
999 self.__slots=None
1000
1010
1012 if type(key) is not int:
1013 raise KeyError
1014 if key<0 or key>=self.__phone.protocolclass.max_pb_slots:
1015 raise IndexError
1016 if self.__slots is None:
1017 self.read()
1018 return self.__slots.slot[key].pbbook_index
1019