示例#1
0
    def sendpbcommand(self, request, responseclass):
        self.setmode(self.MODEBREW)
        buffer = prototypes.buffer()
        request.writetobuffer(buffer,
                              logtitle="audiovox cdm8900 phonebook request")
        data = buffer.getvalue()
        data = common.pppescape(data +
                                common.crcs(data)) + common.pppterminator
        first = data[0]
        try:
            data = self.comm.writethenreaduntil(data,
                                                False,
                                                common.pppterminator,
                                                logreaduntilsuccess=False)
        except com_phone.modeignoreerrortypes:
            self.mode = self.MODENONE
            self.raisecommsdnaexception("manipulating the phonebook")
        self.comm.success = True

        origdata = data
        # sometimes there is junk at the begining, eg if the user
        # turned off the phone and back on again.  So if there is more
        # than one 7e in the escaped data we should start after the
        # second to last one
        d = data.rfind(common.pppterminator, 0, -1)
        if d >= 0:
            self.log(
                "Multiple PB packets in data - taking last one starting at " +
                ` d + 1 `)
            self.logdata("Original pb data", origdata, None)
            data = data[d + 1:]

        # turn it back to normal
        data = common.pppunescape(data)

        # sometimes there is other crap at the begining
        d = data.find(first)
        if d > 0:
            self.log("Junk at begining of pb packet, data at " + ` d `)
            self.logdata("Original pb data", origdata, None)
            self.logdata("Working on pb data", data, None)
            data = data[d:]
        # take off crc and terminator
        crc = data[-3:-1]
        data = data[:-3]
        if common.crcs(data) != crc:
            self.logdata("Original pb data", origdata, None)
            self.logdata("Working on pb data", data, None)
            raise common.CommsDataCorruption(
                "Audiovox phonebook packet failed CRC check", self.desc)

        # parse data
        buffer = prototypes.buffer(data)
        res = responseclass()
        res.readfrombuffer(buffer, logtitle="Audiovox phonebook response")
        return res
    def sendpbcommand(self, request, responseclass):
        self.setmode(self.MODEBREW)
        buffer=prototypes.buffer()
        request.writetobuffer(buffer, logtitle="audiovox cdm8900 phonebook request")
        data=buffer.getvalue()
        data=common.pppescape(data+common.crcs(data))+common.pppterminator
        first=data[0]
        try:
            data=self.comm.writethenreaduntil(data, False, common.pppterminator, logreaduntilsuccess=False)
        except com_phone.modeignoreerrortypes:
            self.mode=self.MODENONE
            self.raisecommsdnaexception("manipulating the phonebook")
        self.comm.success=True

        origdata=data
        # sometimes there is junk at the begining, eg if the user
        # turned off the phone and back on again.  So if there is more
        # than one 7e in the escaped data we should start after the
        # second to last one
        d=data.rfind(common.pppterminator,0,-1)
        if d>=0:
            self.log("Multiple PB packets in data - taking last one starting at "+`d+1`)
            self.logdata("Original pb data", origdata, None)
            data=data[d+1:]

        # turn it back to normal
        data=common.pppunescape(data)

        # sometimes there is other crap at the begining
        d=data.find(first)
        if d>0:
            self.log("Junk at begining of pb packet, data at "+`d`)
            self.logdata("Original pb data", origdata, None)
            self.logdata("Working on pb data", data, None)
            data=data[d:]
        # take off crc and terminator
        crc=data[-3:-1]
        data=data[:-3]
        if common.crcs(data)!=crc:
            self.logdata("Original pb data", origdata, None)
            self.logdata("Working on pb data", data, None)
            raise common.CommsDataCorruption("Audiovox phonebook packet failed CRC check", self.desc)
        
        # parse data
        buffer=prototypes.buffer(data)
        res=responseclass()
        res.readfrombuffer(buffer, logtitle="Audiovox phonebook response")
        return res
 def sendpbcommand(self, request, responseclass, callsetmode=True):
     if callsetmode:
         self.setmode(self.MODEPHONEBOOK)
     buffer=prototypes.buffer()
     request.header.sequence=self.pbseq
     self.pbseq+=1
     if self.pbseq>0xff:
         self.pbseq=0
     request.writetobuffer(buffer, logtitle="lg phonebook request")
     data=buffer.getvalue()
     data=common.pppescape(data+common.crcs(data))+common.pppterminator
     firsttwo=data[:2]
     try:
         data=self.comm.writethenreaduntil(data, False, common.pppterminator, logreaduntilsuccess=False)
     except com_phone.modeignoreerrortypes:
         self.mode=self.MODENONE
         self.raisecommsdnaexception("manipulating the phonebook")
     self.comm.success=True
     origdata=data
     d=data.rfind(common.pppterminator,0,-1)
     if d>=0:
         self.log("Multiple LG packets in data - taking last one starting at "+`d+1`)
         self.logdata("Original LG data", origdata, None)
         data=data[d+1:]
     data=common.pppunescape(data)
     crc=data[-3:-1]
     data=data[:-3]
     calccrc=common.crcs(data)
     if calccrc!=crc:
         d=data.find(firsttwo)
         if d>0:
             self.log("Junk at begining of LG packet, data at "+`d`)
             self.logdata("Original LG data", origdata, None)
             self.logdata("Working on LG data", data, None)
             data=data[d:]
             calccrc=common.crcs(data)
         if calccrc!=crc:
             self.logdata("Original LG data", origdata, None)
             self.logdata("Working on LG data", data, None)
             raise common.CommsDataCorruption("LG packet failed CRC check", self.desc)
     if ord(data[0])==0x13:
         raise com_brew.BrewBadBrewCommandException()
     if ord(data[0])==0x14:
         raise com_brew.BrewMalformedBrewCommandException()
     buffer=prototypes.buffer(data)
     res=responseclass()
     res.readfrombuffer(buffer, logtitle="lg phonebook response")
     return res
 def modemmoderequest(self):
     self.log("Attempting to put phone in modem mode")
     req=p_brew.setmodemmoderequest()
     buffer=prototypes.buffer()
     req.writetobuffer(buffer, logtitle="modem mode request")
     data=buffer.getvalue()
     data=common.pppescape(data+common.crcs(data))+common.pppterminator
     self.comm.write(data)
     self.comm.readsome(numchars=5)
     self.mode=self.MODENONE # Probably should add a modem mode
 def sendpbcommand(self, request, responseclass):
     self.setmode(self.MODEBREW)
     buffer=prototypes.buffer()
     request.writetobuffer(buffer)
     data=buffer.getvalue()
     self.logdata("toshiba vm4050 phonebook request", data, request)
     data=common.pppescape(data+common.crcs(data))+common.pppterminator
     first=data[0]
     try:
         data=self.comm.writethenreaduntil(data, False, common.pppterminator, logreaduntilsuccess=False)
     except com_phone.modeignoreerrortypes:
         self.mode=self.MODENONE
         self.raisecommsdnaexception("manipulating the phonebook")
     self.comm.success=True
     origdata=data
     d=data.rfind(common.pppterminator,0,-1)
     if d>=0:
         self.log("Multiple PB packets in data - taking last one starting at "+`d+1`)
         self.logdata("Original pb data", origdata, None)
         data=data[d+1:]
     data=common.pppunescape(data)
     d=data.find(first)
     if d>0:
         self.log("Junk at begining of pb packet, data at "+`d`)
         self.logdata("Original pb data", origdata, None)
         self.logdata("Working on pb data", data, None)
         data=data[d:]
     crc=data[-3:-1]
     data=data[:-3]
     if common.crcs(data)!=crc:
         self.logdata("Original pb data", origdata, None)
         self.logdata("Working on pb data", data, None)
         raise common.CommsDataCorruption("toshiba phonebook packet failed CRC check", self.desc)
     self.logdata("toshiba phonebook response", data, responseclass)
     buffer=prototypes.buffer(data)
     res=responseclass()
     res.readfrombuffer(buffer)
     return res
 def sendbrewcommand(self, request, responseclass, callsetmode=True):
     if callsetmode:
         self.setmode(self.MODEBREW)
     buffer=prototypes.buffer()
     request.writetobuffer(buffer, logtitle="sendbrewcommand")
     data=buffer.getvalue()
     data=common.pppescape(data+common.crcs(data))+common.pppterminator
     firsttwo=data[:2]
     try:
         data=self.comm.writethenreaduntil(data, False, common.pppterminator, logreaduntilsuccess=False) 
     except modeignoreerrortypes:
         self.mode=self.MODENONE
         self.raisecommsdnaexception("manipulating the filesystem")
     self.comm.success=True
     origdata=data
     d=data.rfind(common.pppterminator,0,-1)
     if d>=0:
         self.log("Multiple packets in data - taking last one starting at "+`d+1`)
         self.logdata("Original data", origdata, None)
         data=data[d+1:]
     data=common.pppunescape(data)
     crc=data[-3:-1]
     data=data[:-3]
     calccrc=common.crcs(data)
     if calccrc!=crc:
         d=data.find(firsttwo)
         if d>0:
             self.log("Junk at begining of packet, data at "+`d`)
             self.logdata("Original data", origdata, None)
             self.logdata("Working on data", data, None)
             data=data[d:]
             calccrc=common.crcs(data)
         if calccrc!=crc:
             self.logdata("Original data", origdata, None)
             self.logdata("Working on data", data, None)
             raise common.CommsDataCorruption("Brew packet failed CRC check", self.desc)
     self.logdata("brew response", data, responseclass)
     if firsttwo=="Y\x0c" and data==firsttwo:
         raise common.CommsWrongPort("The port you are using is echoing data back, and is not valid for Brew data.  Most likely you have selected the modem interface when you should be using the diagnostic interface.", self.desc)
     if data[0]=="Y" and data[2]!="\x00":  # Y is 0x59 which is brew command prefix
             err=ord(data[2])
             if err==0x1c:
                 raise BrewNoMoreEntriesException()
             if err==0x08:
                 raise BrewNoSuchDirectoryException()
             if err==0x06:
                 raise BrewNoSuchFileException()
             if err==0x1a:
                 raise BrewBadPathnameException()
             if err==0x0b:
                 raise BrewFileLockedException()
             if err==0x0d:
                 raise BrewNameTooLongException()
             if err==0x07:
                 raise BrewDirectoryExistsException()
             if err==0x04:
                 raise BrewAccessDeniedException()
             if err==0x16:
                 raise BrewFileSystemFullException()
             raise BrewCommandException(err)
     if ord(data[0])==0x13:
         if firsttwo[0]=="Y": # brew command
             raise BrewAccessDeniedException()
         else:
             raise BrewBadBrewCommandException()
     if ord(data[0])==0x14:
         raise BrewMalformedBrewCommandException()
     buffer=prototypes.buffer(data)
     res=responseclass()
     try:
         res.readfrombuffer(buffer, autolog=False)
     except:
         self.log(formatpacketerrorlog("Error decoding response", origdata, data, responseclass))
         raise
     return res
	def sendpbcommand(self, request, responseclass):

        self.setmode(self.MODEBREW)

        buffer=prototypes.buffer()

        request.writetobuffer(buffer)

        data=buffer.getvalue()

        self.logdata("toshiba vm4050 phonebook request", data, request)

        data=common.pppescape(data+common.crcs(data))+common.pppterminator

        first=data[0]

        try:

            data=self.comm.writethenreaduntil(data, False, common.pppterminator, logreaduntilsuccess=False)

        except com_phone.modeignoreerrortypes:

            self.mode=self.MODENONE

            self.raisecommsdnaexception("manipulating the phonebook")

        self.comm.success=True

        origdata=data

        d=data.rfind(common.pppterminator,0,-1)

        if d>=0:

            self.log("Multiple PB packets in data - taking last one starting at "+`d+1`)

            self.logdata("Original pb data", origdata, None)

            data=data[d+1:]

        data=common.pppunescape(data)

        d=data.find(first)

        if d>0:

            self.log("Junk at begining of pb packet, data at "+`d`)

            self.logdata("Original pb data", origdata, None)

            self.logdata("Working on pb data", data, None)

            data=data[d:]

        crc=data[-3:-1]

        data=data[:-3]

        if common.crcs(data)!=crc:

            self.logdata("Original pb data", origdata, None)

            self.logdata("Working on pb data", data, None)

            raise common.CommsDataCorruption("toshiba phonebook packet failed CRC check", self.desc)

        self.logdata("toshiba phonebook response", data, responseclass)

        buffer=prototypes.buffer(data)

        res=responseclass()

        res.readfrombuffer(buffer)

        return res

	def get_detect_data(self, res):

        self.modemmoderequest()

        res['manufacturer']=self.comm.sendatcommand('+GMI')[0]

        res['model']=self.comm.sendatcommand('+GMM')[0]

        res['firmware_version']=self.comm.sendatcommand('+GMR')[0]

        res['esn']=self.comm.sendatcommand('+GSN')[0][2:] 

        return

	def detectphone(coms, likely_ports, res, _module, _log):

        if not likely_ports:

            return None

        for port in likely_ports:

            if not res.has_key(port):

                res[port]={ 'mode_modem': None, 'mode_brew': None,
                            'manufacturer': None, 'model': None,
                            'firmware_version': None, 'esn': None,
                            'firmwareresponse': None }

            try:

                if res[port]['model']:

                    continue

                p=_module.Phone(_log, commport.CommConnection(_log, port, timeout=1))

                res[port]['mode_brew']=p._setmodebrew()

                if res[port]['mode_brew']:

                    p.get_detect_data(res[port])

                p.comm.close()

            except:

                if __debug__:

                    raise

	detectphone=staticmethod(detectphone)
	"Talk to Toshiba VM4050 cell phone"

