Package phones ::
Module com_samsung_packet
|
|
1
2
3
4
5
6
7
8
9
10
11 """Communicate with a Samsung SCH-Axx phone using AT commands"""
12
13
14 import time
15 import re
16 import datetime
17
18
19 import bpcalendar
20 import p_brew
21 import com_brew
22 import com_phone
23 import prototypes
24 import common
25 import commport
26 import todo
27 import memo
28
29 -class Phone(com_phone.Phone, com_brew.BrewProtocol):
30 "Talk to a Samsung phone using AT commands"
31
32 desc="Samsung SPH-Axx phone"
33
34 MODEPHONEBOOK="modephonebook"
35
36 __read_timeout=0.1
37
38
39
40
41 __cal_end_datetime_value=None
42 __cal_alarm_values={0: 10, 1: 30, 2: 60, 3: -1, 4: 0 }
43 __cal_max_name_len=32
44 _cal_max_events_per_day=9
45
46 builtinringtones=()
47
48 builtinimages=()
49
50 - def __init__(self, logtarget, commport):
55
61
63 self.log("_setmodemodemtobrew")
64 self.log('Switching from modem to BREW')
65 try:
66 self.comm.sendatcommand('$QCDMG')
67 return True
68 except commport.ATError:
69 return False
70
72 self.log("_setmodebrewtomodem")
73 self.log('Switching from BREW to modem')
74 try:
75 self.modemmoderequest()
76 self.mode=self.MODEMODEM
77 return True
78 except:
79 pass
80
81 try:
82 self.modemmoderequest()
83 self.mode=self.MODEMODEM
84 return True
85 except:
86 return False
87
89 self.log("_setmodemodemtophonebook")
90 self.log('Switching from modem to phonebook')
91 response=self.comm.sendatcommand("#PMODE=1")
92 return True
93
95 self.log("_setmodemodem")
96 req=p_brew.memoryconfigrequest()
97 respc=p_brew.memoryconfigresponse
98
99
100 try:
101 self.comm.sendatcommand("Z")
102 self.comm.sendatcommand('E0V1')
103 return True
104 except:
105 pass
106
107
108 for baud in 0, 38400,115200:
109 if baud:
110 if not self.comm.setbaudrate(baud):
111 continue
112 try:
113 self.sendbrewcommand(req, respc, callsetmode=False)
114 self.log('In BREW mode, trying to switch to Modem mode')
115
116 if self._setmodebrewtomodem():
117 break
118 return False
119 except com_brew.modeignoreerrortypes:
120 pass
121
122
123 for baud in (0, 115200, 19200, 230400):
124 self.log("Baud="+`baud`)
125 if baud:
126 if not self.comm.setbaudrate(baud):
127 continue
128
129 try:
130 self.comm.sendatcommand("Z")
131 self.comm.sendatcommand('E0V1')
132 return True
133 except:
134 pass
135
136 return False
137
143
145 self.log("_setmodephonebooktomodem")
146 self.log('Switching from phonebook to modem')
147 response=self.comm.sendatcommand("#PMODE=0")
148 return True
149
150 - def sendpbcommand(self, request, responseclass, ignoreerror=False, fixup=None):
179
227
250
252 "Repair a line from a phone with broken firmware"
253 return line
254
287
289 """Extract and build phone numbers"""
290 res['numbers']=[]
291 secret=0
292
293 speeddialtype=entry.speeddial
294 numberindex=0
295 for type in self.numbertypetab:
296 if len(entry.numbers[numberindex].number):
297 numhash={'number': entry.numbers[numberindex].number, 'type': type }
298 if entry.numbers[numberindex].secret==1:
299 secret=1
300 if speeddialtype==numberindex:
301 numhash['speeddial']=entry.uslot
302 res['numbers'].append(numhash)
303
304 numberindex+=1
305
306
307
308 res['flags']=[ {'secret': secret} ]
322
324 res={}
325
326 res['serials']=[ {'sourcetype': self.serialsname,
327 'slot': entry.slot,
328 'sourceuniqueid': fundamentals['uniqueserial']} ]
329
330 res['names']=[ {'full': entry.name} ]
331
332 cat=fundamentals['groups'].get(entry.group, {'name': "Unassigned"})['name']
333 if cat!="Unassigned":
334 res['categories']=[ {'category': cat} ]
335
336 if len(entry.email):
337 res['emails']=[ {'email': entry.email} ]
338
339 if len(entry.url):
340 res['urls']=[ {'url': entry.url} ]
341
342
343 self._extractphonebook_numbers(entry, fundamentals, res)
344 self._extractphonebook_ringtone(entry, fundamentals, res)
345 self._extractphonebook_wallpaper(entry, fundamentals, res)
346
347
348
349
350
351 return res
352
354 "Saves out the phonebook"
355
356 pb=data['phonebook']
357 keys=pb.keys()
358 keys.sort()
359 keys=keys[:self.protocolclass.NUMPHONEBOOKENTRIES]
360
361
362
363
364
365
366 uslots={}
367 names={}
368 birthdays={}
369 req=self.protocolclass.phonebookslotrequest()
370
371 self.log('Erasing '+self.desc+' phonebook')
372 progressmax=self.protocolclass.NUMPHONEBOOKENTRIES+len(keys)
373 for slot in range(1,self.protocolclass.NUMPHONEBOOKENTRIES+1):
374 req.slot=slot
375 self.progress(slot,progressmax,"Erasing "+`slot`)
376 try:
377 res=self.sendpbcommand(req,self.protocolclass.phonebookslotresponse, fixup=self.pblinerepair)
378 if len(res) > 0:
379 names[slot]=res[0].entry.name
380 birthdays[slot]=res[0].entry.birthday
381 if len(res[0].entry.url)>0:
382 reqhack=self.protocolclass.phonebookslotupdaterequest()
383 reqhack.entry=res[0].entry
384 reqhack.entry.url=""
385 reqhack.entry.ringtone=self.protocolclass.DEFAULT_RINGTONE
386 reqhack.entry.wallpaper=self.protocolclass.DEFAULT_WALLPAPER
387 reqhack.entry.timestamp=[1900,1,1,0,0,0]
388 self.sendpbcommand(reqhack, self.protocolclass.phonebookslotupdateresponse)
389 else:
390 names[slot]=""
391 except:
392 names[slot]=""
393 self.log("Slot "+`slot`+" read failed")
394 reqerase=self.protocolclass.phonebooksloterase()
395 reqerase.slot=slot
396 self.sendpbcommand(reqerase, self.protocolclass.phonebookslotupdateresponse)
397
398 self.savegroups(data)
399
400 for i in range(len(keys)):
401 slot=keys[i]
402 req=self.protocolclass.phonebookslotupdaterequest()
403 req.entry=self.makeentry(pb[slot],data)
404 if names[slot]==req.entry.name:
405 req.entry.birthday=birthdays[slot]
406 self.log('Writing entry '+`slot`+" - "+req.entry.name)
407 self.progress(i+self.protocolclass.NUMPHONEBOOKENTRIES,progressmax,"Writing "+req.entry.name)
408 self.sendpbcommand(req, self.protocolclass.phonebookslotupdateresponse)
409 self.progress(progressmax+1,progressmax+1, "Phone book write completed")
410 return data
411
412 - def makeentry(self, entry, data):
413 e=self.protocolclass.pbentry()
414
415 for k in entry:
416
417 if k=='numbertypes' or k=='secrets':
418 continue
419 if k=='ringtone':
420
421 continue
422 elif k=='wallpaper':
423
424 continue
425 elif k=='numbers':
426
427 for numberindex in range(self.protocolclass.NUMPHONENUMBERS):
428 enpn=self.protocolclass.phonenumber()
429
430 e.numbers.append(enpn)
431 for i in range(len(entry[k])):
432 numberindex=entry['numbertypes'][i]
433 e.numbers[numberindex].number=entry[k][i]
434 e.numbers[numberindex].secret=entry['secrets'][i]
435 continue
436
437 setattr(e, k, entry[k])
438 e.ringtone=self.protocolclass.DEFAULT_RINGTONE
439 e.wallpaper=self.protocolclass.DEFAULT_WALLPAPER
440 return e
441
483
485 entry['repeat']=None
486 entry['changeserial']=1
487 entry['snoozedelay']=0
488 entry['daybitmap']=0
489 entry['ringtone']=0
490
492 """ Optimize and expand calendar data suitable for phone download
493 """
494
495
496 r={}
497 rp=[]
498 today=datetime.date.today()
499 last_date=today
500 if __debug__:
501 print 'original calendar:'
502 for k,e in dict.items():
503 if __debug__:
504 print e.description,':',e.start
505 sd=datetime.date(*e.start[:3])
506 ed=datetime.date(*e.end[:3])
507 if ed>last_date:
508 last_date=ed
509 if e.repeat is None:
510 if sd>=today:
511 r.setdefault(e.start[:3], []).append(Samsung_Calendar(e))
512 else:
513 if ed>=today:
514 rp.append(e)
515
516 delta_1=datetime.timedelta(1)
517 for n in rp:
518 current_date=today
519 end_date=datetime.date(*n.end[:3])
520 cnt=0
521 while current_date<=end_date:
522 if n.is_active(current_date.year, current_date.month,
523 current_date.day):
524 cd_l=(current_date.year, current_date.month,
525 current_date.day)
526 r.setdefault(cd_l, []).append(\
527 Samsung_Calendar(n, cd_l))
528 cnt+=1
529 if cnt>self.protocolclass.NUMCALENDAREVENTS:
530
531 break
532 current_date+=delta_1
533
534 res=[]
535 keys=r.keys()
536
537 keys.sort()
538 for k in keys:
539
540 r[k].sort()
541
542 if len(r[k])>self._cal_max_events_per_day:
543 res+=r[k][:self._cal_max_events_per_day]
544 else:
545 res+=r[k]
546
547 if len(res)>self.protocolclass.NUMCALENDAREVENTS:
548 res=res[:self.protocolclass.NUMCALENDAREVENTS]
549 return res
550
552
553 self.log("Sending calendar entries")
554
555 cal=self.process_calendar(dict['calendar'])
556
557 if __debug__:
558 print 'processed calendar: ', len(cal), ' items'
559 for c in cal:
560 print c.description,':', c.start
561
562 self.setmode(self.MODEPHONEBOOK)
563 self.log("Saving calendar entries")
564 cal_cnt=0
565 req=self.protocolclass.eventupdaterequest()
566 l = self.protocolclass.NUMCALENDAREVENTS
567 for c in cal:
568
569
570
571
572 req.slot=cal_cnt
573
574
575
576 req.start=list(c.start)+[0]
577
578
579 if self.__cal_end_datetime_value is None:
580
581 req.end=list(c.end)+[0]
582
583 else:
584
585 req.end=req.start
586
587
588 req.timestamp=list(time.localtime(time.time())[0:6])
589
590
591 req.alarm=c.alarm
592
593
594
595 name=c.desc_loc
596 if len(name)>self.__cal_max_name_len:
597 name=name[:self.__cal_max_name_len]
598 req.eventname=name
599
600
601 self.progress(cal_cnt+1, l, "Updating "+name)
602 self.sendpbcommand(req,self.protocolclass.eventupdateresponse)
603 cal_cnt += 1
604
605
606 self.log('Deleting unused entries')
607 for k in range(cal_cnt, l):
608 self.progress(k, l, "Deleting entry %d" % k)
609 reqerase=self.protocolclass.eventsloterase()
610 reqerase.slot=k
611 self.sendpbcommand(reqerase, self.protocolclass.eventupdateresponse)
612 self.setmode(self.MODEMODEM)
613
614 return dict
615
641
643 self.setmode(self.MODEPHONEBOOK)
644 todos=dict.get('todo', {})
645
646 todos_len=len(todos)
647 l=self.protocolclass.NUMTODOENTRIES
648 if todos_len > l:
649 self.log("The number of Todo entries (%d) exceeded the mamximum (%d)" % (cal_len, l))
650 self.setmode(self.MODEPHONEBOOK)
651 self.log("Saving todo entries")
652 todo_cnt=0
653 req=self.protocolclass.todoupdaterequest()
654 for k in todos:
655 todo=todos[k]
656 print todo.__doc__
657 if todo_cnt >= l:
658 break
659
660 req.slot=todo_cnt
661 if todo.priority is not None and todo.priority<5:
662 req.priority=1
663 else:
664 req.priority=0
665
666 dd=todo.due_date
667 req.duedate=(int(dd[:4]),int(dd[4:6]),int(dd[6:10]),0,0,0)
668 req.timestamp=list(time.localtime(time.time())[0:6])
669 req.subject=todo.summary
670 self.sendpbcommand(req,self.protocolclass.todoupdateresponse)
671 todo_cnt += 1
672
673 req=self.protocolclass.todoerase()
674 for slot in range(todo_cnt, self.protocolclass.NUMTODOENTRIES):
675 req.slot=slot
676 self.sendpbcommand(req,self.protocolclass.todoupdateresponse)
677
694
722
723
731 getphoneinfo=getbasicinfo
732 getcallhistory=None
733
735
736 BP_Calendar_Version=3
737
738 usbids=( ( 0x04e8, 0x6601, 1),
739 )
740
741
742 deviceclasses=("modem","serial")
743 WALLPAPER_WIDTH=128
744 WALLPAPER_HEIGHT=118
745 OVERSIZE_PERCENTAGE=100
746 MAX_WALLPAPER_BASENAME_LENGTH=19
747 WALLPAPER_FILENAME_CHARS="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .`~!@#$%^&()-_=+[{]};\'"
748 WALLPAPER_CONVERT_FORMAT="png"
749
750 MAX_RINGTONE_BASENAME_LENGTH=19
751 RINGTONE_FILENAME_CHARS="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .`~!@#$%^&()-_=+[{]};\'"
752
753 _supportedsyncs=()
754
757
763
764
806
808 """Converts the data to what will be used by the phone
809
810 @param data: contains the dict returned by getfundamentals
811 as well as where the results go"""
812
813 self.normalisegroups(helper, data)
814 results={}
815
816
817 pb=data['phonebook']
818
819 slots=[ (helper.getserial(pb[pbentry].get("serials", []), self.serialsname, data['uniqueserial'], "slot", None), pbentry)
820 for pbentry in pb]
821 slots.sort()
822
823 newones=[(pbentry,slot) for slot,pbentry in slots if slot is None]
824 existing=[(pbentry,slot) for slot,pbentry in slots if slot is not None]
825
826 uslotsused={}
827
828 tempslot=0
829 for pbentry,slot in existing+newones:
830
831 if len(results)==self.protocolclass.NUMPHONEBOOKENTRIES:
832 break
833
834 try:
835
836 e={}
837
838 entry=data['phonebook'][pbentry]
839
840 secret=helper.getflag(entry.get('flags', []), 'secret', False)
841 if secret:
842 secret=1
843 else:
844 secret=0
845
846
847 e['name']=helper.getfullname(entry.get('names', []),1,1,20)[0]
848
849 cat=helper.makeone(helper.getcategory(entry.get('categories',[]),0,1,12), None)
850 if cat is None:
851 e['group']=self.protocolclass.NUMGROUPS
852 else:
853 key,value=self._getgroup(cat, data['groups'])
854 if key is not None:
855 e['group']=key
856 else:
857
858 e['group']=self.protocolclass.NUMGROUPS
859
860
861 e['email']=helper.makeone(helper.getemails(entry.get('emails', []), 0,1,32), "")
862
863 e['url']=helper.makeone(helper.geturls(entry.get('urls', []), 0,1,32), "")
864
865
866
867 minnumbers=1
868 numbers=helper.getnumbers(entry.get('numbers', []),minnumbers,self.protocolclass.NUMPHONENUMBERS)
869 e['numbertypes']=[]
870 e['numbers']=[]
871 e['secrets']=[]
872 unusednumbers=[]
873 typesused={}
874 defaulttypenum=0
875 for num in numbers:
876 typename=num['type']
877 if typesused.has_key(typename):
878 unusednumbers.append(num)
879 continue
880 typesused[typename]=1
881 for typenum,tnsearch in enumerate(self.numbertypetab):
882 if typename==tnsearch:
883 if defaulttypenum==0:
884 defaulttypenum=typenum
885 number=self.phonize(num['number'])
886 if len(number)>self.protocolclass.MAXNUMBERLEN:
887
888 number=number[:self.protocolclass.MAXNUMBERLEN]
889 e['numbers'].append(number)
890 if(num.has_key('speeddial')):
891
892
893
894 e['speeddial']=typenum
895 tryuslot = num['speeddial']
896 e['numbertypes'].append(typenum)
897 e['secrets'].append(secret)
898
899 break
900
901
902
903 if e.has_key('speeddial'):
904 if tryuslot>=1 and tryuslot<=self.protocolclass.NUMPHONEBOOKENTRIES and not uslotsused.has_key(tryuslot):
905 uslotsused[tryuslot]=1
906 e['uslot']=tryuslot
907 else:
908 e['speeddial']=defaulttypenum
909
910 e['ringtone']=helper.getringtone(entry.get('ringtones', []), 'call', None)
911 e['wallpaper']=helper.getwallpaper(entry.get('wallpapers', []), 'call', None)
912
913
914 if slot is None or slot<1 or slot>self.protocolclass.NUMPHONEBOOKENTRIES or slot in results:
915 for i in range(1,100000):
916 if i not in results:
917 slot=i
918 break
919
920 e['slot']=slot
921
922 e['timestamp']=list(time.localtime(time.time())[0:6])
923
924 results[slot]=e
925 except helper.ConversionFailed:
926 continue
927
928
929
930 tryuslot=1
931 for slot in results.keys():
932
933 e=results[slot]
934 if not e.has_key('uslot'):
935 while tryuslot<self.protocolclass.NUMPHONEBOOKENTRIES and uslotsused.has_key(tryuslot):
936 tryuslot += 1
937 uslotsused[tryuslot]=1
938 e['uslot'] = tryuslot
939 results[slot] = e
940
941 data['phonebook']=results
942 return data
943
945 """Convert the phone number into something the phone understands
946 All digits, P, T, * and # are kept, everything else is removed"""
947
948 return re.sub("[^0-9PT#*]", "", str)[:self.protocolclass.MAXNUMBERLEN]
949
1009