| 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 
   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