class  Profile (com_phone.Profile) :
	protocolclass=Phone.protocolclass
	    serialsname=Phone.serialsname
	    phone_manufacturer='Audiovox Communications Corporation'
	    phone_model='VM4050'
	    usbids=((0x05C6, 0x3100, 1), 
        )
	    deviceclasses=("modem",)
	    _supportedsyncs=(
        ('phonebook', 'read', None),         
        ('phonebook', 'write', 'OVERWRITE'), 
        )
	    def convertphonebooktophone(self, helper, data):

        """Converts the data to what will be used by the phone
        @param data: contains the dict returned by getfundamentals
                 as well as where the results go"""

        results={}

        slotsused={}

        for pbentry in data['phonebook']:

            entry=data['phonebook'][pbentry]

            serial1=helper.getserial(entry.get('serials', []), self.serialsname, data['uniqueserial'], 'serial1', -1)

            if(serial1 >= 0 and serial1 < self.protocolclass.NUMSLOTS):

                slotsused[serial1]=1

        lastunused=0 

        for pbentry in data['phonebook']:

            if len(results)==self.protocolclass.NUMSLOTS:

                break

            e={} 

            entry=data['phonebook'][pbentry] 

            try:

                e['name']=helper.getfullname(entry.get('names', []),1,1,36)[0]

                serial1=helper.getserial(entry.get('serials', []), self.serialsname, data['uniqueserial'], 'serial1', -1)

                if(serial1 >= 0 and serial1 < self.protocolclass.NUMSLOTS):

                    e['slot']=serial1

                else:  

                    while(slotsused.has_key(lastunused)):

                        lastunused+=1

                        if(lastunused >= self.protocolclass.NUMSLOTS):

                            helper.add_error_message("Name: %s. Unable to add, phonebook full" % e['name'])

                            raise helper.ConversionFailed()

                    e['slot']=lastunused

                    slotsused[lastunused]=1

                emails=helper.getemails(entry.get('emails', []) ,0,self.protocolclass.MAXEMAILS,self.protocolclass.MAXEMAILLEN)

                e['emails']=helper.filllist(emails, self.protocolclass.MAXEMAILS, "")

                e['web_page']=helper.makeone(helper.geturls(entry.get('urls', []), 0,1,48), "")

                numbers=helper.getnumbers(entry.get('numbers', []),0,self.protocolclass.MAXPHONENUMBERS)

                e['numbertypes']=[]

                e['numbers']=[]

                typesused={}

                for num in numbers:

                    type=num['type']

                    if(typesused.has_key(type)):

                        continue

                    typesused[type]=1

                    for typenum,tnsearch in enumerate(self.protocolclass.numbertypetab):

                        if type==tnsearch:

                            number=self.phonize(num['number'])

                            if len(number)==0:

                                continue

                            if len(number)>self.protocolclass.MAXPHONENUMBERLEN: 

                                number=number[:self.protocolclass.MAXPHONENUMBERLEN]

                            e['numbers'].append(number)

                            e['numbertypes'].append(typenum)

                            break

                e['ringtone']=helper.getringtone(entry.get('ringtones', []), 'call', None)

                e['secret']=helper.getflag(entry.get('flags',[]), 'secret', False)

                results[pbentry]=e

            except helper.ConversionFailed:

                continue

        data['phonebook']=results

        return data

	def phonize(self, str):

        """Convert the phone number into something the phone understands
        All digits, P, T, *, #  are kept, everything else is removed.
        In theory the phone can store a dash in the phonebook, but that
        is not normal."""

        return re.sub("[^0-9PT#*]", "", str)[:self.protocolclass.MAXPHONENUMBERLEN]
 def sendpbcommand(self, request, responseclass, callsetmode=True, writemode=False, numsendretry=0, returnerror=False):
     if writemode:
         numretry=3
     else:
         numretry=0
     if callsetmode:
         self.setmode(self.MODEPHONEBOOK)
     buffer=prototypes.buffer()
     request.writetobuffer(buffer)
     data=buffer.getvalue()
     firsttwo=data[:2]
     data=common.pppescape(data+common.crcs(data))+common.pppterminator
     self.logdata("N400 phonebook request", data, request)
     isendretry=numsendretry
     while isendretry>=0:
         try:
             rdata=self.comm.writethenreaduntil(data, False, common.pppterminator, logreaduntilsuccess=False, numfailures=numretry)
             break
         except com_phone.modeignoreerrortypes:
             if isendretry>0:
                 self.log("Resending request packet...")
                 time.sleep(0.3)
             else:
                 self.comm.success=False
                 self.mode=self.MODENONE
                 self.raisecommsdnaexception("manipulating the phonebook")
             isendretry-=1
     self.comm.success=True
     origdata=rdata
     d=rdata.rfind(common.pppterminator,0,-1)
     if d>=0:
         self.log("Multiple N400 packets in data - taking last one starting at "+`d+1`)
         self.logdata("Original N400 data", origdata, None)
         rdata=rdata[d+1:]
     data=common.pppunescape(rdata)
     d=data.find(firsttwo)
     crc=data[-3:-1]
     crcok=False
     for i in range(0,d+1):
         trydata=data[i:-3]
         if common.crcs(trydata)==crc:
             crcok=True
             break
     if not crcok:
         self.logdata("first two",firsttwo, None)
         self.logdata("Original N400 data", origdata, None)
         self.logdata("Working on N400 data", data, None)
         raise common.CommsDataCorruption("N400 packet failed CRC check", self.desc)
     res=responseclass()
     if d>0:
         if d==i:
             self.log("Junk at beginning of N400 packet, data at "+`d`)
             self.logdata("Original N400 data", origdata, None)
             self.logdata("Working on N400 data", data, None)
         else:
             if returnerror:
                 res=self.protocolclass.sanyoerror()
             else:
                 self.log("N400 Error code "+`ord(data[0])`)
                 self.logdata("Samsung phonebook response", data, None)
                 raise N400CommandException(ord(data[0]))
     data=trydata
     self.logdata("sanyo phonebook response", data, responseclass)
     buffer=prototypes.buffer(data)
     res.readfrombuffer(buffer)
     return res
	def modemmoderequest(self):

        self.log("Attempting to put phone in modem mode")

        req=p_brew.setmodemmoderequest()

        buffer=prototypes.buffer()

        req.writetobuffer(buffer)

        data=buffer.getvalue()

        self.logdata("brew request", data, req)

        data=common.pppescape(data+common.crcs(data))+common.pppterminator

        self.comm.write(data)

        self.comm.readsome(numchars=5)

        self.mode=self.MODENONE

	def mkdir(self, name):

        self.log("Making directory '"+name+"'")

        req=p_brew.mkdirrequest()

        req.dirname=name

        self.sendbrewcommand(req, p_brew.mkdirresponse)

	def mkdirs(self, directory):

        if len(directory)<1:

            return

        dirs=directory.split('/')

        for i in range(0,len(dirs)):

            try:

                self.mkdir("/".join(dirs[:i+1]))  

            except:

                pass

	def rmdir(self,name):

        self.log("Deleting directory '"+name+"'")

        req=p_brew.rmdirrequest()

        req.dirname=name

        self.sendbrewcommand(req, p_brew.rmdirresponse)

	def rmfile(self,name):

        self.log("Deleting file '"+name+"'")

        req=p_brew.rmfilerequest()

        req.filename=name

        self.sendbrewcommand(req, p_brew.rmfileresponse)

        file_cache.clear(name)

	def rmdirs(self, path):

        self.progress(0,1, "Listing child files and directories")

        all=self.getfilesystem(path, 100)

        keys=all.keys()

        keys.sort()

        keys.reverse()

        count=0

        for k in keys:

            self.progress(count, len(keys), "Deleting "+k)

            count+=1

            if all[k]['type']=='directory':

                self.rmdir(k)

            else:

                self.rmfile(k)

        self.rmdir(path)

	def exists(self, path):

        req=p_brew.listfilerequest()

        req.dirname=path

        req.entrynumber=0

        try:

            res=self.sendbrewcommand(req,p_brew.listfileresponse)

        except (BrewBadPathnameException, BrewNoSuchDirectoryException,
                ValueError):

            return False

        except:

            if __debug__:

                raise

            return False

        return True

	def listsubdirs(self, dir='', recurse=0):

        results={}

        self.log("Listing subdirs in dir: '"+dir+"'")

        req=p_brew.listdirectoryrequest()

        req.dirname=dir

        for i in xrange(10000):

            try:

                req.entrynumber=i

                res=self.sendbrewcommand(req,p_brew.listdirectoryresponse)

                f=res.subdir.rfind("/")

                if f>=0:

                    subdir=res.subdir[f+1:]

                else:

                    subdir=res.subdir

                if len(dir):

                    subdir=dir+"/"+subdir

                results[subdir]={ 'name': subdir, 'type': 'directory' }

            except BrewNoMoreEntriesException:

                break

            except (BrewBadPathnameException, ValueError):

                self.log('Failed to list dir '+dir)

                return {}

        if recurse:

            for k,_subdir in results.items():

                results.update(self.listsubdirs(_subdir['name'], recurse-1))

        return results

	def hassubdirs(self, dir=''):

        self.log('Checking for subdirs in dir: "'+dir+'"')

        req=p_brew.listdirectoryrequest()

        req.dirname=dir

        req.entrynumber=0

        try:

            res=self.sendbrewcommand(req,p_brew.listdirectoryresponse)

            return True

        except BrewNoMoreEntriesException:

            return False

        except:

            if __debug__:

                raise

            return False

	def listfiles(self, dir=''):

        results={}

        self.log("Listing files in dir: '"+dir+"'")

        req=p_brew.listfilerequest()

        req.dirname=dir

        for i in xrange(10000):

            try:

                req.entrynumber=i

                res=self.sendbrewcommand(req,p_brew.listfileresponse)

                results[res.filename]={ 'name': res.filename, 'type': 'file',
                                        'size': res.size }

                if res.date==0:

                    results[res.filename]['date']=(0, "")

                else:

                    try:

                        date=res.date+self._brewepochtounix

                        results[res.filename]['date']=(date, time.strftime("%x %X", time.gmtime(date)))

                    except:

                        results[res.filename]['date']=(0, "")

            except BrewNoMoreEntriesException:

                break

            except (BrewBadPathnameException, ValueError):

                self.log('Failed to list files in dir '+dir)

                return {}

        return results

	def getfilesystem(self, dir="", recurse=0):

        self.log("Getting file system in dir '"+dir+"'")

        results=self.listsubdirs(dir)

        subdir_list=[x['name'] for k,x in results.items()]

        results.update(self.listfiles(dir))

        if recurse:

            for _subdir in subdir_list:

                results.update(self.getfilesystem(_subdir, recurse-1))

        return results

	def statfile(self, name):

        try:

            self.log('stat file '+name)

            req=p_brew.statfilerequest()

            req.filename=name

            res=self.sendbrewcommand(req, p_brew.statfileresponse)

            results={ 'name': name, 'type': 'file', 'size': res.size,
                      'datevalue': res.date }

            if res.date==0:

                results['date']=(0, '')

            else:

                try:

                    date=res.date+self._brewepochtounix

                    results['date']=(date, time.strftime("%x %X", time.gmtime(date)))

                except:

                    results['date']=(0, '')

            return results

        except BrewNoSuchFileException:

            return None

        except:

            if __debug__:

                raise

            return None

	def setfileattr(self, filename, date):

        self.log('set file date '+filename +`date`)

        req=p_brew.setfileattrrequest()

        req.date=date-self._brewepochtounix

        req.filename=filename

        self.sendbrewcommand(req, p_brew.setfileattrresponse)

	def writefile(self, name, contents):

        start=time.time()

        self.log("Writing file '"+name+"' bytes "+`len(contents)`)

        desc="Writing "+name

        req=p_brew.writefilerequest()

        req.filesize=len(contents)

        req.data=contents[:0x100]

        req.filename=name

        self.sendbrewcommand(req, p_brew.writefileresponse)

        numblocks=len(contents)/0x100

        count=0

        for offset in range(0x100, len(contents), 0x100):

            req=p_brew.writefileblockrequest()

            count+=1

            if count>=0x100: count=1

            if count % 5==0:

                self.progress(offset>>8,numblocks,desc)

            req.blockcounter=count

            req.thereismore=offset+0x100<len(contents)

            block=contents[offset:]

            l=min(len(block), 0x100)

            block=block[:l]

            req.data=block

            self.sendbrewcommand(req, p_brew.writefileblockresponse)

        end=time.time()

        if end-start>3:

            self.log("Wrote "+`len(contents)`+" bytes at "+`int(len(contents)/(end-start))`+" bytes/second")

	def getfilecontents(self, file, use_cache=False):

        if use_cache:

            node=self.statfile(file)

            if node and file_cache.hit(file, node['date'][0], node['size']):

                self.log('Reading from cache: '+file)

                _data=file_cache.data(file)

                if _data:

                    return _data

                self.log('Cache file corrupted and discarded')

        start=time.time()

        self.log("Getting file contents '"+file+"'")

        desc="Reading "+file

        data=cStringIO.StringIO()

        req=p_brew.readfilerequest()

        req.filename=file

        res=self.sendbrewcommand(req, p_brew.readfileresponse)

        filesize=res.filesize

        data.write(res.data)

        counter=0

        while res.thereismore:

            counter+=1

            if counter>0xff:

                counter=0x01

            if counter%5==0:

                self.progress(data.tell(), filesize, desc)

            req=p_brew.readfileblockrequest()

            req.blockcounter=counter

            res=self.sendbrewcommand(req, p_brew.readfileblockresponse)

            data.write(res.data)

        self.progress(1,1,desc)

        data=data.getvalue()

        end=time.time()

        if end-start>3:

            self.log("Read "+`filesize`+" bytes at "+`int(filesize/(end-start))`+" bytes/second")

        if filesize!=len(data):

            self.log("expected size "+`filesize`+"  actual "+`len(data)`)

            self.raisecommsexception("Brew file read is incorrect size", common.CommsDataCorruption)

        if use_cache and node:

            file_cache.add(file, node.get('date', [0])[0], data)

        return data

	DirCache=_DirCache
	    def _setmodebrew(self):

        req=p_brew.memoryconfigrequest()

        respc=p_brew.memoryconfigresponse

        for baud in 0, 38400,115200:

            if baud:

                if not self.comm.setbaudrate(baud):

                    continue

            try:

                self.sendbrewcommand(req, respc, callsetmode=False)

                return True

            except modeignoreerrortypes:

                pass

        for baud in (0, 115200, 19200, 230400):

            if baud:

                if not self.comm.setbaudrate(baud):

                    continue

            print "Baud="+`baud`

            try:

                for line in self.comm.sendatcommand("+GMM"):

                    if line.find("SPH-A700")>0:

                        raise BrewNotSupported("This phone is not supported by BitPim", self.desc)

            except modeignoreerrortypes:

                self.log("No response to AT+GMM")

            except:

                print "GMM Exception"

                self.mode=self.MODENONE

                self.comm.shouldloop=True

                raise

            try:

                self.comm.write("AT$QCDMG\r\n")

            except:

                self.mode=self.MODENONE

                self.comm.shouldloop=True

                raise

            try:

                if self.comm.readsome().find("OK")>=0:

                    break

            except modeignoreerrortypes:

                self.log("No response to setting QCDMG mode")

        for baud in 0,38400,115200:

            if baud:

                if not self.comm.setbaudrate(baud):

                    continue

            try:

                self.sendbrewcommand(req, respc, callsetmode=False)

                return True

            except modeignoreerrortypes:

                pass

        return False

	def sendbrewcommand(self, request, responseclass, callsetmode=True):

        if callsetmode:

            self.setmode(self.MODEBREW)

        buffer=prototypes.buffer()

        request.writetobuffer(buffer)

        data=buffer.getvalue()

        self.logdata("brew request", data, request)

        data=common.pppescape(data+common.crcs(data))+common.pppterminator

        firsttwo=data[:2]

        try:

            data=self.comm.writethenreaduntil(data, False, common.pppterminator, logreaduntilsuccess=False) 

        except modeignoreerrortypes:

            self.mode=self.MODENONE

            self.raisecommsdnaexception("manipulating the filesystem")

        self.comm.success=True

        origdata=data

        d=data.rfind(common.pppterminator,0,-1)

        if d>=0:

            self.log("Multiple packets in data - taking last one starting at "+`d+1`)

            self.logdata("Original data", origdata, None)

            data=data[d+1:]

        data=common.pppunescape(data)

        d=data.find(firsttwo)

        if d>0:

            self.log("Junk at begining of packet, data at "+`d`)

            self.logdata("Original data", origdata, None)

            self.logdata("Working on data", data, None)

            data=data[d:]

        crc=data[-3:-1]

        data=data[:-3]

        calccrc=common.crcs(data)

        if calccrc!=crc:

            self.logdata("Original data", origdata, None)

            self.logdata("Working on data", data, None)

            raise common.CommsDataCorruption("Brew packet failed CRC check", self.desc)

        self.logdata("brew response", data, responseclass)

        if firsttwo=="Y\x0c" and data==firsttwo:

            raise common.CommsWrongPort("The port you are using is echoing data back, and is not valid for Brew data.  Most likely you have selected the modem interface when you should be using the diagnostic interface.", self.desc)

        if data[0]=="Y" and data[2]!="\x00":  

                err=ord(data[2])

                if err==0x1c:

                    raise BrewNoMoreEntriesException()

                if err==0x08:

                    raise BrewNoSuchDirectoryException()

                if err==0x06:

                    raise BrewNoSuchFileException()

                if err==0x1a:

                    raise BrewBadPathnameException()

                if err==0x0b:

                    raise BrewFileLockedException()

                if err==0x0d:

                    raise BrewNameTooLongException()

                if err==0x07:

                    raise BrewDirectoryExistsException()

                raise BrewCommandException(err)

        buffer=prototypes.buffer(data)

        res=responseclass()

        try:

            res.readfrombuffer(buffer)

        except:

            self.log(formatpacketerrorlog("Error decoding response", origdata, data, responseclass))

            raise

        return res

	"Talk to a phone using the 'brew' protocol"

