Package phones ::
Module com_sanyo
|
|
1
2
3
4
5
6
7
8
9
10 """Phonebook conversations with Sanyo phones"""
11
12
13 import re
14 import time
15 import cStringIO
16 import sha
17 import datetime
18
19
20 import com_brew
21 import com_phone
22 import p_sanyo
23 import prototypes
24 import common
25 import conversions
26 import bpcalendar
27 import call_history
28 import sms
29 import todo
30 import helpids
31
32 numbertypetab=( 'home', 'office', 'cell', 'pager',
33 'data', 'fax', 'none' )
34
37 if str is None:
38 str="Sanyo Packet Error 0x%02x" % (errnum,)
39 Exception.__init__(self, str)
40 self.errnum=errnum
41
43 "Talk to a Sanyo Sprint Phone such as SCP-4900, SCP-5300, or SCP-8100"
44
45
46
47 _sanyoepochtounix=315532800+432000;
48
49 pbterminator="\x7e"
50 MODEPHONEBOOK="modephonebook"
51
52 calendar_defaultringtone=0
53 calendar_defaultcaringtone=0
54 calendar_voicenumber=0
55 phonebook_voicenumber=0
56
59
64
81
139
162
165
168
195
219
220 - def sendpbcommand(self, request, responseclass, callsetmode=True, writemode=False, numsendretry=0, returnerror=False):
221 if writemode:
222 numretry=3
223 else:
224 numretry=0
225
226 if callsetmode:
227 self.setmode(self.MODEPHONEBOOK)
228 buffer=prototypes.buffer()
229
230 request.writetobuffer(buffer, logtitle="Sanyo phonebook request")
231 data=buffer.getvalue()
232 firsttwo=data[:2]
233 data=common.pppescape(data+common.crcs(data))+common.pppterminator
234 isendretry=numsendretry
235 while isendretry>=0:
236 try:
237 rdata=self.comm.writethenreaduntil(data, False, common.pppterminator, logreaduntilsuccess=False, numfailures=numretry)
238 break
239 except com_phone.modeignoreerrortypes:
240 if isendretry>0:
241 self.log("Resending request packet...")
242 time.sleep(0.3)
243 else:
244 self.comm.success=False
245 self.mode=self.MODENONE
246 self.raisecommsdnaexception("manipulating the phonebook")
247 isendretry-=1
248
249 self.comm.success=True
250
251 origdata=rdata
252
253
254
255
256 d=rdata.rfind(common.pppterminator,0,-1)
257 if d>=0:
258 self.log("Multiple Sanyo packets in data - taking last one starting at "+`d+1`)
259 self.logdata("Original Sanyo data", origdata, None)
260 rdata=rdata[d+1:]
261
262
263 data=common.pppunescape(rdata)
264
265
266
267
268
269 d=data.find(firsttwo)
270 crc=data[-3:-1]
271 crcok=False
272 for i in range(0,d+1):
273 trydata=data[i:-3]
274 if common.crcs(trydata)==crc:
275 crcok=True
276 break
277
278 if not crcok:
279 self.logdata("first two",firsttwo, None)
280 self.logdata("Original Sanyo data", origdata, None)
281 self.logdata("Working on Sanyo data", data, None)
282 raise common.CommsDataCorruption("Sanyo packet failed CRC check", self.desc)
283
284 res=responseclass()
285 if d>0:
286 if d==i:
287 self.log("Junk at beginning of Sanyo packet, data at "+`d`)
288 self.logdata("Original Sanyo data", origdata, None)
289 self.logdata("Working on Sanyo data", data, None)
290 else:
291 if returnerror:
292 res=self.protocolclass.sanyoerror()
293 else:
294 self.log("Sanyo Error code "+`ord(data[0])`)
295 self.logdata("sanyo phonebook response", data, None)
296 raise SanyoCommandException(ord(data[0]))
297
298 data=trydata
299
300
301 buffer=prototypes.buffer(data)
302 res.readfrombuffer(buffer, logtitle="sanyo phonebook response")
303 return res
304
306 """Gets information fundamental to interopating with the phone and UI."""
307
308
309 print "HASRINGPICBUF=",self.protocolclass.HASRINGPICBUF
310 self.log("Retrieving fundamental phone information")
311 self.log("Phone serial number")
312 results['uniqueserial']=sha.new(self.getfilecontents("nvm/$SYS.ESN")).hexdigest()
313
314
315
316 self.getmediaindices(results)
317 self.log("Fundamentals retrieved")
318 return results
319
321 "Sanyo sort order. Case insensitive, letters first"
322 x=a[1]
323 y=b[1]
324
325 if(x[0:1].isalpha() and not y[0:1].isalpha()):
326 return -1
327 if(y[0:1].isalpha() and not x[0:1].isalpha()):
328 return 1
329 return cmp(x.lower(), y.lower())
330
370
390
392 pbook={}
393
394
395 sortstuff = self.getsanyobuffer(self.protocolclass.pbsortbuffer)
396
397
398 if self.protocolclass.HASRINGPICBUF:
399 ringpic = self.getsanyobuffer(self.protocolclass.ringerpicbuffer)
400
401 speedslot=[]
402 speedtype=[]
403 for i in range(self.protocolclass._NUMSPEEDDIALS):
404 speedslot.append(sortstuff.speeddialindex[i].pbslotandtype & 0xfff)
405 numtype=(sortstuff.speeddialindex[i].pbslotandtype>>12)-1
406 if(numtype >= 0 and numtype <= len(self.numbertypetab)):
407 speedtype.append(self.numbertypetab[numtype])
408 else:
409 speedtype.append("")
410
411 numentries=sortstuff.slotsused
412 self.log("There are %d entries" % (numentries,))
413
414 count = 0
415 numcount = 0
416 numemail = 0
417 numurl = 0
418 res=self.protocolclass.phonebookentry()
419 usedefaultnum = 'defaultnum' in res.getfields()
420 print "usedefaultnum =",usedefaultnum
421
422 req=self.protocolclass.phonebookslotrequest()
423 for i in range(0, self.protocolclass._NUMPBSLOTS):
424 if sortstuff.usedflags[i].used:
425
426 req.slot = i
427 res=self.sendpbcommand(req, self.protocolclass.phonebookslotresponse)
428 self.log("Read entry "+`i`+" - "+res.entry.name)
429
430 entry=self.extractphonebookentry(res.entry, result)
431
432 for j in range(len(speedslot)):
433 if(speedslot[j]==req.slot):
434 for k in range(len(entry['numbers'])):
435 if(entry['numbers'][k]['type']==speedtype[j]):
436 entry['numbers'][k]['speeddial']=j+2
437 break
438
439 if self.protocolclass.HASRINGPICBUF:
440
441 if ringpic.ringtones[i].ringtone>0:
442 print res.entry.name,ringpic.ringtones[i].ringtone
443 try:
444 tone=result['ringtone-index'][ringpic.ringtones[i].ringtone]['name']
445 except:
446 tone=self.serialsname+"Index_"+`ringpic.ringtones[i].ringtone`
447 entry['ringtones']=[{'ringtone': tone, 'use': 'call'}]
448
449
450 if ringpic.wallpapers[i].wallpaper>0:
451 try:
452 paper=result['wallpaper-index'][ringpic.wallpapers[i].wallpaper]['name']
453 except:
454 paper=self.serialsname+"Index_"+`ringpic.wallpapers[i].wallpaper`
455 entry['wallpapers']=[{'wallpaper': paper, 'use': 'call'}]
456
457
458 if usedefaultnum:
459 firsttype=res.entry.defaultnum-1
460 if firsttype < len(self.numbertypetab):
461 defaulttype=self.numbertypetab[firsttype]
462 k=0
463 for j in range(len(entry['numbers'])):
464 if entry['numbers'][j]['type'] == defaulttype:
465 k=j
466 break
467 if k>0:
468 exchange=entry['numbers'][k]
469 for kk in range(k,0,-1):
470 entry['numbers'][kk]=entry['numbers'][kk-1]
471 entry['numbers'][0]=exchange
472
473 pbook[count]=entry
474 self.progress(count, numentries, res.entry.name)
475 count+=1
476 numcount+=len(entry['numbers'])
477 if entry.has_key('emails'):
478 numemail+=len(entry['emails'])
479 if entry.has_key('urls'):
480 numurl+=len(entry['urls'])
481
482 self.progress(numentries, numentries, "Phone book read completed")
483 self.log("Phone contains "+`count`+" contacts, "+`numcount`+" phone numbers, "+`numemail`+" Emails, "+`numurl`+" URLs")
484 result['phonebook']=pbook
485 return pbook
486
488 """Return a phonebook entry in BitPim format"""
489 res={}
490
491 res['serials']=[ {'sourcetype': self.serialsname, 'serial1': entry.slot, 'serial2': entry.slotdup,
492 'sourceuniqueid': fundamentals['uniqueserial']} ]
493
494 res['names']=[ {'full': entry.name} ]
495
496 if len(entry.email):
497 res['emails']=[ {'email': entry.email} ]
498
499 if len(entry.url):
500 res['urls']=[ {'url': entry.url} ]
501
502 res['flags']=[ {'secret': entry.secret } ]
503
504 res['numbers']=[]
505 numberindex = 0
506 for type in self.numbertypetab:
507 if len(entry.numbers[numberindex].number):
508 res['numbers'].append({'number': entry.numbers[numberindex].number, 'type': type })
509
510 numberindex+=1
511 return res
512
526
527 - def makeentry(self, entry, dict):
528
529
530
531 e=self.protocolclass.phonebookentry()
532
533 for k in entry:
534
535 if k=='ringtones' or k=='wallpapers' or k=='numbertypes':
536 continue
537 if k=='numbers':
538 for numberindex in range(self.protocolclass.NUMPHONENUMBERS):
539 enpn=self.protocolclass.phonenumber()
540 e.numbers.append(enpn)
541
542 for i in range(len(entry[k])):
543 numberindex=entry['numbertypes'][i]
544 e.numbers[numberindex].number=entry[k][i]
545 e.numbers[numberindex].number_len=len(e.numbers[numberindex].number)
546 continue
547
548 setattr(e,k,entry[k])
549 return e
550
552 """Loop until phone status indicates ready to write"""
553 for i in range(100):
554 req=self.protocolclass.statusrequest()
555 res=self.sendpbcommand(req, self.protocolclass.statusresponse)
556
557 if res.ready==res.readyvalue:
558 return
559 time.sleep(0.1)
560
561 self.log("Phone did not transfer to ready to write state")
562 self.log("Waiting a bit longer and trying anyway")
563 return
564
566
567
568
569
570
571
572
573
574 newphonebook={}
575 self.mode=self.MODENONE
576 self.setmode(self.MODEBREW)
577 self.setmode(self.MODEPHONEBOOK)
578
579
580
581
582 sortstuff=self.protocolclass.pbsortbuffer()
583 ringpic=self.protocolclass.ringerpicbuffer()
584 callerid=self.protocolclass.calleridbuffer()
585
586 res=self.protocolclass.phonebookentry()
587 usedefaultnum = 'defaultnum' in res.getfields()
588
589 for i in range(self.protocolclass._NUMPBSLOTS):
590 sortstuff.usedflags.append(0)
591 sortstuff.firsttypes.append(0)
592 sortstuff.sortorder.append(0xffff)
593 sortstuff.sortorder2.append(0xffff)
594 sortstuff.emails.append(0xffff)
595 sortstuff.urls.append(0xffff)
596 ringpic.ringtones.append(0)
597 ringpic.wallpapers.append(0)
598
599 for i in range(self.protocolclass._NUMSPEEDDIALS):
600 sortstuff.speeddialindex.append(0xffff)
601
602 for i in range(self.protocolclass._NUMLONGNUMBERS):
603 sortstuff.longnumbersindex.append(0xffff)
604
605
606
607
608
609 namemap=[]
610 emailmap=[]
611 urlmap=[]
612
613 callerid.numentries=0
614
615 pbook=data['phonephonebook']
616 self.log("Putting phone into write mode")
617 req=self.protocolclass.beginendupdaterequest()
618 req.beginend=1
619 res=self.sendpbcommand(req, self.protocolclass.beginendupdateresponse, writemode=True)
620
621 self.writewait()
622
623 keys=pbook.keys()
624 keys.sort()
625 sortstuff.slotsused=len(keys)
626 sortstuff.numemail=0
627 sortstuff.numurl=0
628
629 progresscur=0
630 progressmax=len(keys)
631 self.log("Writing %d entries to phone" % (len(keys),))
632 nlongphonenumbers=0
633 nonumbercount=0
634 for ikey in keys:
635 ii=pbook[ikey]
636 slot=ii['slot']
637
638 progresscur+=1
639 self.progress(progresscur, progressmax, "Writing "+ii['name'])
640 self.log("Writing entry "+`slot`+" - "+ii['name'])
641 entry=self.makeentry(ii, data)
642 if not usedefaultnum:
643 delattr(entry,'defaultnum')
644 req=self.protocolclass.phonebookslotupdaterequest()
645 req.entry=entry
646 res=self.sendpbcommand(req, self.protocolclass.phonebookslotresponse, writemode=True)
647
648 entry=self.extractphonebookentry(entry, data)
649 entry['ringtones']=[{'ringtone': ii['ringtone'], 'use': 'call'}]
650 entry['wallpapers']=[{'wallpaper': ii['wallpaper'], 'use': 'call'}]
651
652
653
654 sortstuff.usedflags[slot].used=1
655 if(len(ii['numbers'])):
656 sortstuff.firsttypes[slot].firsttype=min(ii['numbertypes'])+1
657 else:
658 if(len(ii['email'])):
659 sortstuff.firsttypes[slot].firsttype=8
660 nonumbercount+=1
661 elif(len(ii['url'])):
662 sortstuff.firsttypes[slot].firsttype=9
663 nonumbercount+=1
664 else:
665 sortstuff.firsttypes[slot].firsttype=0
666
667
668
669
670
671
672
673 for i in range(len(ii['numbers'])):
674 nindex=ii['numbertypes'][i]
675 speeddial=ii['speeddials'][i]
676 code=slot+((nindex+1)<<12)
677 if(speeddial>=2 and speeddial<=self.protocolclass._NUMSPEEDDIALS+1):
678 sortstuff.speeddialindex[speeddial-2]=code
679 for k in range(len(entry['numbers'])):
680 if(entry['numbers'][k]['type']==nindex):
681 entry['numbers'][k]['speeddial']=speeddial
682 break
683 if(callerid.numentries<callerid.maxentries):
684 phonenumber=ii['numbers'][i]
685 cidentry=self.makecidentry(phonenumber,slot,nindex)
686 callerid.items.append(cidentry)
687 callerid.numentries+=1
688 if(len(phonenumber)>self.protocolclass._LONGPHONENUMBERLEN):
689 if(nlongphonenumbers<self.protocolclass._NUMLONGNUMBERS):
690 sortstuff.longnumbersindex[nlongphonenumbers].pbslotandtype=code
691
692 namemap.append((slot,ii['name']))
693 if(len(ii['email'])):
694 emailmap.append((slot,ii['email']))
695 sortstuff.numemail+=1
696 if(len(ii['url'])):
697 urlmap.append((slot,ii['url']))
698 sortstuff.numurl+=1
699
700 ringpic.ringtones[slot].ringtone=self._findmediaindex(data['ringtone-index'], ii['ringtone'],ii['name'],'ringtone')
701 ringpic.wallpapers[slot].wallpaper=self._findmediaindex(data['wallpaper-index'], ii['wallpaper'],ii['name'],'wallpaper')
702
703 newphonebook[slot]=entry
704
705 sortstuff.slotsused2=len(keys)-nonumbercount
706
707
708
709 i=0
710 j=0
711 sortstuff.pbfirstletters=""
712 namemap.sort(self.sanyosort)
713 for (slot, name) in namemap:
714 sortstuff.sortorder[i].pbslot=slot
715 if sortstuff.firsttypes[slot].firsttype<=7:
716 sortstuff.sortorder2[j].pbslot=slot
717 j+=1
718 if name:
719 sortstuff.pbfirstletters+=name[0]
720 else:
721 sortstuff.pbfirstletters+=chr(0)
722 i+=1
723
724 i=0
725 sortstuff.emailfirstletters=""
726 emailmap.sort(self.sanyosort)
727 for (slot, email) in emailmap:
728 sortstuff.emails[i].pbslot=slot
729 sortstuff.emailfirstletters+=email[0]
730 i+=1
731
732 i=0
733 sortstuff.urlfirstletters=""
734 urlmap.sort(self.sanyosort)
735 for (slot, url) in urlmap:
736 sortstuff.urls[i].pbslot=slot
737 sortstuff.urlfirstletters+=url[0]
738 i+=1
739
740
741 self.sendsanyobuffer(sortstuff)
742
743 if self.protocolclass.HASRINGPICBUF:
744 self.sendsanyobuffer(ringpic)
745
746 self.sendsanyobuffer(callerid)
747
748 time.sleep(1.0)
749
750 data['phonebook']=newphonebook
751 del data['phonephonebook']
752 data['rebootphone'] = 1
753
754 - def makecidentry(self, number, slot, nindex):
755 "Prepare entry for caller ID lookup buffer"
756
757 numstripped=re.sub("[^0-9PT#*]", "", number)
758 numonly=re.sub("^(\\d*).*$", "\\1", numstripped)
759
760 cidentry=self.protocolclass.calleridentry()
761 cidentry.pbslotandtype=slot+((nindex+1)<<12)
762 cidentry.actualnumberlen=len(numonly)
763 cidentry.numberfragment=numonly[-10:]
764
765 return cidentry
766
767
769
770 return self.savemedia('wallpapers', 'wallpaper-index', 'images', results, merge)
771
772
773
774
776 return self.savemedia('ringtone', 'ringtone-index', 'ringers', results, merge)
777
852
853
854
855
856
857
858
859
860
861
862
863
864
866 start=time.time()
867 self.log("Writing file '"+name+"' bytes "+`len(contents)`)
868 desc="Writing "+name
869
870
871
872 try:
873 name=name[:name.index(".mid")]
874 except:
875 try:
876 name=name[:name.index(".png")]
877 except:
878 pass
879
880
881 if hasattr(self.protocolclass,"sanyomediathingyrequest"):
882 req=self.protocolclass.sanyomediathingyrequest()
883 req.faset = 0x10
884 res=self.sendpbcommand(req, self.protocolclass.sanyomediathingyresponse)
885 time.sleep(10.0)
886 req.faset = 0x13
887 res=self.sendpbcommand(req, self.protocolclass.sanyomediathingyresponse)
888
889 req=self.protocolclass.sanyosendfilename()
890 req.filename=name
891 res=self.sendpbcommand(req, self.protocolclass.sanyosendfileresponse, returnerror=True)
892 if 'errorcode' in res.getfields():
893 if res.errorcode==0x65:
894 self.alert("Please put your phone into PC Sync Mode", False)
895 else:
896 raise SanyoCommandException(res.errorcode)
897
898 waitcount=120
899 while waitcount>0:
900 time.sleep(1.0)
901 res=self.sendpbcommand(req, self.protocolclass.sanyosendfileresponse, returnerror=True)
902 if not 'errorcode' in res.getfields():
903 break
904 waitcount-=1
905 if waitcount==0:
906 raise SanyoCommandException(res.errorcode)
907
908 req=self.protocolclass.sanyosendfilesize()
909 req.filesize=len(contents)
910 self.sendpbcommand(req, self.protocolclass.sanyosendfileresponse)
911
912 req=self.protocolclass.sanyosendfilefragment()
913 packetsize=req.payloadsize
914
915
916 offset=0
917 count=0
918 numblocks=len(contents)/packetsize+1
919 for offset in range(0, len(contents), packetsize):
920 count+=1
921 if count % 5==0:
922 self.progress(count,numblocks,desc)
923 req.header.command=offset
924 req.data=contents[offset:min(offset+packetsize,len(contents))]
925
926 self.sendpbcommand(req, self.protocolclass.sanyosendfileresponse, writemode=True, returnerror=True)
927 if 'errorcode' in res.getfields():
928 self.log(name+" not written due to error code "+`res.errorcode`)
929 return False
930
931 req=self.protocolclass.sanyosendfileterminator()
932 try:
933 res=self.sendpbcommand(req, self.protocolclass.sanyosendfileresponse, writemode=True, returnerror=True)
934
935 if 'errorcode' in res.getfields():
936 self.log(name+" not written due to error code "+`res.errorcode`)
937 return False
938 except:
939 self.log("Exception on writing terminator for file "+name)
940 self.log("Continuing...")
941
942 end=time.time()
943 if end-start>3:
944 self.log("Wrote "+`len(contents)`+" bytes at "+`int(len(contents)/(end-start))`+" bytes/second")
945 return True
946
947
949
950
951
952
953
954
955
956 calres={}
957
958 progressmax=self.protocolclass._NUMEVENTSLOTS+self.protocolclass._NUMCALLALARMSLOTS
959 req=self.protocolclass.eventrequest()
960 count=0
961
962 try:
963 reqflag=self.protocolclass.eventslotinuserequest()
964 except:
965 reqflag=0
966
967 for i in range(0, self.protocolclass._NUMEVENTSLOTS):
968 self.progress(i,progressmax,"Events")
969 if reqflag:
970 reqflag.slot=i
971 resflag=self.sendpbcommand(reqflag, self.protocolclass.eventslotinuseresponse)
972 if not resflag.flag:
973 continue
974 req.slot = i
975 res=self.sendpbcommand(req, self.protocolclass.eventresponse)
976 if not reqflag:
977 if not res.entry.flag:
978 continue
979 self.log("Read calendar event "+`i`+" - "+res.entry.eventname+", alarm ID "+`res.entry.ringtone`)
980 entry=bpcalendar.CalendarEntry()
981
982 entry.changeserial=res.entry.serial
983 entry.description=res.entry.eventname
984 entry.location=res.entry.location
985 starttime=res.entry.start
986 entry.start=self.decodedate(starttime)
987 entry.end=self.decodedate(res.entry.end)
988 repeat=self._calrepeatvalues[res.entry.period]
989 entry.repeat = self.makerepeat(repeat,entry.start)
990
991 if res.entry.alarm==0xffffffff:
992 entry.alarm=res.entry.alarmdiff/60
993 else:
994 alarmtime=res.entry.alarm
995 entry.alarm=(starttime-alarmtime)/60
996 ringtone=res.entry.ringtone
997 print "ringtone=",ringtone
998 if self.calendar_voicenumber and ringtone == self.calendar_voicenumber:
999 ringtone=self.phonebook_voicenumber
1000 if ringtone in self.calendar_tonerange:
1001 print "Adjusting ringtone by",-self.calendar_toneoffset
1002 ringtone-=self.calendar_toneoffset
1003 print "ringtone=",ringtone
1004 if ringtone!=self.calendar_defaultringtone:
1005 if result['ringtone-index'].has_key(ringtone):
1006 entry.ringtone=result['ringtone-index'][ringtone]['name']
1007
1008 entry.snoozedelay=0
1009 calres[entry.id]=entry
1010 count+=1
1011
1012 req=self.protocolclass.callalarmrequest()
1013 for i in range(0, self.protocolclass._NUMCALLALARMSLOTS):
1014 self.progress(self.protocolclass._NUMEVENTSLOTS,progressmax,"Call Alarms")
1015 req.slot=i
1016 res=self.sendpbcommand(req, self.protocolclass.callalarmresponse)
1017 if res.entry.flag and res.entry.date:
1018 self.log("Read call alarm entry "+`i`+" - "+res.entry.phonenum+", alarm ID "+`res.entry.ringtone`)
1019 entry=bpcalendar.CalendarEntry()
1020
1021 entry.changeserial=res.entry.serial
1022 entry.description=res.entry.phonenum
1023 starttime=res.entry.date
1024 entry.start=self.decodedate(starttime)
1025 entry.end=entry.start
1026 repeat=self._calrepeatvalues[res.entry.period]
1027 entry.repeat = self.makerepeat(repeat,entry.start)
1028 entry.alarm=0
1029 if res.entry.ringtone!=self.calendar_defaultcaringtone:
1030 entry.ringtone=result['ringtone-index'][res.entry.ringtone]['name']
1031 entry.snoozedelay=0
1032 calres[entry.id]=entry
1033 count+=1
1034
1035 result['calendar']=calres
1036 return result
1037
1060
1062
1063
1064
1065
1066
1067
1068
1069
1070 cal=dict['calendar']
1071 newcal={}
1072 keys=cal.keys()
1073
1074
1075
1076 zonedif=time.mktime(time.gmtime(0))-time.mktime(time.localtime(0))
1077 save_tonerange = xrange(self.calendar_tonerange[0]-self.calendar_toneoffset,self.calendar_tonerange[-1]-self.calendar_toneoffset+1)
1078
1079 try:
1080 reqflag=self.protocolclass.eventslotinuseupdaterequest()
1081 except:
1082 reqflag=0
1083
1084 eventslot=0
1085 callslot=0
1086 progressmax=self.protocolclass._NUMEVENTSLOTS+self.protocolclass._NUMCALLALARMSLOTS
1087 for k in keys:
1088 entry=cal[k]
1089
1090 descloc=entry.description
1091 self.progress(eventslot+callslot, progressmax, "Writing "+descloc)
1092
1093 rp=entry.repeat
1094 if rp is None:
1095 repeat=0
1096 else:
1097 repeatname=None
1098 if rp.repeat_type==rp.daily:
1099 repeatname='daily'
1100 elif rp.repeat_type==rp.weekly:
1101 repeatname='weekly'
1102 elif rp.repeat_type==rp.monthly:
1103 repeatname='monthly'
1104 elif rp.repeat_type==rp.yearly:
1105 repeatname='yearly'
1106 for k,v in self._calrepeatvalues.items():
1107 if repeatname==v:
1108 repeat=k
1109 break
1110 if repeatname is None:
1111 self.log(descloc+": Repeat type "+`entry.repeat`+" not valid for this phone")
1112 repeat=0
1113
1114 phonenum=re.sub("\-","",descloc)
1115 now=time.mktime(time.localtime(time.time()))-zonedif
1116 if(phonenum.isdigit()):
1117 self.log("Write calendar call alarm slot "+`callslot`+ " - "+descloc)
1118 e=self.protocolclass.callalarmentry()
1119 e.slot=callslot
1120 e.phonenum=phonenum
1121 e.phonenum_len=len(e.phonenum)
1122
1123
1124 timearray=list(entry.start)+[0,0,0,0]
1125 starttimelocal=time.mktime(timearray)-zonedif
1126 if(starttimelocal<now and repeat==0):
1127 e.flag=2
1128 else:
1129 e.flag=1
1130 e.date=starttimelocal-self._sanyoepochtounix
1131 e.datedup=e.date
1132 e.phonenumbertype=0
1133 e.phonenumberslot=0
1134 e.name=""
1135
1136 e.name_len=len(e.name)
1137
1138 print "Setting ringtone "+`e.ringtone`
1139
1140 req=self.protocolclass.callalarmupdaterequest()
1141 callslot+=1
1142 respc=self.protocolclass.callalarmresponse
1143 else:
1144 self.log("Write calendar event slot "+`eventslot`+ " - "+descloc)
1145 e=self.protocolclass.evententry()
1146 e.slot=eventslot
1147
1148 e.eventname=descloc
1149 e.eventname_len=len(e.eventname)
1150 e.location=entry.location
1151 e.location_len=len(e.location)
1152
1153 timearray=list(entry.start)+[0,0,0,0]
1154 starttimelocal=time.mktime(timearray)-zonedif
1155 e.start=starttimelocal-self._sanyoepochtounix
1156
1157 try:
1158 timearray=list(entry.end)+[0,0,0,0]
1159 endtimelocal=time.mktime(timearray)-zonedif
1160 e.end=endtimelocal-self._sanyoepochtounix
1161 except:
1162 e.end=e.start+60
1163
1164 alarmdiff=entry.alarm
1165 if alarmdiff<0:
1166 alarmdiff=0
1167 alarmdiff=max(alarmdiff,0)*60
1168 e.alarmdiff=alarmdiff
1169 e.alarm=starttimelocal-self._sanyoepochtounix-alarmdiff
1170
1171 if reqflag:
1172 reqflag.slot=eventslot
1173 if(e.alarm+self._sanyoepochtounix<now and repeat==0):
1174 reqflag.flag=4
1175 else:
1176 reqflag.flag=1
1177 res=self.sendpbcommand(reqflag, self.protocolclass.eventslotinuseresponse)
1178 else:
1179 if(starttimelocal<now and repeat==0):
1180 e.flag=2
1181 else:
1182 e.flag=1
1183
1184
1185
1186 try:
1187 timearray=list(entry.end)+[0,0,0,0]
1188 endtimelocal=time.mktime(timearray)-zonedif
1189 e.end=endtimelocal-self._sanyoepochtounix
1190 except:
1191 e.end=e.start+60
1192
1193 ringtoneindex=self._findmediaindex(dict['ringtone-index'],entry.ringtone,'Calendar','ringtone')
1194 if ringtoneindex==0:
1195 e.ringtone=self.calendar_defaultringtone
1196 else:
1197 e.ringtone=ringtoneindex
1198 if e.ringtone in save_tonerange:
1199 e.ringtone+=self.calendar_toneoffset
1200 if self.calendar_voicenumber and e.ringtone==self.phonebook_voicenumber:
1201 e.ringtone=self.calendar_voicenumber
1202
1203
1204 print "Setting ringtone "+`e.ringtone`
1205
1206
1207
1208
1209 req=self.protocolclass.eventupdaterequest()
1210 eventslot+=1
1211 respc=self.protocolclass.eventresponse
1212
1213 e.period=repeat
1214 e.dom=entry.start[2]
1215 if entry.id>=0 and entry.id<256:
1216 e.serial=entry.id
1217 else:
1218 e.serial=0
1219 req.entry=e
1220 res=self.sendpbcommand(req, respc, writemode=True)
1221
1222
1223
1224
1225 if reqflag:
1226 req=reqflag
1227 req.flag=0
1228 else:
1229 e=self.protocolclass.evententry()
1230 e.flag=0
1231 e.eventname=""
1232 e.eventname_len=0
1233 e.location=""
1234 e.location_len=0
1235 e.start=0
1236 e.end=0
1237 e.period=0
1238 e.dom=0
1239 e.ringtone=0
1240 e.alarm=0
1241 e.alarmdiff=0
1242 req=self.protocolclass.eventupdaterequest()
1243 req.entry=e
1244
1245 for eventslot in range(eventslot,self.protocolclass._NUMEVENTSLOTS):
1246 self.progress(eventslot+callslot, progressmax, "Writing unused")
1247 self.log("Write calendar event slot "+`eventslot`+ " - Unused")
1248 if reqflag:
1249 req.slot=eventslot
1250 else:
1251 req.entry.slot=eventslot
1252 res=self.sendpbcommand(req, self.protocolclass.eventresponse, writemode=True)
1253
1254 e=self.protocolclass.callalarmentry()
1255 e.flag=0
1256 e.name=""
1257 e.name_len=0
1258 e.phonenum=""
1259 e.phonenum_len=0
1260 e.date=0
1261 e.datedup=0
1262 e.period=0
1263 e.dom=0
1264 e.ringtone=0
1265 e.phonenumbertype=0
1266 e.phonenumberslot=0
1267 req=self.protocolclass.callalarmupdaterequest()
1268 req.entry=e
1269 for callslot in range(callslot,self.protocolclass._NUMCALLALARMSLOTS):
1270 self.progress(eventslot+callslot, progressmax, "Writing unused")
1271 self.log("Write calendar call alarm slot "+`callslot`+ " - Unused")
1272 req.entry.slot=callslot
1273 res=self.sendpbcommand(req, self.protocolclass.callalarmresponse, writemode=True)
1274
1275 self.progress(progressmax, progressmax, "Calendar write done")
1276
1277 dict['rebootphone'] = True
1278 return dict
1279
1280 - def getcallhistory(self, result):
1281 res={}
1282 self._readhistory(self.protocolclass.OUTGOING,'Outgoing',res)
1283 self._readhistory(self.protocolclass.MISSED,'Missed',res)
1284 self._readhistory(self.protocolclass.INCOMING,'Incoming',res)
1285 result['call_history']=res
1286 return result
1287
1288 - def _readhistory(self, type, folder, res):
1289 req=self.protocolclass.historyrequest()
1290 req.type=type
1291 for slot in range(self.protocolclass.NUMCALLHISTORY):
1292 req.slot=slot
1293 call=self.sendpbcommand(req, self.protocolclass.historyresponse)
1294 if call.entry.phonenum=='' and call.entry.name=='':
1295 continue
1296 entry=call_history.CallHistoryEntry()
1297 entry.folder=folder
1298 entry.name=call.entry.name
1299 entry.number=call.entry.phonenum
1300 entry.datetime=((call.entry.date))
1301 res[entry.id]=entry
1302
1304 self.log('Getting Phone Info')
1305 try:
1306 phone_info.append('ESN:', self.get_esn())
1307 phone_info.append('Manufacturer:', 'Sanyo')
1308 req=self.protocolclass.lockcoderequest()
1309 try:
1310 res=self.sendpbcommand(req, self.protocolclass.lockcoderesponse)
1311 phone_info.append('Lock Code:', res.lockcode)
1312 except:
1313 pass
1314
1315 req=self.protocolclass.sanyofirmwarerequest()
1316 res=self.sendpbcommand(req, self.protocolclass.sanyofirmwareresponse)
1317 phone_info.append('Firmware Version:',res.firmware)
1318 if 'prl' in res.getfields():
1319 phone_info.append('PRL:', res.prl)
1320 if 'phonemodel' in res.getfields():
1321 phone_info.append('Model:', res.phonemodel)
1322 else:
1323 phone_info.append('Model:', self.desc)
1324 req=self.protocolclass.phonenumberrequest()
1325 res=self.sendpbcommand(req, self.protocolclass.phonenumberresponse)
1326 phone_info.append('Phone Number:', res.myphonenumber)
1327
1328 req=self.protocolclass.reconditionedrequest()
1329 res=self.sendpbcommand(req, self.protocolclass.reconditionedresponse)
1330 if res.reconditioned:
1331 recon='Yes'
1332 else:
1333 recon='No'
1334 phone_info.append('Reconditioned:',recon)
1335 except:
1336 pass
1337
1338 return
1339
1341 """Unpack 32 bit value into date/time
1342
1343 @rtype: tuple
1344 @return: (year, month, day, hour, minute)
1345 """
1346 return list(time.gmtime(val+self._sanyoepochtounix)[:5])
1347
1348 _calrepeatvalues={
1349 0: None,
1350 1: 'daily',
1351 2: 'weekly',
1352 3: 'monthly',
1353 4: 'yearly'
1354 }
1355
1356
1358 """Convert the phone number into something the phone understands
1359
1360 All digits, P, T, * and # are kept, everything else is removed"""
1361
1362
1363 return re.sub("[^0-9PT#*]", "", str)
1364
1366 serialsname='sanyo'
1367
1368 WALLPAPER_WIDTH=120
1369 WALLPAPER_HEIGHT=128
1370 OVERSIZE_PERCENTAGE=100
1371
1372 MAX_WALLPAPER_BASENAME_LENGTH=19
1373 WALLPAPER_FILENAME_CHARS="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .`~!@#$%^&()-_=+[{]};\'"
1374 WALLPAPER_CONVERT_FORMAT="png"
1375
1376 MAX_RINGTONE_BASENAME_LENGTH=19
1377 RINGTONE_FILENAME_CHARS="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .`~!@#$%^&()-_=+[{]};\'"
1378
1379
1380 usbids=( ( 0x0474, 0x0701, 1),
1381 )
1382
1383 deviceclasses=("modem",)
1384
1385 BP_Calendar_Version=3
1386
1390
1391
1392 _supportedsyncs=(
1393 ('phonebook', 'read', None),
1394 ('calendar', 'read', None),
1395 ('phonebook', 'write', 'OVERWRITE'),
1396 ('calendar', 'write', 'OVERWRITE'),
1397 ('wallpaper', 'write', 'MERGE'),
1398 ('ringtone', 'write', 'MERGE'),
1399 ('call_history', 'read', None),
1400 ('sms', 'read', None),
1401 )
1402
1403
1404
1405
1406
1407
1409 "Converts the data to what will be used by the phone"
1410 results={}
1411
1412 slotsused={}
1413 for pbentry in data['phonebook']:
1414 entry=data['phonebook'][pbentry]
1415 serial1=helper.getserial(entry.get('serials', []), self.serialsname, data['uniqueserial'], 'serial1', -1)
1416 if(serial1 >= 0 and serial1 < self.protocolclass._NUMPBSLOTS):
1417 slotsused[serial1]=1
1418
1419 lastunused=0
1420
1421 for pbentry in data['phonebook']:
1422 e={}
1423 entry=data['phonebook'][pbentry]
1424 try:
1425 try:
1426 e['name']=helper.getfullname(entry.get('names', []),1,1,16)[0]
1427 except:
1428 e['name']=''
1429 e['name_len']=len(e['name'])
1430
1431 serial1=helper.getserial(entry.get('serials', []), self.serialsname, data['uniqueserial'], 'serial1', -1)
1432
1433 if(serial1 >= 0 and serial1 < self.protocolclass._NUMPBSLOTS):
1434 e['slot']=serial1
1435 else:
1436 while(slotsused.has_key(lastunused)):
1437 lastunused+=1
1438 if(lastunused >= self.protocolclass._NUMPBSLOTS):
1439 raise helper.ConversionFailed()
1440 e['slot']=lastunused
1441 slotsused[lastunused]=1
1442
1443 e['slotdup']=e['slot']
1444
1445 e['email']=helper.makeone(helper.getemails(entry.get('emails', []),0,1,self.protocolclass._MAXEMAILLEN), "")
1446 e['email_len']=len(e['email'])
1447
1448 e['url']=helper.makeone(helper.geturls(entry.get('urls', []), 0,1,self.protocolclass._MAXEMAILLEN), "")
1449 e['url_len']=len(e['url'])
1450
1451
1452 numbers=helper.getnumbers(entry.get('numbers', []),0,7)
1453 e['numbertypes']=[]
1454 e['numbers']=[]
1455 e['speeddials']=[]
1456 unusednumbers=[]
1457 typesused={}
1458 defaultnum=0
1459 for num in numbers:
1460 typename=num['type']
1461 if(typesused.has_key(typename)):
1462 unusednumbers.append(num)
1463 continue
1464 typesused[typename]=1
1465 for typenum,tnsearch in enumerate(self.numbertypetab):
1466 if typename==tnsearch:
1467 if defaultnum==0:
1468 defaultnum=typenum+1
1469 number=phonize(num['number'])
1470 if len(number)>self.protocolclass._MAXNUMBERLEN:
1471
1472 number=number[:self.protocolclass._MAXNUMBERLEN]
1473 e['numbers'].append(number)
1474 if(num.has_key('speeddial')):
1475 e['speeddials'].append(num['speeddial'])
1476 else:
1477 e['speeddials'].append(-1)
1478
1479 e['numbertypes'].append(typenum)
1480
1481 break
1482
1483
1484 trytype=len(self.numbertypetab)
1485 for num in unusednumbers:
1486 while trytype>0:
1487 trytype-=1
1488 if not typesused.has_key(self.numbertypetab[trytype]):
1489 break
1490 else:
1491 break
1492 if defaultnum==0:
1493 defaultnum=trytype+1
1494 number=phonize(num['number'])
1495 if len(number)>self.protocolclass._MAXNUMBERLEN:
1496
1497 number=number[:self.protocolclass._MAXNUMBERLEN]
1498 e['numbers'].append(number)
1499 e['numbertypes'].append(trytype)
1500 if(num.has_key('speeddial')):
1501 e['speeddials'].append(num['speeddial'])
1502 else:
1503 e['speeddials'].append(-1)
1504
1505 if defaultnum==0:
1506 if e['url_len'] > 0:
1507 defaultnum=8
1508 elif e['email_len'] > 0:
1509 defaultnum=9
1510
1511 e['ringtone']=helper.getringtone(entry.get('ringtones', []), 'call', None)
1512 e['wallpaper']=helper.getwallpaper(entry.get('wallpapers', []), 'call', None)
1513
1514 e['secret']=helper.getflag(entry.get('flags', []), 'secret', False)
1515 e['defaultnum']=defaultnum
1516
1517 results[pbentry]=e
1518
1519 except helper.ConversionFailed:
1520
1521 print "No Free Slot for "+e['name']
1522 continue
1523
1524 data['phonephonebook']=results
1525 return data
1526
1527
1528 -class Phone(SanyoPhonebook,com_phone.Phone,com_brew.BrewProtocol):
1550