class  RealBrewProtocol2 :
	"""Talk to a phone using the 'brew' protocol
    This class uses the new filesystem commands which are supported
    by newer qualcomm chipsets used in phones like the LG vx8100
    """
	    def exists(self, name):

        try:

            self.statfile(name)

        except BrewNoSuchFileException:

            return False

        return True

	def reconfig_directory(self):

        req=p_brew.new_reconfigfilesystemrequest()

        self.sendbrewcommand(req, p_brew.new_reconfigfilesystemresponse)

	def rmfile(self,name):

        self.log("Deleting file '"+name+"'")

        if self.exists(name):

            req=p_brew.new_rmfilerequest()

            req.filename=name

            self.sendbrewcommand(req, p_brew.new_rmfileresponse)

        file_cache.clear(name)

	def rmdir(self,name):

        self.log("Deleting directory '"+name+"'")

        if self.exists(name):

            req=p_brew.new_rmdirrequest()

            req.dirname=name

            self.sendbrewcommand(req, p_brew.new_rmdirresponse)

            self.reconfig_directory()

	def mkdir(self, name):

        self.log("Making directory '"+name+"'")

        if self.exists(name):

            raise BrewDirectoryExistsException

        req=p_brew.new_mkdirrequest()

        req.dirname=name

        self.sendbrewcommand(req, p_brew.new_mkdirresponse)

        self.reconfig_directory()

	def openfile(self, name, mode, flags=p_brew.new_fileopen_flag_existing):

        self.log("Open file '"+name+"'")

        req=p_brew.new_openfilerequest()

        req.filename=name

        req.mode=mode

        req.flags=flags

        res=self.sendbrewcommand(req, p_brew.new_openfileresponse)

        return res.handle

	def closefile(self, handle):

        self.log("Close file")

        req=p_brew.new_closefilerequest()

        req.handle=handle

        self.sendbrewcommand(req, p_brew.new_closefileresponse)

	def writefile(self, name, contents):

        start=time.time()

        self.log("Writing file '"+name+"' bytes "+`len(contents)`)

        desc="Writing "+name

        size=len(contents)       

        exists=self.exists(name)

        if exists:

            info=self.statfile(name)

            current_size=info['size']

        else:

            current_size=0

        if exists and size<current_size:

            self.rmfile(name)

            exists=False

        if exists:

            handle=self.openfile(name, p_brew.new_fileopen_mode_write, p_brew.new_fileopen_flag_existing)

        else:

            handle=self.openfile(name, p_brew.new_fileopen_mode_write, p_brew.new_fileopen_flag_create)

        if not handle:

            raise BrewNoSuchFileException

        try:

            remain=size

            pos=0

            count=0

            while remain:

                req=p_brew.new_writefilerequest()

                req.handle=handle

                if remain>243:

                    req.bytes=243

                else:

                    req.bytes=remain

                req.position=size-remain

                req.data=contents[req.position:(req.position+req.bytes)]

                count=(count&0xff)+1

                if count % 5==0:

                    self.progress(req.position,size,desc)

                res=self.sendbrewcommand(req, p_brew.new_writefileresponse)

                if res.bytes!=req.bytes:

                    self.raisecommsexception("Brew file write error", common.CommsDataCorruption)

                remain-=req.bytes

        except Exception, e: 

            self.closefile(handle)

            raise Exception, e 

        self.closefile(handle)

        self.progress(1,1,desc)

        end=time.time()

        if end-start>3:

            self.log("Wrote "+`len(contents)`+" bytes at "+`int(len(contents)/(end-start))`+" bytes/second")

	def getfilecontents(self, file, use_cache=False):

        node=self.statfile(file)

        if use_cache:

            if node and file_cache.hit(file, node['date'][0], node['size']):

                self.log('Reading from cache: '+file)

                _data=file_cache.data(file)

                if _data:

                    return _data

                self.log('Cache file corrupted and discarded')

        start=time.time()

        self.log("Getting file contents '"+file+"'")

        desc="Reading "+file

        data=cStringIO.StringIO()

        handle=self.openfile(file, p_brew.new_fileopen_mode_read)

        if not handle:

            raise BrewNoSuchFileException

        try:

            filesize=node['size']

            read=0

            counter=0

            while True:

                counter=(counter&0xff)+1

                if counter%5==0:

                    self.progress(data.tell(), filesize, desc)

                req=p_brew.new_readfilerequest()

                req.handle=handle

                req.bytes=0xEB

                req.position=read

                res=self.sendbrewcommand(req, p_brew.new_readfileresponse)

                if res.bytes:

                    data.write(res.data)

                    read+=res.bytes

                else:

                    break

                if read==filesize:

                    break

        except Exception, e: 

            self.closefile(handle)

            raise Exception, e 

        self.closefile(handle)

        self.progress(1,1,desc)

        data=data.getvalue()

        end=time.time()

        if end-start>3:

            self.log("Read "+`filesize`+" bytes at "+`int(filesize/(end-start))`+" bytes/second")

        if filesize!=len(data):

            self.log("expected size "+`filesize`+"  actual "+`len(data)`)

            self.raisecommsexception("Brew file read is incorrect size", common.CommsDataCorruption)

        if use_cache and node:

            file_cache.add(file, node.get('date', [0])[0], data)

        return data

	def listfiles(self, dir=''):

        self.log("Listing files in dir: '"+dir+"'")

        return self.getfilesystem(dir, recurse=0, directories=0)

	def getfilesystem(self, dir="", recurse=0, directories=1, files=1):

        results={}

        self.log("Listing dir '"+dir+"'")

        req=p_brew.new_opendirectoryrequest()

        if dir=="":

            req.dirname="/"

        else:

            req.dirname=dir

        res=self.sendbrewcommand(req, p_brew.new_opendirectoryresponse)

        handle=res.handle

        if handle==0: 

            raise BrewNoSuchDirectoryException

        dirs={}

        count=0

        try:

            for i in xrange(1, 10000):

                req=p_brew.new_listentryrequest()

                req.entrynumber=i

                req.handle=handle

                res=self.sendbrewcommand(req, p_brew.new_listentryresponse)

                if len(res.entryname) == 0: 

                    break

                if len(dir):

                    direntry=dir+"/"+res.entryname

                else:

                    direntry=res.entryname

                if files and res.type==0: 

                    results[direntry]={ 'name': direntry, 'type': 'file',
                                    'size': res.size }

                    if res.date==0:

                        results[direntry]['date']=(0, "")

                    else:

                        results[direntry]['date']=(res.date, time.strftime("%x %X", time.localtime(res.date)))

                elif directories and res.type: 

                    results[direntry]={ 'name': direntry, 'type': 'directory' }

                    if recurse>0:

                        dirs[count]=direntry

                        count+=1

        except Exception, e: 

            req=p_brew.new_closedirectoryrequest()

            req.handle=handle

            res=self.sendbrewcommand(req, p_brew.new_closedirectoryresponse)

            raise Exception, e

        req=p_brew.new_closedirectoryrequest()

        req.handle=handle

        res=self.sendbrewcommand(req, p_brew.new_closedirectoryresponse)

        for i in range(count):

            results.update(self.getfilesystem(dirs[i], recurse-1))

        return results

	def statfile(self, name):

        self.log('stat file '+name)

        req=p_brew.new_statfilerequest()

        req.filename=name

        res=self.sendbrewcommand(req, p_brew.new_statfileresponse)

        if res.flags==2:

            raise BrewNoSuchFileException

        if res.type==1:

            results={ 'name': name, 'type': 'file', 'size': res.size }

            if res.created_date==0:

                results['date']=(0, '')

            else:

                results['date']=(res.created_date, time.strftime("%x %X", time.localtime(res.created_date)))

        else:

            results={ 'name': name, 'type': 'directory' }

        return results

	"""Talk to a phone using the 'brew' protocol
    This class uses the new filesystem commands which are supported
    by newer qualcomm chipsets used in phones like the LG vx8100
    """

class  BrewProtocol (RealBrewProtocol) :
	"""This is just a wrapper class that allows the manipulation between
    RealBrewProtocol and DebugBrewProtocol classes.
    """
	    def __init__(self):

        phone_path=os.environ.get('PHONE_FS', None)

        if __debug__ and phone_path:

            print 'Debug Phone File System:',phone_path

            DebugBrewProtocol._fs_path=os.path.normpath(phone_path)

            self._update_base_class(self.__class__)

        elif __debug__ and getattr(self, "protocolclass", 0) and \
                getattr(self.protocolclass, "BREW_FILE_SYSTEM", 0) == 2:

            print '_set_new_brew', self.protocolclass

	def _update_base_class(self, klass):

        _bases=[]

        found=False

        for e in klass.__bases__:

            if e==RealBrewProtocol:

                _bases.append(DebugBrewProtocol)

                found=True

            else:

                _bases.append(e)

        if found:

            klass.__bases__=tuple(_bases)

        else:

            for e in _bases:

                self._update_base_class(e)

	def _set_new_brew(self, klass):

        _bases=[]

        found=False

        for e in klass.__bases__:

            if e==RealBrewProtocol:

                _bases.append(RealBrewProtocol2)

                found=True

            _bases.append(e)

        if found:

            klass.__bases__=tuple(_bases)

        else:

            for e in _bases:

                self._set_new_brew(e)

	"""This is just a wrapper class that allows the manipulation between
    RealBrewProtocol and DebugBrewProtocol classes.
    """

def formatpacketerrorlog(str, origdata, data, klass):

    hd=""

    if data is not None:

        hd="Data - "+`len(data)`+" bytes\n"

        if klass is not None:

            try:

                hd+="<#! %s.%s !#>\n" % (klass.__module__, klass.__name__)

            except:

                klass=klass.__class__

                hd+="<#! %s.%s !#>\n" % (klass.__module__, klass.__name__)

        hd+=common.datatohexstring(data)

    if origdata is not None:

        hd+="\nOriginal Data - "+`len(data)`+" bytes\n"+common.datatohexstring(origdata)

    return str+" "+hd

def brewbasename(str):

    "returns basename of str"

    if str.rfind("/")>0:

        return str[str.rfind("/")+1:]

    return str

def brewdirname(str):

    "returns dirname of str"

    if str.rfind("/")>0:

        return str[:str.rfind("/")]

    return str

class  SPURIOUSZERO (prototypes.BaseProtogenClass) :
	"""This is a special class used to consume the spurious zero in some p_brew.listfileresponse
    The three bytes are formatted as follows:
       - An optional 'null' byte (this class)
       - A byte specifying how long the directory name portion is, including trailing slash
       - A byte specifying the length of the whole name
       - The bytes of the filename (which includes the full directory name)
    Fun and games ensue because files in the root directory have a zero length directory
    name, so we have some heuristics to try and distinguish if the first byte is the
    spurious zero or not
    Also allow for zero length filenames.
    """
	    def __init__(self, *args, **kwargs):

        super(SPURIOUSZERO,self).__init__(*args, **kwargs)

        self._value=None

        if self._ismostderived(SPURIOUSZERO):

            self._update(args, kwargs)

	def _update(self, args, kwargs):

        super(SPURIOUSZERO, self)._update(args, kwargs)

        self._complainaboutunusedargs(SPURIOUSZERO, kwargs)

        if len(args):

            raise TypeError("Unexpected arguments "+`args`)

	def readfrombuffer(self, buf):

         self._bufferstartoffset=buf.getcurrentoffset()

         while True:  

             if buf.peeknextbyte()!=0:

                 self._value=-1

                 break

             if buf.peeknextbyte(1)==0:

                 if buf.howmuchmore()==2:

                     break

                 self._value=buf.getnextbyte() 

                 break

             all=buf.peeknextbytes(min(max(2+buf.peeknextbyte(1), 3+buf.peeknextbyte(2)), buf.howmuchmore()))

             ddirlen=ord(all[1])

             dfulllen=ord(all[2])

             if ddirlen<dfulllen and ddirlen<len(all)-3 and all[3+ddirlen-1]=='/':

                 self._value=buf.getnextbyte() 

                 break

             self._value=-2

             break

         self._bufferendoffset=buf.getcurrentoffset()

	def writetobuffer(self, buf):

        raise NotImplementedError()

	def packetsize(self):

         raise NotImplementedError()

	def getvalue(self):

        "Returns the string we are"

        if self._value is None:

            raise prototypes.ValueNotSetException()

        return self._value

	"""This is a special class used to consume the spurious zero in some p_brew.listfileresponse
    The three bytes are formatted as follows:
       - An optional 'null' byte (this class)
       - A byte specifying how long the directory name portion is, including trailing slash
       - A byte specifying the length of the whole name
       - The bytes of the filename (which includes the full directory name)
    Fun and games ensue because files in the root directory have a zero length directory
    name, so we have some heuristics to try and distinguish if the first byte is the
    spurious zero or not
    Also allow for zero length filenames.
    """
file_cache=None
class  EmptyFileCache (object) :
	def __init__(self, bitpim_path):

        self._path=None

        self._cache_file_name=None

        self._data={ 'file_index': 0 }

        self.esn=None

	def hit(self, file_name, datetime, data_len):

        return False

	def data(self, file_name):

        return None

	def add(self, file_name, datetime, data):

        pass

	def clear(self, file_name):

        pass

	def set_path(self, bitpim_path):

        try:

            print 'setting path to',`bitpim_path`

            if not bitpim_path:

                raise ValueError

            self.__class__=FileCache

            self._path=os.path.join(bitpim_path, 'cache')

            self._cache_file_name=os.path.join(self._path,
                                               self._cache_index_file_name)

            self._check_path()

            self._read_index()

            self._write_index()

        except:

            self.__class__=EmptyFileCache


class  FileCache (object) :
	_cache_index_file_name='index.idx'
	    current_version=1
	    def __init__(self, bitpim_path):

        self._path=os.path.join(bitpim_path, 'cache')

        self._cache_file_name=os.path.join(self._path,
                                           self._cache_index_file_name)

        self._data={ 'file_index': 0 }

        self.esn=None

        try:

            if not bitpim_path:

                raise ValueError

            self._check_path()

            self._read_index()

            self._write_index()

        except:

            self.__class__=EmptyFileCache

	def _check_path(self):

        try:

            os.makedirs(self._path)

        except:

            pass

        if not os.path.isdir(self._path):

            raise Exception("Bad cache directory: '"+self._path+"'")

	def _read_index(self):

        self._check_path()

        d={ 'result': {} }

        try:

            common.readversionedindexfile(self._cache_file_name, d, None,
                                          self.current_version)

            self._data.update(d['result'])

        except:

            print 'failed to read cache index file'

	def _write_index(self):

        self._check_path()

        common.writeversionindexfile(self._cache_file_name, self._data,
                                     self.current_version)

	def _entry(self, file_name):

        k=self._data.get(self.esn, None)

        if k:

            return k.get(file_name, None)

	def hit(self, file_name, datetime, data_len):

        try:

            e=self._entry(file_name)

            if e:

                return e['datetime'] and e['datetime']==datetime and \
                       e['size']==data_len

            return False

        except:

            if __debug__:

                raise

            return False

	def data(self, file_name):

        try:

            e=self._entry(file_name)

            if e:

                _data=file(os.path.join(self._path, e['cache']), 'rb').read()

                if len(_data)==e['size']:

                    return _data

        except IOError:

            return None

        except:

            if __debug__:

                raise

            return None

	def add(self, file_name, datetime, data):

        try:

            if self.esn:

                e=self._entry(file_name)

                if not e:

                    self._data.setdefault(self.esn, {})[file_name]={}

                    e=self._data[self.esn][file_name]

                    e['cache']='F%05d'%self._data['file_index']

                    self._data['file_index']+=1

                e['datetime']=datetime

                e['size']=len(data)

                _cache_file_name=os.path.join(self._path, e['cache'])

                try:

                    file(_cache_file_name, 'wb').write(data)

                    self._write_index()

                except IOError:

                    self._read_index()

        except:

            if __debug__:

                raise

	def clear(self, file_name):

        try:

            e=self._entry(file_name)

            if e:

                try:

                    os.remove(os.path.join(self._path, e['cache']))

                except:

                    pass

                del self._data[self.esn][file_name]

                self._write_index()

        except:

            if __debug__:

                raise

	def set_path(self, bitpim_path):

        try:

            print 'setting path to',`bitpim_path`

            if not bitpim_path:

                raise ValueError

            self.__class__=FileCache

            self._path=os.path.join(bitpim_path, 'cache')

            self._cache_file_name=os.path.join(self._path,
                                               self._cache_index_file_name)

            self._check_path()

            self._read_index()

            self._write_index()

        except:

            raise

            self.__class__=EmptyFileCache
	def sendpbcommand(self, request, responseclass, callsetmode=True, writemode=False, numsendretry=0, returnerror=False):

        if writemode:

            numretry=3

        else:

            numretry=0

        if callsetmode:

            self.setmode(self.MODEPHONEBOOK)

        buffer=prototypes.buffer()

        request.writetobuffer(buffer)

        data=buffer.getvalue()

        firsttwo=data[:2]

        data=common.pppescape(data+common.crcs(data))+common.pppterminator

        self.logdata("N400 phonebook request", data, request)

        isendretry=numsendretry

        while isendretry>=0:

            try:

                rdata=self.comm.writethenreaduntil(data, False, common.pppterminator, logreaduntilsuccess=False, numfailures=numretry)

                break

            except com_phone.modeignoreerrortypes:

                if isendretry>0:

                    self.log("Resending request packet...")

                    time.sleep(0.3)

                else:

                    self.comm.success=False

                    self.mode=self.MODENONE

                    self.raisecommsdnaexception("manipulating the phonebook")

                isendretry-=1

        self.comm.success=True

        origdata=rdata

        d=rdata.rfind(common.pppterminator,0,-1)

        if d>=0:

            self.log("Multiple N400 packets in data - taking last one starting at "+`d+1`)

            self.logdata("Original N400 data", origdata, None)

            rdata=rdata[d+1:]

        data=common.pppunescape(rdata)

        d=data.find(firsttwo)

        crc=data[-3:-1]

        crcok=False

        for i in range(0,d+1):

            trydata=data[i:-3]

            if common.crcs(trydata)==crc:

                crcok=True

                break

        if not crcok:

            self.logdata("first two",firsttwo, None)

            self.logdata("Original N400 data", origdata, None)

            self.logdata("Working on N400 data", data, None)

            raise common.CommsDataCorruption("N400 packet failed CRC check", self.desc)

        res=responseclass()

        if d>0:

            if d==i:

                self.log("Junk at beginning of N400 packet, data at "+`d`)

                self.logdata("Original N400 data", origdata, None)

                self.logdata("Working on N400 data", data, None)

            else:

                if returnerror:

                    res=self.protocolclass.sanyoerror()

                else:

                    self.log("N400 Error code "+`ord(data[0])`)

                    self.logdata("Samsung phonebook response", data, None)

                    raise N400CommandException(ord(data[0]))

        data=trydata

        self.logdata("sanyo phonebook response", data, responseclass)

        buffer=prototypes.buffer(data)

        res.readfrombuffer(buffer)

        return res

	def getphonebook(self, result):

        pbook={}

        reqname=self.protocolclass.phonebooknamerequest()

        reqnumbers=self.protocolclass.phonebooknumbersrequest()

        count = 0

        for i in range(2, 251):

            reqname.slot=i

            resname=self.sendpbcommand(reqname, self.protocolclass.phonebooknameresponse)

            if resname.entry.nonzeroifused:

                entry={}

                entry['serials']=[ {'sourcetype': self.serialsname,
                          'slot': i,
                          'sourceuniqueid': result['uniqueserial']} ]

                entry['names']=[{'full': resname.entry.name} ]

                entry['numbers'] = []

                for i in range(7):

                    numptr = resname.entry.numbers[i].pnumber

                    if numptr:

                        reqnumbers.slot=numptr

                        resnumbers=self.sendpbcommand(reqnumbers, self.protocolclass.phonebooknumbersresponse)

                        numhash={'number': resnumbers.entry.number, 'type': numbertypetab[i]}

                        if numptr==resname.entry.pspeed:

                            numhash['speeddial']=i

                        entry['numbers'].append(numhash)

                if resname.entry.pemail:

                    reqnumbers.slot=resname.entry.pemail

                    resnumbers=self.sendpbcommand(reqnumbers, self.protocolclass.phonebooknumbersresponse)

                    entry['emails']=[{'email': resnumbers.entry.number}]

                if resname.entry.purl:

                    reqnumbers.slot=resname.entry.purl

                    resnumbers=self.sendpbcommand(reqnumbers, self.protocolclass.phonebooknumbersresponse)

                    entry['urls']=[{'url': resnumbers.entry.number}]

                self.log("Read entry "+`i`+": "+resname.entry.name)

                pbook[count]=entry

                count+=1

        result['phonebook']=pbook

        return result

	def getcalendar(self, result):

        pbook={}

        result['calendar']=pbook

        return result

	def getwallpapers(self, results):

        pass

	def getringtones(self, results):

        pass

	"Talk to a Samsung SPH-N400 cell phone"

class  Profile (com_phone.Profile) :
	protocolclass=Phone.protocolclass
	    serialsname=Phone.serialsname
	    phone_manufacturer='SAMSUNG'
	    phone_model='SPH-N400'
	    usbids_usbtoserial=(
        ( 0x067b, 0x2303, None), 
        ( 0x0403, 0x6001, None), 
        ( 0x0731, 0x2003, None), 
        )
	    usbids=usbids_usbtoserial
	    deviceclasses=("serial",)
	    def __init__(self):

        com_phone.Profile.__init__(self)

	_supportedsyncs=(
        ('phonebook', 'read', None),
        )
示例#11
0
    def sendpbcommand(self, request, responseclass, callsetmode=True, writemode=False, numsendretry=0, returnerror=False):
        if writemode:
            numretry=3
        else:
            numretry=0
            
        if callsetmode:
            self.setmode(self.MODEPHONEBOOK)
        buffer=prototypes.buffer()

        request.writetobuffer(buffer, logtitle="Samsung phonebook request")
        data=buffer.getvalue()
        firsttwo=data[:2]
        data=common.pppescape(data+common.crcs(data))+common.pppterminator
        isendretry=numsendretry
        while isendretry>=0:
            try:
                rdata=self.comm.writethenreaduntil(data, False, common.pppterminator, logreaduntilsuccess=False, numfailures=numretry)
                break
            except com_phone.modeignoreerrortypes:
                if isendretry>0:
                    self.log("Resending request packet...")
                    time.sleep(0.3)
                else:
                    self.comm.success=False
                    self.mode=self.MODENONE
                    self.raisecommsdnaexception("manipulating the phonebook")
                isendretry-=1

        self.comm.success=True

        origdata=rdata
        # sometimes there is junk at the beginning, eg if the user
        # turned off the phone and back on again.  So if there is more
        # than one 7e in the escaped data we should start after the
        # second to last one
        d=rdata.rfind(common.pppterminator,0,-1)
        if d>=0:
            self.log("Multiple Samsung packets in data - taking last one starting at "+`d+1`)
            self.logdata("Original Samsung data", origdata, None)
            rdata=rdata[d+1:]

        # turn it back to normal
        data=common.pppunescape(rdata)

        # Sometimes there is other crap at the beginning.  But it might
        # be a Sanyo error byte.  So strip off bytes from the beginning
        # until the crc agrees, or we get to the first two bytes of the
        # request packet.
        d=data.find(firsttwo)
        crc=data[-3:-1]
        crcok=False
        for i in range(0,d+1):
            trydata=data[i:-3]
            if common.crcs(trydata)==crc:
                crcok=True
                break

        if not crcok:
            self.logdata("first two",firsttwo, None)
            self.logdata("Original Sanyo data", origdata, None)
            self.logdata("Working on Sanyo data", data, None)
            raise common.CommsDataCorruption("Sanyo packet failed CRC check", self.desc)

        res=responseclass()
        if d>0:
            if d==i:
                self.log("Junk at beginning of Sanyo packet, data at "+`d`)
                self.logdata("Original Sanyo data", origdata, None)
                self.logdata("Working on Sanyo data", data, None)
            else:
                if returnerror:
                    res=self.protocolclass.sanyoerror()
                else:
                    self.log("Sanyo Error code "+`ord(data[0])`)
                    self.logdata("sanyo phonebook response", data, None)
                    raise SanyoCommandException(ord(data[0]))
            
        data=trydata

        # parse data
        buffer=prototypes.buffer(data)
        res.readfrombuffer(buffer, logtitle="sanyo phonebook response")
        return res
	def sendpbcommand(self, request, responseclass, callsetmode=True, writemode=False, numsendretry=0, returnerror=False):

        if writemode:

            numretry=3

        else:

            numretry=0

        if callsetmode:

            self.setmode(self.MODEPHONEBOOK)

        buffer=prototypes.buffer()

        request.writetobuffer(buffer)

        data=buffer.getvalue()

        self.logdata("Sanyo phonebook request", data, request)

        firsttwo=data[:2]

        data=common.pppescape(data+common.crcs(data))+common.pppterminator

        isendretry=numsendretry

        while isendretry>=0:

            try:

                rdata=self.comm.writethenreaduntil(data, False, common.pppterminator, logreaduntilsuccess=False, numfailures=numretry)

                break

            except com_phone.modeignoreerrortypes:

                if isendretry>0:

                    self.log("Resending request packet...")

                    time.sleep(0.3)

                else:

                    self.comm.success=False

                    self.mode=self.MODENONE

                    self.raisecommsdnaexception("manipulating the phonebook")

                isendretry-=1

        self.comm.success=True

        origdata=rdata

        d=rdata.rfind(common.pppterminator,0,-1)

        if d>=0:

            self.log("Multiple Sanyo packets in data - taking last one starting at "+`d+1`)

            self.logdata("Original Sanyo data", origdata, None)

            rdata=rdata[d+1:]

        data=common.pppunescape(rdata)

        d=data.find(firsttwo)

        crc=data[-3:-1]

        crcok=False

        for i in range(0,d+1):

            trydata=data[i:-3]

            if common.crcs(trydata)==crc:

                crcok=True

                break

        if not crcok:

            self.logdata("first two",firsttwo, None)

            self.logdata("Original Sanyo data", origdata, None)

            self.logdata("Working on Sanyo data", data, None)

            raise common.CommsDataCorruption("Sanyo packet failed CRC check", self.desc)

        res=responseclass()

        if d>0:

            if d==i:

                self.log("Junk at beginning of Sanyo packet, data at "+`d`)

                self.logdata("Original Sanyo data", origdata, None)

                self.logdata("Working on Sanyo data", data, None)

            else:

                if returnerror:

                    res=self.protocolclass.sanyoerror()

                else:

                    self.log("Sanyo Error code "+`ord(data[0])`)

                    self.logdata("sanyo phonebook response", data, None)

                    raise SanyoCommandException(ord(data[0]))

        data=trydata

        self.logdata("sanyo phonebook response", data, responseclass)

        buffer=prototypes.buffer(data)

        res.readfrombuffer(buffer)

        return res

	def getfundamentals(self, results):

        """Gets information fundamental to interopating with the phone and UI."""

        print "HASRINGPICBUF=",self.protocolclass.HASRINGPICBUF

        self.log("Retrieving fundamental phone information")

        self.log("Phone serial number")

        results['uniqueserial']=sha.new(self.getfilecontents("nvm/$SYS.ESN")).hexdigest()

        self.getmediaindices(results)

        self.log("Fundamentals retrieved")

        return results

	def sanyosort(self, a, b):

        "Sanyo sort order.  Case insensitive, letters first"

        x=a[1]

        y=b[1]

        if(x[0:1].isalpha() and not y[0:1].isalpha()):

            return -1

        if(y[0:1].isalpha() and not x[0:1].isalpha()):

            return 1

        return cmp(x.lower(), y.lower())

	def getsms(self, result):

        gsms = {}

        self.log("Getting sms entries")

        req=self.protocolclass.messagerequest()

        for slot in range(self.protocolclass.NUMMESSAGESLOTS):

            req.slot=slot

            res=self.sendpbcommand(req, self.protocolclass.messageresponse)

            if res.entry.dunno4==2:

                entry=sms.SMSEntry()

                entry.folder=entry.Folder_Inbox

                entry.datetime="200%d%02d%02dT%02d%02d%02d" % ((res.entry.year, res.entry.month, res.entry.day, res.entry.hour,res.entry.minute, res.entry.second))

                if res.entry.read==17:

                    entry.read=1

                else:

                    entry.read=0

                entry._from=res.entry.phonenum

                entry.callback=res.entry.callback

                entry.subject="%d-%s-%s" % ((res.entry.counter, res.entry.phonenum, res.entry.message[:12]))

                self.log(res.entry.message[:8])

                if res.entry.priority==100:

                    entry.priority=sms.SMSEntry.Priority_Normal

                if res.entry.priority==200:

                    entry.priority=sms.SMSEntry.Priority_High

                entry.text=unicode(res.entry.message, errors='ignore')

                gsms[entry.id]=entry

                result['sms']=gsms

        return result

	def gettodo(self, result):

        gtodo = {}

        self.log("Getting todo entries")

        req=self.protocolclass.todorequest()

        for slot in range(self.protocolclass.NUMTODOSLOTS):

            req.slot=slot

            res=self.sendpbcommand(req, self.protocolclass.todoresponse)

            entry=todo.TodoEntry()

            if res.entry.flag:

                entry.summary=res.entry.todo

                if res.entry.priority==2:

                    entry.status=4

                if res.entry.priority==0:

                    entry.priority=5

                if res.entry.priority==1:

                    entry.priority=1

                gtodo[entry.id]=entry

                result['todo']=gtodo

        return result

	def getphonebook(self,result):

        pbook={}

        sortstuff = self.getsanyobuffer(self.protocolclass.pbsortbuffer)

        if self.protocolclass.HASRINGPICBUF:

            ringpic = self.getsanyobuffer(self.protocolclass.ringerpicbuffer)

        speedslot=[]

        speedtype=[]

        for i in range(self.protocolclass._NUMSPEEDDIALS):

            speedslot.append(sortstuff.speeddialindex[i].pbslotandtype & 0xfff)

            numtype=(sortstuff.speeddialindex[i].pbslotandtype>>12)-1

            if(numtype >= 0 and numtype <= len(self.numbertypetab)):

                speedtype.append(self.numbertypetab[numtype])

            else:

                speedtype.append("")

        numentries=sortstuff.slotsused

        self.log("There are %d entries" % (numentries,))

        count = 0 

        numcount = 0 

        numemail = 0 

        numurl = 0 

        res=self.protocolclass.phonebookentry()

        usedefaultnum = 'defaultnum' in res.getfields()

        print "usedefaultnum =",usedefaultnum

        req=self.protocolclass.phonebookslotrequest()

        for i in range(0, self.protocolclass._NUMPBSLOTS):

            if sortstuff.usedflags[i].used:

                req.slot = i

                res=self.sendpbcommand(req, self.protocolclass.phonebookslotresponse)

                self.log("Read entry "+`i`+" - "+res.entry.name)

                entry=self.extractphonebookentry(res.entry, result)

                for j in range(len(speedslot)):

                    if(speedslot[j]==req.slot):

                        for k in range(len(entry['numbers'])):

                            if(entry['numbers'][k]['type']==speedtype[j]):

                                entry['numbers'][k]['speeddial']=j+2

                                break

                if self.protocolclass.HASRINGPICBUF:

                    if ringpic.ringtones[i].ringtone>0:

                        try:

                            tone=result['ringtone-index'][ringpic.ringtones[i].ringtone]['name']

                        except:

                            tone=self.serialsname+"Index_"+`ringpic.ringtones[i].ringtone`

                        entry['ringtones']=[{'ringtone': tone, 'use': 'call'}]

                    if ringpic.wallpapers[i].wallpaper>0:

                        try:

                            paper=result['wallpaper-index'][ringpic.wallpapers[i].wallpaper]['name']

                        except:

                            paper=self.serialsname+"Index_"+`ringpic.wallpapers[i].wallpaper`

                        entry['wallpapers']=[{'wallpaper': paper, 'use': 'call'}]

                if usedefaultnum:

                    firsttype=res.entry.defaultnum-1

                    if firsttype < len(self.numbertypetab):

                        defaulttype=self.numbertypetab[firsttype]

                        k=0

                        for j in range(len(entry['numbers'])):

                            if entry['numbers'][j]['type'] == defaulttype:

                                k=j

                                break

                        if k>0:

                            exchange=entry['numbers'][k]

                            for kk in range(k,0,-1):

                                entry['numbers'][kk]=entry['numbers'][kk-1]

                            entry['numbers'][0]=exchange

                pbook[count]=entry 

                self.progress(count, numentries, res.entry.name)

                count+=1

                numcount+=len(entry['numbers'])

                if entry.has_key('emails'):

                    numemail+=len(entry['emails'])

                if entry.has_key('urls'):

                    numurl+=len(entry['urls'])

        self.progress(numentries, numentries, "Phone book read completed")

        self.log("Phone contains "+`count`+" contacts, "+`numcount`+" phone numbers, "+`numemail`+" Emails, "+`numurl`+" URLs")

        result['phonebook']=pbook

        return pbook

	def extractphonebookentry(self, entry, fundamentals):

        """Return a phonebook entry in BitPim format"""

        res={}

        res['serials']=[ {'sourcetype': self.serialsname, 'serial1': entry.slot, 'serial2': entry.slotdup,
                          'sourceuniqueid': fundamentals['uniqueserial']} ]

        res['names']=[ {'full': entry.name} ]

        if len(entry.email):

            res['emails']=[ {'email': entry.email} ]

        if len(entry.url):

            res['urls']=[ {'url': entry.url} ]

        res['flags']=[ {'secret': entry.secret } ]

        res['numbers']=[]

        numberindex = 0

        for type in self.numbertypetab:

            if len(entry.numbers[numberindex].number):

                res['numbers'].append({'number': entry.numbers[numberindex].number, 'type': type })

            numberindex+=1

        return res

	def _findmediaindex(self, index, name, pbentryname, type):

        if name is None:

            return 0

        for i in index:

            if index[i]['name']==name:

                return i

        pos=name.find('_')

        if(pos>=0):

            i=int(name[pos+1:])

            return i

        return 0

	def makeentry(self, entry, dict):

        e=self.protocolclass.phonebookentry()

        for k in entry:

            if k=='ringtones' or k=='wallpapers' or k=='numbertypes':

                continue

            if k=='numbers':

                for numberindex in range(self.protocolclass.NUMPHONENUMBERS):

                    enpn=self.protocolclass.phonenumber()

                    e.numbers.append(enpn)

                for i in range(len(entry[k])):

                    numberindex=entry['numbertypes'][i]

                    e.numbers[numberindex].number=entry[k][i]

                    e.numbers[numberindex].number_len=len(e.numbers[numberindex].number)

                continue

            setattr(e,k,entry[k])

        return e

	def writewait(self):

        """Loop until phone status indicates ready to write"""

        for i in range(100):

            req=self.protocolclass.statusrequest()

            res=self.sendpbcommand(req, self.protocolclass.statusresponse)

            if res.ready==res.readyvalue:

                return

            time.sleep(0.1)

        self.log("Phone did not transfer to ready to write state")

        self.log("Waiting a bit longer and trying anyway")

        return

	def savephonebook(self, data):

        newphonebook={}

        self.mode=self.MODENONE

        self.setmode(self.MODEBREW) 

        self.setmode(self.MODEPHONEBOOK)

        sortstuff=self.protocolclass.pbsortbuffer()

        ringpic=self.protocolclass.ringerpicbuffer()

        callerid=self.protocolclass.calleridbuffer()

        res=self.protocolclass.phonebookentry()

        usedefaultnum = 'defaultnum' in res.getfields()

        for i in range(self.protocolclass._NUMPBSLOTS):

            sortstuff.usedflags.append(0)

            sortstuff.firsttypes.append(0)

            sortstuff.sortorder.append(0xffff)

            sortstuff.sortorder2.append(0xffff)

            sortstuff.emails.append(0xffff)

            sortstuff.urls.append(0xffff)

            ringpic.ringtones.append(0)

            ringpic.wallpapers.append(0)

        for i in range(self.protocolclass._NUMSPEEDDIALS):

            sortstuff.speeddialindex.append(0xffff)

        for i in range(self.protocolclass._NUMLONGNUMBERS):

            sortstuff.longnumbersindex.append(0xffff)

        namemap=[]

        emailmap=[]

        urlmap=[]

        callerid.numentries=0

        pbook=data['phonephonebook'] 

        self.log("Putting phone into write mode")

        req=self.protocolclass.beginendupdaterequest()

        req.beginend=1 

        res=self.sendpbcommand(req, self.protocolclass.beginendupdateresponse, writemode=True)

        self.writewait()

        keys=pbook.keys()

        keys.sort()

        sortstuff.slotsused=len(keys)

        sortstuff.numemail=0

        sortstuff.numurl=0

        progresscur=0

        progressmax=len(keys)

        self.log("Writing %d entries to phone" % (len(keys),))

        nlongphonenumbers=0

        nonumbercount=0

        for ikey in keys:

            ii=pbook[ikey]

            slot=ii['slot'] 

            progresscur+=1

            self.progress(progresscur, progressmax, "Writing "+ii['name'])

            self.log("Writing entry "+`slot`+" - "+ii['name'])

            entry=self.makeentry(ii, data)

            if not usedefaultnum:

                delattr(entry,'defaultnum')

            req=self.protocolclass.phonebookslotupdaterequest()

            req.entry=entry

            res=self.sendpbcommand(req, self.protocolclass.phonebookslotresponse, writemode=True)

            entry=self.extractphonebookentry(entry, data)

            entry['ringtones']=[{'ringtone': ii['ringtone'], 'use': 'call'}]

            entry['wallpapers']=[{'wallpaper': ii['wallpaper'], 'use': 'call'}]

            sortstuff.usedflags[slot].used=1

            if(len(ii['numbers'])):

                sortstuff.firsttypes[slot].firsttype=min(ii['numbertypes'])+1

            else:

                if(len(ii['email'])):

                    sortstuff.firsttypes[slot].firsttype=8

                    nonumbercount+=1

                elif(len(ii['url'])):

                    sortstuff.firsttypes[slot].firsttype=9

                    nonumbercount+=1

                else:

                    sortstuff.firsttypes[slot].firsttype=0

            for i in range(len(ii['numbers'])):

                nindex=ii['numbertypes'][i]

                speeddial=ii['speeddials'][i]

                code=slot+((nindex+1)<<12)

                if(speeddial>=2 and speeddial<=self.protocolclass._NUMSPEEDDIALS+1):

                    sortstuff.speeddialindex[speeddial-2]=code

                    for k in range(len(entry['numbers'])):

                        if(entry['numbers'][k]['type']==nindex):

                            entry['numbers'][k]['speeddial']=speeddial

                            break

                if(callerid.numentries<callerid.maxentries):

                    phonenumber=ii['numbers'][i]

                    cidentry=self.makecidentry(phonenumber,slot,nindex)

                    callerid.items.append(cidentry)

                    callerid.numentries+=1

                    if(len(phonenumber)>self.protocolclass._LONGPHONENUMBERLEN):

                        if(nlongphonenumbers<self.protocolclass._NUMLONGNUMBERS):

                            sortstuff.longnumbersindex[nlongphonenumbers].pbslotandtype=code

            namemap.append((slot,ii['name']))

            if(len(ii['email'])):

                emailmap.append((slot,ii['email']))

                sortstuff.numemail+=1

            if(len(ii['url'])):

                urlmap.append((slot,ii['url']))

                sortstuff.numurl+=1

            ringpic.ringtones[slot].ringtone=self._findmediaindex(data['ringtone-index'], ii['ringtone'],ii['name'],'ringtone')

            ringpic.wallpapers[slot].wallpaper=self._findmediaindex(data['wallpaper-index'], ii['wallpaper'],ii['name'],'wallpaper')

            newphonebook[slot]=entry

        sortstuff.slotsused2=len(keys)-nonumbercount

        i=0

        j=0

        sortstuff.pbfirstletters=""

        namemap.sort(self.sanyosort)

        for (slot, name) in namemap:

            sortstuff.sortorder[i].pbslot=slot

            if sortstuff.firsttypes[slot].firsttype<=7:

                sortstuff.sortorder2[j].pbslot=slot

                j+=1

            if name:

                sortstuff.pbfirstletters+=name[0]

            else:

                sortstuff.pbfirstletters+=chr(0)

            i+=1

        i=0

        sortstuff.emailfirstletters=""

        emailmap.sort(self.sanyosort)

        for (slot, email) in emailmap:

            sortstuff.emails[i].pbslot=slot

            sortstuff.emailfirstletters+=email[0]

            i+=1

        i=0

        sortstuff.urlfirstletters=""

        urlmap.sort(self.sanyosort)

        for (slot, url) in urlmap:

            sortstuff.urls[i].pbslot=slot

            sortstuff.urlfirstletters+=url[0]

            i+=1

        self.sendsanyobuffer(sortstuff)

        if self.protocolclass.HASRINGPICBUF:

            self.sendsanyobuffer(ringpic)

        self.sendsanyobuffer(callerid)

        time.sleep(1.0)

        data['phonebook']=newphonebook

        del data['phonephonebook']

        data['rebootphone'] = 1

	def makecidentry(self, number, slot, nindex):

        "Prepare entry for caller ID lookup buffer"

        numstripped=re.sub("[^0-9PT#*]", "", number)

        numonly=re.sub("^(\\d*).*$", "\\1", numstripped)

        cidentry=self.protocolclass.calleridentry()

        cidentry.pbslotandtype=slot+((nindex+1)<<12)

        cidentry.actualnumberlen=len(numonly)

        cidentry.numberfragment=numonly[-10:]

        return cidentry

	def savewallpapers(self, results, merge):

        return self.savemedia('wallpapers', 'wallpaper-index', 'images', results, merge)

	def saveringtones(self, results, merge):

        return self.savemedia('ringtone', 'ringtone-index', 'ringers', results, merge)

	def savemedia(self, mediakey, mediaindexkey, mediatype, results, merge):

        """Actually saves out the media
        @param mediakey: key of the media (eg 'wallpapers' or 'ringtones')
                         Index of media in wallpaper or ringer tab
        @param mediaindexkey:  index key (eg 'wallpaper-index')
                         Index of media on the phone
        @param results: results dict
        """

        wp=results[mediakey].copy()

        wpi=results[mediaindexkey].copy()

        for k in wpi.keys():

            if wpi[k]['origin']=='builtin':

                del wpi[k]

        for w in wp.keys():

            name=wp[w]['name']

            if wp[w].get("origin", "")=='camera':

                self.log("Not transferring camera picture "+name+" to phone")

                del wp[w]

            else:

                for k in wpi.keys():

                    if name==wpi[k]['name']:

                        self.log("Not transferring "+name+" as it is already on the phone")

                        del wp[w]

                        break

        init={}

        init[mediatype]={}

        idx=0

        for w in wp.keys():

            idx-=1

            data=wp[w]['data']

            name=wp[w]['name']

            init[mediatype][idx]={'name': name, 'data': data}

        index=init[mediatype]

        errors=False

        for key in index:

            efile=index[key]['name']

            content=index[key]['data']

            if content is None:

                continue 

            if mediatype=='images':

                content = conversions.convertto8bitpng(content,16383)

            if not self.writesanyofile(efile, content):

                errors=True

        if errors:

            self.log("One or more files were rejected by the phone, due to")

            self.log("invalid file type (only PNG or MIDI are allowed), file")

            self.log("size too big, or too many ringers or wallpaper on the phone")

            self.log("See Sanyo Error Codes section of the Sanyh Phone Notes")

            self.log("in the help for more information")

        return results

	def writesanyofile(self, name, contents):

        start=time.time()

        self.log("Writing file '"+name+"' bytes "+`len(contents)`)

        desc="Writing "+name

        try:

            name=name[:name.index(".mid")]

        except:

            try:

                name=name[:name.index(".png")]

            except:

                pass

        if hasattr(self.protocolclass,"sanyomediathingyrequest"):

            req=self.protocolclass.sanyomediathingyrequest()

            req.faset = 0x10

            res=self.sendpbcommand(req, self.protocolclass.sanyomediathingyresponse)

            time.sleep(10.0)

            req.faset = 0x13

            res=self.sendpbcommand(req, self.protocolclass.sanyomediathingyresponse)

	req=self.protocolclass.sanyosendfilename()

	req.filename=name

        res=self.sendpbcommand(req, self.protocolclass.sanyosendfileresponse, returnerror=True)

        if 'errorcode' in res.getfields():

            if res.errorcode==0x65:

                self.alert("Please put your phone into PC Sync Mode", False)

            else:

                raise SanyoCommandException(res.errorcode)

            waitcount=120

            while waitcount>0:

                time.sleep(1.0)

                res=self.sendpbcommand(req, self.protocolclass.sanyosendfileresponse, returnerror=True)

                if not 'errorcode' in res.getfields():

                    break

                waitcount-=1

            if waitcount==0:

                raise SanyoCommandException(res.errorcode)

        req=self.protocolclass.sanyosendfilesize()

        req.filesize=len(contents)

        self.sendpbcommand(req, self.protocolclass.sanyosendfileresponse)

        req=self.protocolclass.sanyosendfilefragment()

        packetsize=req.payloadsize

        offset=0

        count=0

        numblocks=len(contents)/packetsize+1

        for offset in range(0, len(contents), packetsize):

            count+=1

            if count % 5==0:

                self.progress(count,numblocks,desc)

            req.header.command=offset

            req.data=contents[offset:min(offset+packetsize,len(contents))]

            self.sendpbcommand(req, self.protocolclass.sanyosendfileresponse, writemode=True, returnerror=True)

            if 'errorcode' in res.getfields():

                self.log(name+" not written due to error code "+`res.errorcode`)

                return False

        req=self.protocolclass.sanyosendfileterminator()

        try:

            res=self.sendpbcommand(req, self.protocolclass.sanyosendfileresponse, writemode=True, returnerror=True)

            if 'errorcode' in res.getfields():

                self.log(name+" not written due to error code "+`res.errorcode`)

                return False

        except:

            self.log("Exception on writing terminator for file "+name)

            self.log("Continuing...")

        end=time.time()

        if end-start>3:

            self.log("Wrote "+`len(contents)`+" bytes at "+`int(len(contents)/(end-start))`+" bytes/second")

        return True

	def getcalendar(self,result):

        calres={}

        progressmax=self.protocolclass._NUMEVENTSLOTS+self.protocolclass._NUMCALLALARMSLOTS

        req=self.protocolclass.eventrequest()

        count=0

        try:

            reqflag=self.protocolclass.eventslotinuserequest()

        except:

            reqflag=0

        for i in range(0, self.protocolclass._NUMEVENTSLOTS):

            self.progress(i,progressmax,"Events")

            if reqflag:

                reqflag.slot=i

                resflag=self.sendpbcommand(reqflag, self.protocolclass.eventslotinuseresponse)

                if not resflag.flag:

                    continue

            req.slot = i

            res=self.sendpbcommand(req, self.protocolclass.eventresponse)

            if not reqflag:

                if not res.entry.flag:

                    continue

            self.log("Read calendar event "+`i`+" - "+res.entry.eventname+", alarm ID "+`res.entry.ringtone`)

            entry=bpcalendar.CalendarEntry()

            entry.changeserial=res.entry.serial

            entry.description=res.entry.eventname

            entry.location=res.entry.location

            starttime=res.entry.start

            entry.start=self.decodedate(starttime)

            entry.end=self.decodedate(res.entry.end)

            repeat=self._calrepeatvalues[res.entry.period]

            entry.repeat = self.makerepeat(repeat,entry.start)

            if res.entry.alarm==0xffffffff:

                entry.alarm=res.entry.alarmdiff/60

            else:

                alarmtime=res.entry.alarm

                entry.alarm=(starttime-alarmtime)/60

            ringtone=res.entry.ringtone

            if ringtone in self.calendar_tonerange:

                ringtone-=self.calendar_toneoffset

            if ringtone!=self.calendar_defaultringtone:

                if result['ringtone-index'].has_key(ringtone):

                    entry.ringtone=result['ringtone-index'][ringtone]['name']

            entry.snoozedelay=0

            calres[entry.id]=entry

            count+=1

        req=self.protocolclass.callalarmrequest()

        for i in range(0, self.protocolclass._NUMCALLALARMSLOTS):

            self.progress(self.protocolclass._NUMEVENTSLOTS,progressmax,"Call Alarms")

            req.slot=i

            res=self.sendpbcommand(req, self.protocolclass.callalarmresponse)

            if res.entry.flag and res.entry.date:

                self.log("Read call alarm entry "+`i`+" - "+res.entry.phonenum+", alarm ID "+`res.entry.ringtone`)

                entry=bpcalendar.CalendarEntry()

                entry.changeserial=res.entry.serial

                entry.description=res.entry.phonenum

                starttime=res.entry.date

                entry.start=self.decodedate(starttime)

                entry.end=entry.start

                repeat=self._calrepeatvalues[res.entry.period]

                entry.repeat = self.makerepeat(repeat,entry.start)

                entry.alarm=0

                if res.entry.ringtone!=self.calendar_defaultcaringtone:

                    entry.ringtone=result['ringtone-index'][res.entry.ringtone]['name']

                entry.snoozedelay=0

                calres[entry.id]=entry

                count+=1

        result['calendar']=calres

        return result

	def makerepeat(self, repeatword, startdate):

        if repeatword is None:

            repeat_entry=None

        else:

            repeat_entry=bpcalendar.RepeatEntry()

            if repeatword=='daily':

                repeat_entry.repeat_type=repeat_entry.daily

                repeat_entry.interval=1

            elif repeatword=='monfri':

                repeat_entry.repeat_type=repeat_entry.daily

                repeat_entry.interval=0

            elif repeatword=='weekly':

                repeat_entry.repeat_type=repeat_entry.weekly

                repeat_entry.interval=1

                dow=datetime.date(*startdate[:3]).isoweekday()%7

                repeat_entry.dow=1<<dow

            elif repeatword=='monthly':

                repeat_entry.repeat_type=repeat_entry.monthly

            else:

                repeat_entry.repeat_type=repeat_entry.yearly

        return repeat_entry

	def savecalendar(self, dict, merge):

        cal=dict['calendar']

        newcal={}

        keys=cal.keys()

        zonedif=time.mktime(time.gmtime(0))-time.mktime(time.localtime(0))

        try:

            reqflag=self.protocolclass.eventslotinuseupdaterequest()

        except:

            reqflag=0

        eventslot=0

        callslot=0

        progressmax=self.protocolclass._NUMEVENTSLOTS+self.protocolclass._NUMCALLALARMSLOTS

        for k in keys:

            entry=cal[k]

            descloc=entry.description

            self.progress(eventslot+callslot, progressmax, "Writing "+descloc)

            rp=entry.repeat

            if rp is None:

                repeat=0

            else:

                repeatname=None

                if rp.repeat_type==rp.daily:

                    repeatname='daily'

                elif rp.repeat_type==rp.weekly:

                    repeatname='weekly'

                elif rp.repeat_type==rp.monthly:

                    repeatname='monthly'

                elif rp.repeat_type==rp.yearly:

                    repeatname='yearly'

                for k,v in self._calrepeatvalues.items():

                    if repeatname==v:

                        repeat=k

                        break

                    if repeatname is None:

                        self.log(descloc+": Repeat type "+`entry.repeat`+" not valid for this phone")

                        repeat=0

            phonenum=re.sub("\-","",descloc)

            now=time.mktime(time.localtime(time.time()))-zonedif

            if(phonenum.isdigit()):  

                self.log("Write calendar call alarm slot "+`callslot`+ " - "+descloc)

                e=self.protocolclass.callalarmentry()

                e.slot=callslot

                e.phonenum=phonenum

                e.phonenum_len=len(e.phonenum)

                timearray=list(entry.start)+[0,0,0,0]

                starttimelocal=time.mktime(timearray)-zonedif

                if(starttimelocal<now and repeat==0):

                    e.flag=2 

                else:

                    e.flag=1 

                e.date=starttimelocal-self._sanyoepochtounix

                e.datedup=e.date

                e.phonenumbertype=0

                e.phonenumberslot=0

                e.name="" 

                e.name_len=len(e.name)

                e.ringtone=self.calendar_defaultcaringtone

                print "Setting ringtone "+`e.ringtone`

                req=self.protocolclass.callalarmupdaterequest()

                callslot+=1

                respc=self.protocolclass.callalarmresponse

            else: 

                self.log("Write calendar event slot "+`eventslot`+ " - "+descloc)

                e=self.protocolclass.evententry()

                e.slot=eventslot

                slashpos=descloc.find('/')

                if(slashpos >= 0):

                    eventname=descloc[0:slashpos]

                    location=descloc[slashpos+1:]

                else:

                    eventname=descloc

                    location=''

                e.eventname=descloc

                e.eventname_len=len(e.eventname)

                e.location=entry.location

                e.location_len=len(e.location)

                timearray=list(entry.start)+[0,0,0,0]

                starttimelocal=time.mktime(timearray)-zonedif

                e.start=starttimelocal-self._sanyoepochtounix

                try:

                    timearray=list(entry.end)+[0,0,0,0]

                    endtimelocal=time.mktime(timearray)-zonedif

                    e.end=endtimelocal-self._sanyoepochtounix

                except: 

                    e.end=e.start+60 

                alarmdiff=entry.alarm

                if alarmdiff<0:

                    alarmdiff=0

                alarmdiff=max(alarmdiff,0)*60

                e.alarmdiff=alarmdiff

                e.alarm=starttimelocal-self._sanyoepochtounix-alarmdiff

                if reqflag:

                    reqflag.slot=eventslot

                    if(e.alarm+self._sanyoepochtounix<now and repeat==0):

                        reqflag.flag=4 

                    else:

                        reqflag.flag=1 

                    res=self.sendpbcommand(reqflag, self.protocolclass.eventslotinuseresponse)

                else:

                    if(starttimelocal<now and repeat==0):

                        e.flag=2 

                    else:

                        e.flag=1 

                try:

                    timearray=list(entry.end)+[0,0,0,0]

                    endtimelocal=time.mktime(timearray)-zonedif

                    e.end=endtimelocal-self._sanyoepochtounix

                except: 

                    e.end=e.start+60 

                e.ringtone=self.calendar_defaultringtone

                print "Setting ringtone "+`e.ringtone`

                req=self.protocolclass.eventupdaterequest()

                eventslot+=1

                respc=self.protocolclass.eventresponse

            e.period=repeat

            e.dom=entry.start[2]

            if entry.id>=0 and entry.id<256:

                e.serial=entry.id

            else:

                e.serial=0

            req.entry=e

            res=self.sendpbcommand(req, respc, writemode=True)

        if reqflag:

            req=reqflag

            req.flag=0

        else:

            e=self.protocolclass.evententry()

            e.flag=0 

            e.eventname=""

            e.eventname_len=0

            e.location=""

            e.location_len=0

            e.start=0

            e.end=0

            e.period=0

            e.dom=0

            e.ringtone=0

            e.alarm=0

            e.alarmdiff=0

            req=self.protocolclass.eventupdaterequest()

            req.entry=e

        for eventslot in range(eventslot,self.protocolclass._NUMEVENTSLOTS):

            self.progress(eventslot+callslot, progressmax, "Writing unused")

            self.log("Write calendar event slot "+`eventslot`+ " - Unused")

            if reqflag:

                req.slot=eventslot

            else:

                req.entry.slot=eventslot

            res=self.sendpbcommand(req, self.protocolclass.eventresponse, writemode=True)

        e=self.protocolclass.callalarmentry()

        e.flag=0 

        e.name=""

        e.name_len=0

        e.phonenum=""

        e.phonenum_len=0

        e.date=0

        e.datedup=0

        e.period=0

        e.dom=0

        e.ringtone=0

        e.phonenumbertype=0

        e.phonenumberslot=0

        req=self.protocolclass.callalarmupdaterequest()

        req.entry=e

        for callslot in range(callslot,self.protocolclass._NUMCALLALARMSLOTS):

            self.progress(eventslot+callslot, progressmax, "Writing unused")

            self.log("Write calendar call alarm slot "+`callslot`+ " - Unused")

            req.entry.slot=callslot

            res=self.sendpbcommand(req, self.protocolclass.callalarmresponse, writemode=True)

        self.progress(progressmax, progressmax, "Calendar write done")

        dict['rebootphone'] = True

        return dict

	def getcallhistory(self, result):

        res={}

        self._readhistory(self.protocolclass.OUTGOING,'Outgoing',res)

        self._readhistory(self.protocolclass.MISSED,'Missed',res)

        self._readhistory(self.protocolclass.INCOMING,'Incoming',res)

        result['call_history']=res

        return result

	def _readhistory(self, type, folder, res):

        req=self.protocolclass.historyrequest()

        req.type=type

        for slot in range(self.protocolclass.NUMCALLHISTORY):

            req.slot=slot

            call=self.sendpbcommand(req, self.protocolclass.historyresponse)

            if call.entry.phonenum=='' and call.entry.name=='':

                continue

            entry=call_history.CallHistoryEntry()

            entry.folder=folder

            entry.name=call.entry.name

            entry.number=call.entry.phonenum

            entry.datetime=((call.entry.date))

            res[entry.id]=entry

	def decodedate(self,val):

        """Unpack 32 bit value into date/time
        @rtype: tuple
        @return: (year, month, day, hour, minute)
        """

        return list(time.gmtime(val+self._sanyoepochtounix)[:5])

	_calrepeatvalues={
        0: None,
        1: 'daily',
        2: 'weekly',
        3: 'monthly',
        4: 'yearly'
        }
	"Talk to a Sanyo Sprint Phone such as SCP-4900, SCP-5300, or SCP-8100"

def phonize(str):

    """Convert the phone number into something the phone understands
    All digits, P, T, * and # are kept, everything else is removed"""

    return re.sub("[^0-9PT#*]", "", str)

class  Profile (com_phone.Profile) :
	serialsname='sanyo'
	    WALLPAPER_WIDTH=120
	    WALLPAPER_HEIGHT=128
	    OVERSIZE_PERCENTAGE=100
	    MAX_WALLPAPER_BASENAME_LENGTH=19
	    WALLPAPER_FILENAME_CHARS="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .`~!@#$%^&()-_=+[{]};\'"
	    WALLPAPER_CONVERT_FORMAT="png"
	    MAX_RINGTONE_BASENAME_LENGTH=19
	    RINGTONE_FILENAME_CHARS="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .`~!@#$%^&()-_=+[{]};\'"
	    usbids=( ( 0x0474, 0x0701, 1),  
        )
	    deviceclasses=("modem",)
	    BP_Calendar_Version=3
	    def __init__(self):

        self.numbertypetab=numbertypetab

        com_phone.Profile.__init__(self)

	_supportedsyncs=(
        ('phonebook', 'read', None),  
        ('calendar', 'read', None),   
        ('phonebook', 'write', 'OVERWRITE'),  
        ('calendar', 'write', 'OVERWRITE'),   
        ('wallpaper', 'write', 'MERGE'),
        ('ringtone', 'write', 'MERGE'),
        ('call_history', 'read', None),
        ('sms', 'read', None),
        )
	    def convertphonebooktophone(self, helper, data):

        "Converts the data to what will be used by the phone"

        results={}

        slotsused={}

        for pbentry in data['phonebook']:

            entry=data['phonebook'][pbentry]

            serial1=helper.getserial(entry.get('serials', []), self.serialsname, data['uniqueserial'], 'serial1', -1)

            if(serial1 >= 0 and serial1 < self.protocolclass._NUMPBSLOTS):

                slotsused[serial1]=1

        lastunused=0 

        for pbentry in data['phonebook']:

            e={} 

            entry=data['phonebook'][pbentry] 

            try:

                try:

                    e['name']=helper.getfullname(entry.get('names', []),1,1,16)[0]

                except:

                    e['name']=''

                e['name_len']=len(e['name'])

                serial1=helper.getserial(entry.get('serials', []), self.serialsname, data['uniqueserial'], 'serial1', -1)

                if(serial1 >= 0 and serial1 < self.protocolclass._NUMPBSLOTS):

                    e['slot']=serial1

                else:  

                    while(slotsused.has_key(lastunused)):

                        lastunused+=1

                        if(lastunused >= self.protocolclass._NUMPBSLOTS):

                            raise helper.ConversionFailed()

                    e['slot']=lastunused

                    slotsused[lastunused]=1

                e['slotdup']=e['slot']

                e['email']=helper.makeone(helper.getemails(entry.get('emails', []),0,1,self.protocolclass._MAXEMAILLEN), "")

                e['email_len']=len(e['email'])

                e['url']=helper.makeone(helper.geturls(entry.get('urls', []), 0,1,self.protocolclass._MAXEMAILLEN), "")

                e['url_len']=len(e['url'])

                numbers=helper.getnumbers(entry.get('numbers', []),0,7)

                e['numbertypes']=[]

                e['numbers']=[]

                e['speeddials']=[]

                unusednumbers=[] 

                typesused={}

                defaultnum=0

                for num in numbers:

                    typename=num['type']

                    if(typesused.has_key(typename)):

                        unusednumbers.append(num)

                        continue

                    typesused[typename]=1

                    for typenum,tnsearch in enumerate(self.numbertypetab):

                        if typename==tnsearch:

                            if defaultnum==0:

                                defaultnum=typenum+1

                            number=phonize(num['number'])

                            if len(number)>self.protocolclass._MAXNUMBERLEN: 

                                number=number[:self.protocolclass._MAXNUMBERLEN]

                            e['numbers'].append(number)

                            if(num.has_key('speeddial')):

                                e['speeddials'].append(num['speeddial'])

                            else:

                                e['speeddials'].append(-1)

                            e['numbertypes'].append(typenum)

                            break

                trytype=len(self.numbertypetab)

                for num in unusednumbers:

                    while trytype>0:

                        trytype-=1

                        if not typesused.has_key(self.numbertypetab[trytype]):

                            break

                    else:

                        break

                    if defaultnum==0:

                        defaultnum=trytype+1

                    number=phonize(num['number'])

                    if len(number)>self.protocolclass._MAXNUMBERLEN: 

                        number=number[:self.protocolclass._MAXNUMBERLEN]

                    e['numbers'].append(number)

                    e['numbertypes'].append(trytype)

                    if(num.has_key('speeddial')):

                        e['speeddials'].append(num['speeddial'])

                    else:

                        e['speeddials'].append(-1)

                if defaultnum==0:

                    if e['url_len'] > 0:

                        defaultnum=8

                    elif e['email_len'] > 0:

                        defaultnum=9

                e['ringtone']=helper.getringtone(entry.get('ringtones', []), 'call', None)

                e['wallpaper']=helper.getwallpaper(entry.get('wallpapers', []), 'call', None)

                e['secret']=helper.getflag(entry.get('flags', []), 'secret', False)

                e['defaultnum']=defaultnum

                results[pbentry]=e

            except helper.ConversionFailed:

                print "No Free Slot for "+e['name']

                continue

        data['phonephonebook']=results

        return data


class  Phone (SanyoPhonebook,com_phone.Phone,com_brew.BrewProtocol) :
	"Talk to a Sanyo Sprint Phone such as SCP-4900, SCP-5300, or SCP-8100"
	    desc="Sanyo"
	    imagelocations=()
	    ringtonelocations=()
	    builtinimages=()
	    builtinringtones=()
	    def __init__(self, logtarget, commport):

        "Call all the contructors and sets initial modes"

        com_phone.Phone.__init__(self, logtarget, commport)

        com_brew.BrewProtocol.__init__(self)

        SanyoPhonebook.__init__(self)

        self.log("Attempting to contact phone")

        self.mode=self.MODENONE

	getwallpapers=None
	    getringtones=None
	"Talk to a Sanyo Sprint Phone such as SCP-4900, SCP-5300, or SCP-8100"
示例#13
0
    def sendpbcommand(
        self, request, responseclass, callsetmode=True, writemode=False, numsendretry=0, returnerror=False
    ):
        if writemode:
            numretry = 3
        else:
            numretry = 0

        if callsetmode:
            self.setmode(self.MODEPHONEBOOK)
        buffer = prototypes.buffer()

        request.writetobuffer(buffer, logtitle="Samsung phonebook request")
        data = buffer.getvalue()
        firsttwo = data[:2]
        data = common.pppescape(data + common.crcs(data)) + common.pppterminator
        isendretry = numsendretry
        while isendretry >= 0:
            try:
                rdata = self.comm.writethenreaduntil(
                    data, False, common.pppterminator, logreaduntilsuccess=False, numfailures=numretry
                )
                break
            except com_phone.modeignoreerrortypes:
                if isendretry > 0:
                    self.log("Resending request packet...")
                    time.sleep(0.3)
                else:
                    self.comm.success = False
                    self.mode = self.MODENONE
                    self.raisecommsdnaexception("manipulating the phonebook")
                isendretry -= 1

        self.comm.success = True

        origdata = rdata
        # sometimes there is junk at the beginning, eg if the user
        # turned off the phone and back on again.  So if there is more
        # than one 7e in the escaped data we should start after the
        # second to last one
        d = rdata.rfind(common.pppterminator, 0, -1)
        if d >= 0:
            self.log("Multiple Samsung packets in data - taking last one starting at " + ` d + 1 `)
            self.logdata("Original Samsung data", origdata, None)
            rdata = rdata[d + 1 :]

        # turn it back to normal
        data = common.pppunescape(rdata)

        # Sometimes there is other crap at the beginning.  But it might
        # be a Sanyo error byte.  So strip off bytes from the beginning
        # until the crc agrees, or we get to the first two bytes of the
        # request packet.
        d = data.find(firsttwo)
        crc = data[-3:-1]
        crcok = False
        for i in range(0, d + 1):
            trydata = data[i:-3]
            if common.crcs(trydata) == crc:
                crcok = True
                break

        if not crcok:
            self.logdata("first two", firsttwo, None)
            self.logdata("Original Sanyo data", origdata, None)
            self.logdata("Working on Sanyo data", data, None)
            raise common.CommsDataCorruption("Sanyo packet failed CRC check", self.desc)

        res = responseclass()
        if d > 0:
            if d == i:
                self.log("Junk at beginning of Sanyo packet, data at " + ` d `)
                self.logdata("Original Sanyo data", origdata, None)
                self.logdata("Working on Sanyo data", data, None)
            else:
                if returnerror:
                    res = self.protocolclass.sanyoerror()
                else:
                    self.log("Sanyo Error code " + ` ord(data[0]) `)
                    self.logdata("sanyo phonebook response", data, None)
                    raise SanyoCommandException(ord(data[0]))

        data = trydata

        # parse data
        buffer = prototypes.buffer(data)
        res.readfrombuffer(buffer, logtitle="sanyo phonebook response")
        return res