vx8100 fixes
"Simon C" <[email protected]>
| Newsgroups | gmane.comp.mobile.bitpim.devel |
|---|---|
| Message-ID | <000001c5c18a$ca796c50$6400a8c0@HOME> |
There is a brew command to list directories one at a time. I replaced the existing function with this new command. The comments in the existing code look like this has been tried before without success, so I added it to the brew protocol file but defined an attribute to access this new way of reading the filesystem so it would not affect anything except the 8100. I did test on the 4400 and the 6100 and it worked OK. This fixes the problem with too many directories causing the filebrowser to crash. Also fixed bogus calender entry crash and allowed underscores and hyphens in wallpaper and ringtone names. New code attached with diffs. Simon > -----Original Message----- > From: [email protected] > [mailto:[email protected]]On Behalf Of Simon C > Sent: Saturday, September 24, 2005 2:29 PM > To: Bitpim-Devel (E-mail) > Subject: [BitPim-devel] brew protocol problem > > > I've managed to reproduce a problem reported by 8100 bitpim > users when the > brew directory has too many files in. > It is due to too many directories in the filesystem, files > themselves are > not a problem > > This is a protocol trace of bitpim obtaining the contents of the brew > directory: > > 14:18:07.311 LG-VX8100: brew request Data - 8 bytes > <#! p_brew.listdirectoriesrequest !#> > 00000000 59 02 05 62 72 65 77 00 Y..brew. > > 14:18:07.391 LG-VX8100: brew response Data - 263 bytes > <#! p_brew.listdirectoriesresponse !#> > 00000000 59 02 00 1a 00 fc 00 62 72 65 77 2f 31 30 35 31 > Y......brew/1051 > 00000010 32 00 62 72 65 77 2f 31 31 37 39 37 00 62 72 65 > 2.brew/11797.bre > 00000020 77 2f 31 32 34 31 34 00 62 72 65 77 2f 31 32 35 > w/12414.brew/125 > 00000030 31 33 00 62 72 65 77 2f 31 33 31 33 36 00 62 72 > 13.brew/13136.br > 00000040 65 77 2f 31 33 34 37 38 00 62 72 65 77 2f 31 33 > ew/13478.brew/13 > 00000050 39 32 31 00 62 72 65 77 2f 31 33 39 32 32 00 62 > 921.brew/13922.b > 00000060 72 65 77 2f 31 36 34 35 32 00 62 72 65 77 2f 31 > rew/16452.brew/1 > 00000070 36 34 35 34 00 62 72 65 77 2f 31 38 31 36 39 00 > 6454.brew/18169. > 00000080 62 72 65 77 2f 33 33 31 34 00 62 72 65 77 2f 33 > brew/3314.brew/3 > 00000090 35 35 32 00 62 72 65 77 2f 33 36 38 32 00 62 72 > 552.brew/3682.br > 000000a0 65 77 2f 33 39 35 39 00 62 72 65 77 2f 33 39 36 > ew/3959.brew/396 > 000000b0 36 00 62 72 65 77 2f 34 39 37 32 00 62 72 65 77 > 6.brew/4972.brew > 000000c0 2f 35 36 39 31 00 62 72 65 77 2f 38 34 35 31 00 > /5691.brew/8451. > 000000d0 62 72 65 77 2f 38 38 33 36 00 62 72 65 77 2f 39 > brew/8836.brew/9 > 000000e0 36 33 39 00 62 72 65 77 2f 64 6f 77 6e 6c 6f 61 > 639.brew/downloa > 000000f0 64 00 62 72 65 77 2f 65 6e 00 62 72 65 77 2f 65 > d.brew/en.brew/e > 00000100 73 00 00 72 65 00 00 s..re.. > > The response looks ok, the number of directories is 0x1A > according to the > response, but the actual number of directories listed in the > packet is 2 > less. Obviously the packet has overflowed. Bitpim ignores the > packet length > 0xFC and also read the spurious characters "re" at the end of > the packets as > a directory. This results in either a crash or directories > with garbage > names listed, trying to list the contents of these directoris > results in a > crash. > > The directories were created by downloading loads of apps > (free demos). > > Has anyone seen this behavior before? Does anyone know what > happens with > other brew phones when the number of directory is too long to > list in a > single packet. > > > Simon > > > > ------------------------------------------------------- > SF.Net email is sponsored by: > Tame your development challenges with Apache's Geronimo App Server. > Download it for free - -and be entered to win a 42" plasma tv > or your very > own Sony(tm)PSP. Click here to play: > http://sourceforge.net/geronimo.php > _______________________________________________ > BitPim-devel mailing list > [email protected] > https://lists.sourceforge.net/lists/listinfo/bitpim-devel
com_lgvx8100.py
(text/plain, 18.6 KB)
### BITPIM ### ### Copyright (C) 2003-2005 Roger Binns <[email protected]> ### Copyright (C) 2005 Simon Capper <[email protected]> ### ### This program is free software; you can redistribute it and/or modify ### it under the terms of the BitPim license as detailed in the LICENSE file. ### """Communicate with the LG VX8100 cell phone The VX8100 is substantially similar to the VX7000 but also supports video. """ # standard modules import re import time import cStringIO import sha # my modules import common import commport import copy import com_lgvx4400 import p_brew import p_lgvx8100 import com_lgvx7000 import com_brew import com_phone import com_lg import prototypes import bpcalendar import call_history import sms import memo from prototypes import * class Phone(com_lgvx7000.Phone): "Talk to the LG VX8100 cell phone" desc="LG-VX8100" protocolclass=p_lgvx8100 serialsname='lgvx8100' builtinringtones= ('Low Beep Once', 'Low Beeps', 'Loud Beep Once', 'Loud Beeps', 'VZW Default Ringtone') + \ tuple(['Ringtone '+`n` for n in range(1,11)]) + \ ('No Ring',) ringtonelocations= ( # type index-file size-file directory-to-use lowest-index-to-use maximum-entries type-major ( 'ringers', 'dload/my_ringtone.dat', 'dload/my_ringtonesize.dat', 'brew/16452/lk/mr', 100, 150, 1), ) builtinwallpapers = () # none wallpaperlocations= ( ( 'images', 'dload/image.dat', 'dload/imagesize.dat', 'brew/16452/mp', 100, 50, 0), ) def __init__(self, logtarget, commport): com_lgvx4400.Phone.__init__(self, logtarget, commport) self.mode=self.MODENONE def getfundamentals(self, results): """Gets information fundamental to interopating with the phone and UI. Currently this is: - 'uniqueserial' a unique serial number representing the phone - 'groups' the phonebook groups - 'wallpaper-index' map index numbers to names - 'ringtone-index' map index numbers to ringtone names This method is called before we read the phonebook data or before we write phonebook data. """ # use a hash of ESN and other stuff (being paranoid) self.log("Retrieving fundamental phone information") self.log("Phone serial number") results['uniqueserial']=sha.new(self.getfilecontents("nvm/$SYS.ESN")).hexdigest() # now read groups self.log("Reading group information") buf=prototypes.buffer(self.getfilecontents("pim/pbgroup.dat")) g=self.protocolclass.pbgroups() g.readfrombuffer(buf) self.logdata("Groups read", buf.getdata(), g) groups={} for i in range(len(g.groups)): if len(g.groups[i].name): # sometimes have zero length names groups[i]={'name': g.groups[i].name } results['groups']=groups self.getwallpaperindices(results) self.getringtoneindices(results) self.log("Fundamentals retrieved") return results def savegroups(self, data): groups=data['groups'] keys=groups.keys() keys.sort() g=self.protocolclass.pbgroups() for k in keys: e=self.protocolclass.pbgroup() e.name=groups[k]['name'] g.groups.append(e) buffer=prototypes.buffer() g.writetobuffer(buffer) self.logdata("New group file", buffer.getvalue(), g) self.writefile("pim/pbgroup.dat", buffer.getvalue()) def getmemo(self, result): # read the memo file try: buf=prototypes.buffer(self.getfilecontents("sch/neomemo.dat")) text_memo=self.protocolclass.textmemofile() text_memo.readfrombuffer(buf) res={} for m in text_memo.items: entry=memo.MemoEntry() entry.text=m.text entry.set_date_isostr("%d%02d%02dT%02d%02d00" % ((m.memotime))) res[entry.id]=entry except com_brew.BrewNoSuchFileException: res={} result['memo']=res return result def savememo(self, result, merge): text_memo=self.protocolclass.textmemofile() memo_dict=result.get('memo', {}) keys=memo_dict.keys() keys.sort() text_memo.itemcount=len(keys) for k in keys: entry=self.protocolclass.textmemo() entry.text=memo_dict[k].text t=time.strptime(memo_dict[k].date, '%b %d, %Y %H:%M') entry.memotime=(t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min) text_memo.items.append(entry) buf=prototypes.buffer() text_memo.writetobuffer(buf) self.writefile("sch/neomemo.dat", buf.getvalue()) return result def getcalendar(self,result): res={} # Read exceptions file first try: buf=prototypes.buffer(self.getfilecontents("sch/newschexception.dat")) ex=self.protocolclass.scheduleexceptionfile() ex.readfrombuffer(buf) self.logdata("Calendar exceptions", buf.getdata(), ex) exceptions={} for i in ex.items: try: exceptions[i.pos].append( (i.year,i.month,i.day) ) except KeyError: exceptions[i.pos]=[ (i.year,i.month,i.day) ] except com_brew.BrewNoSuchFileException: exceptions={} # Now read schedule try: buf=prototypes.buffer(self.getfilecontents("sch/newschedule.dat")) if len(buf.getdata())<3: # file is empty, and hence same as non-existent raise com_brew.BrewNoSuchFileException() sc=self.protocolclass.schedulefile() self.logdata("Calendar", buf.getdata(), sc) sc.readfrombuffer(buf) for event in sc.events: # the vx8100 has a bad entry when the calender is empty # stop processing the calender when we hit this record if event.pos==0: #invalid entry break entry=bpcalendar.CalendarEntry() entry.description=event.description entry.start=event.start entry.end=event.end entry.vibrate=~(event.alarmindex_vibrate&0x1) # vibarate bit is inverted in phone 0=on, 1=off entry.repeat = self.makerepeat(event.repeat) min=event.alarmminutes hour=event.alarmhours if min==0x64 or hour==0x64: entry.alarm=None # no alarm set else: entry.alarm=hour*60+min entry.ringtone=result['ringtone-index'][event.ringtone]['name'] entry.snoozedelay=0 # check for exceptions and remove them if event.repeat[3] and exceptions.has_key(event.pos): for year, month, day in exceptions[event.pos]: entry.suppress_repeat_entry(year, month, day) res[entry.id]=entry assert sc.numactiveitems==len(res) except com_brew.BrewNoSuchFileException: pass # do nothing if file doesn't exist result['calendar']=res return result def makerepeat(self, repeat): # get all the variables out of the repeat tuple # and convert into a bpcalender RepeatEntry type,dow,interval,exceptions=repeat if type==0: repeat_entry=None else: repeat_entry=bpcalendar.RepeatEntry() if type==1: #daily repeat_entry.repeat_type=repeat_entry.daily repeat_entry.interval=interval elif type==5: #'monfri' repeat_entry.repeat_type=repeat_entry.daily repeat_entry.interval=0 elif type==2: #'weekly' repeat_entry.repeat_type=repeat_entry.weekly repeat_entry.dow=dow repeat_entry.interval=interval elif type==3: #'monthly' repeat_entry.repeat_type=repeat_entry.monthly repeat_entry.interval=interval repeat_entry.dow=0 elif type==6: #'monthly' #Xth Y day (e.g. 2nd friday each month) repeat_entry.repeat_type=repeat_entry.monthly repeat_entry.interval=interval #X repeat_entry.dow=dow #Y else: # =4 'yearly' repeat_entry.repeat_type=repeat_entry.yearly return repeat_entry def savecalendar(self, dict, merge): # ::TODO:: # what will be written to the files eventsf=self.protocolclass.schedulefile() exceptionsf=self.protocolclass.scheduleexceptionfile() # what are we working with cal=dict['calendar'] newcal={} #sort into start order, makes it possible to see if the calendar has changed keys=[(x.start, k) for k,x in cal.items()] keys.sort() # number of entries eventsf.numactiveitems=len(keys) pos=1 contains_alarms=False # play with each entry for (_,k) in keys: # entry is what we will return to user entry=cal[k] data=self.protocolclass.scheduleevent() data.pos=eventsf.packetsize() data.description=entry.description data.start=entry.start data.end=entry.end self.setalarm(entry, data) data.ringtone=0 for i in dict['ringtone-index']: if dict['ringtone-index'][i]['name']==entry.ringtone: data.ringtone=i # check for exceptions and add them to the exceptions list exceptions=0 if entry.repeat!=None: if data.end[:3]==entry.no_end_date: data.end=(2100, 12, 31)+data.end[3:] for i in entry.repeat.suppressed: de=self.protocolclass.scheduleexception() de.pos=data.pos de.day=i.date.day de.month=i.date.month de.year=i.date.year exceptions=1 exceptionsf.items.append(de) if entry.repeat != None: data.repeat=(self.getrepeattype(entry, exceptions)) else: data.repeat=((0,0,0,0)) data.unknown1=0 data.unknown2=0 if data.alarmindex_vibrate!=1: # if alarm set contains_alarms=True # put entry in nice shiny new dict we are building entry=copy.copy(entry) newcal[data.pos]=entry eventsf.events.append(data) buf=prototypes.buffer() eventsf.writetobuffer(buf) # We check the existing calender as changes require a reboot for the alarms # to work properly, also no point writing the file if it is not changing if buf.getvalue()!=self.getfilecontents("sch/newschedule.dat"): self.logdata("Writing calendar", buf.getvalue(), eventsf) self.writefile("sch/newschedule.dat", buf.getvalue()) if contains_alarms: self.log("Your phone has to be rebooted due to the calendar changing") dict["rebootphone"]=True else: self.log("Phone calendar unchanged, no update required") buf=prototypes.buffer() exceptionsf.writetobuffer(buf) self.logdata("Writing calendar exceptions", buf.getvalue(), exceptionsf) self.writefile("sch/newschexception.dat", buf.getvalue()) # fix passed in dict dict['calendar']=newcal return dict def getrepeattype(self, entry, exceptions): #convert the bpcalender type into vx8100 type repeat_entry=bpcalendar.RepeatEntry() if entry.repeat.repeat_type==repeat_entry.monthly: dow=entry.repeat.dow if entry.repeat.dow==0: # set interval for month type 4 to start day of month, (required by vx8100) interval=entry.start[2] type=3 else: interval=entry.repeat.interval type=6 elif entry.repeat.repeat_type==repeat_entry.daily: dow=entry.repeat.dow interval=entry.repeat.interval if entry.repeat.interval==0: type=5 else: type=1 elif entry.repeat.repeat_type==repeat_entry.weekly: dow=entry.repeat.dow interval=entry.repeat.interval type=2 elif entry.repeat.repeat_type==repeat_entry.yearly: # set interval to start day of month, (required by vx8100) interval=entry.start[2] # set dow to start month, (required by vx8100) dow=entry.start[1] type=4 return (type, dow, interval, exceptions) def setalarm(self, entry, data): # vx8100 only allows certain repeat intervals, adjust to fit, it also stores an index to the interval if entry.alarm>=2880: entry.alarm=2880 data.alarmminutes=0 data.alarmhours=48 data.alarmindex_vibrate=0x10 elif entry.alarm>=1440: entry.alarm=1440 data.alarmminutes=0 data.alarmhours=24 data.alarmindex_vibrate=0xe elif entry.alarm>=120: entry.alarm=120 data.alarmminutes=0 data.alarmhours=2 data.alarmindex_vibrate=0xc elif entry.alarm>=60: entry.alarm=60 data.alarmminutes=0 data.alarmhours=1 data.alarmindex_vibrate=0xa elif entry.alarm>=15: entry.alarm=15 data.alarmminutes=15 data.alarmhours=0 data.alarmindex_vibrate=0x8 elif entry.alarm>=10: entry.alarm=10 data.alarmminutes=10 data.alarmhours=0 data.alarmindex_vibrate=0x6 elif entry.alarm>=5: entry.alarm=5 data.alarmminutes=5 data.alarmhours=0 data.alarmindex_vibrate=0x4 elif entry.alarm>=0: entry.alarm=0 data.alarmminutes=0 data.alarmhours=0 data.alarmindex_vibrate=0x2 else: # no alarm data.alarmminutes=0x64 data.alarmhours=0x64 data.alarmindex_vibrate=1 # set the vibrate bit if data.alarmindex_vibrate > 1 and entry.vibrate==0: data.alarmindex_vibrate+=1 return my_model='VX8100' def getphoneinfo(self, phone_info): self.log('Getting Phone Info') try: s=self.getfilecontents('brew/version.txt') if s[:6]=='VX8100': phone_info.append('Model:', "VX8100") req=p_brew.firmwarerequest() res=self.sendbrewcommand(req, self.protocolclass.firmwareresponse) phone_info.append('Firmware Version:', res.firmware) s=self.getfilecontents("nvm/$SYS.ESN")[85:89] txt='%02X%02X%02X%02X'%(ord(s[3]), ord(s[2]), ord(s[1]), ord(s[0])) phone_info.append('ESN:', txt) txt=self.getfilecontents("nvm/nvm/nvm_cdma")[180:190] phone_info.append('Phone Number:', txt) except: pass return parentprofile=com_lgvx7000.Profile class Profile(parentprofile): protocolclass=Phone.protocolclass serialsname=Phone.serialsname BP_Calendar_Version=3 phone_manufacturer='LG Electronics Inc' phone_model='VX8100' WALLPAPER_WIDTH=176 WALLPAPER_HEIGHT=184 MAX_WALLPAPER_BASENAME_LENGTH=32 WALLPAPER_FILENAME_CHARS="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 ._-@" WALLPAPER_CONVERT_FORMAT="jpg" MAX_RINGTONE_BASENAME_LENGTH=32 RINGTONE_FILENAME_CHARS="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 ._-@" # there is an origin named 'aod' - no idea what it is for except maybe # 'all other downloads' # the vx8100 supports bluetooth for connectivity to the PC, define the "bluetooth_mgd_id" # to enable bluetooth discovery during phone detection # the bluetooth address starts with LG's the three-octet OUI, all LG phone # addresses start with this, it provides a way to identify LG bluetooth devices # during phone discovery # OUI=Organizationally Unique Identifier # see http://standards.ieee.org/regauth/oui/index.shtml for more info bluetooth_mfg_id="001256" # the 8100 doesn't have seperate origins - they are all dumped in "images" imageorigins={} imageorigins.update(common.getkv(parentprofile.stockimageorigins, "images")) def GetImageOrigins(self): return self.imageorigins # our targets are the same for all origins imagetargets={} imagetargets.update(common.getkv(parentprofile.stockimagetargets, "wallpaper", {'width': 176, 'height': 184, 'format': "JPEG"})) imagetargets.update(common.getkv(parentprofile.stockimagetargets, "pictureid", {'width': 176, 'height': 184, 'format': "JPEG"})) imagetargets.update(common.getkv(parentprofile.stockimagetargets, "outsidelcd", {'width': 96, 'height': 80, 'format': "JPEG"})) imagetargets.update(common.getkv(parentprofile.stockimagetargets, "fullscreen", {'width': 176, 'height': 220, 'format': "JPEG"})) def GetTargetsForImageOrigin(self, origin): return self.imagetargets def __init__(self): parentprofile.__init__(self) _supportedsyncs=( ('phonebook', 'read', None), # all phonebook reading ('calendar', 'read', None), # all calendar reading ('wallpaper', 'read', None), # all wallpaper reading ('ringtone', 'read', None), # all ringtone reading ('call_history', 'read', None),# all call history list reading ('sms', 'read', None), # all SMS list reading ('memo', 'read', None), # all memo list reading ('phonebook', 'write', 'OVERWRITE'), # only overwriting phonebook ('calendar', 'write', 'OVERWRITE'), # only overwriting calendar ('wallpaper', 'write', 'MERGE'), # merge and overwrite wallpaper ('wallpaper', 'write', 'OVERWRITE'), ('ringtone', 'write', 'MERGE'), # merge and overwrite ringtone ('ringtone', 'write', 'OVERWRITE'), ('sms', 'write', 'OVERWRITE'), # all SMS list writing ('memo', 'write', 'OVERWRITE'), # all memo list writing )
com_brew.py
(text/plain, 35.3 KB)
### BITPIM ### ### Copyright (C) 2003-2004 Roger Binns <[email protected]> ### ### This program is free software; you can redistribute it and/or modify ### it under the terms of the BitPim license as detailed in the LICENSE file. ### ### $Id: com_brew.py,v 1.45 2005/09/19 22:23:45 djpham Exp $ """Implements the "Brew" filesystem protocol""" import os import p_brew import time import cStringIO import com_phone import prototypes import common class BrewNotSupported(Exception): """This phone not supported""" pass class BrewCommandException(Exception): def __init__(self, errnum, str=None): if str is None: str="Brew Error 0x%02x" % (errnum,) Exception.__init__(self, str) self.errnum=errnum class BrewNoMoreEntriesException(BrewCommandException): def __init__(self, errnum=0x1c): BrewCommandException.__init__(self, errnum, "No more directory entries") class BrewNoSuchDirectoryException(BrewCommandException): def __init__(self, errnum=0x08): BrewCommandException.__init__(self, errnum, "No such directory") class BrewNoSuchFileException(BrewCommandException): def __init__(self, errnum=0x06): BrewCommandException.__init__(self, errnum, "No such file") class BrewBadPathnameException(BrewCommandException): def __init__(self, errnum=0x1a): BrewCommandException.__init__(self, errnum, "Bad pathname") class BrewFileLockedException(BrewCommandException): def __init__(self, errnum=0x0b): BrewCommandException.__init__(self, errnum, "File is locked") class BrewNameTooLongException(BrewCommandException): def __init__(self, errnum=0x0d): BrewCommandException.__init__(self, errnum, "Name is too long") class BrewDirectoryExistsException(BrewCommandException): def __init__(self, errnum=0x07): BrewCommandException.__init__(self, errnum, "Directory already exists") modeignoreerrortypes=com_phone.modeignoreerrortypes+(BrewCommandException,common.CommsDataCorruption) class DebugBrewProtocol: """ Emulate a phone file system using a local file system. This is used when you may not have access to a physical phone, but have a copy of its file system. """ _fs_path='' def __init__(self): pass def getfirmwareinformation(self): self.log("Getting firmware information") def explore0c(self): self.log("Trying stuff with command 0x0c") def offlinerequest(self, reset=False): self.log("Taking phone offline") if reset: self.log("Resetting phone") def modemmoderequest(self): self.log("Attempting to put phone in modem mode") def mkdir(self, name): self.log("Making directory '"+name+"'") os.mkdir(os.path.join(self._fs_path, name)) 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])) # basically mkdir -p except: pass def rmdir(self,name): self.log("Deleting directory '"+name+"'") os.rmdir(os.path.join(self._fs_path, name)) def rmfile(self,name): self.log("Deleting file '"+name+"'") os.remove(os.path.join(self._fs_path, 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 getfilesystem(self, dir="", recurse=0): results={} self.log("Listing dir '"+dir+"'") _pwd=os.path.join(self._fs_path, dir) for _root,_dir,_file in os.walk(_pwd): break for f in _file: _stat=os.stat(os.path.join(_pwd, f)) _date=_stat[8] _name=dir+'/'+f results[_name]={ 'name': _name, 'type': 'file', 'size': _stat[6], 'date': (_date, time.strftime("%x %X", time.gmtime(_date))) } for d in _dir: results[d]={ 'name': d, 'type': 'directory' } if recurse>0: results.update(self.getfilesystem(os.path.join(dir, d), recurse-1)) return results def statfile(self, name): _stat=os.stat(os.path.join(self._fs_path, name)) _date=_stat[8] results={ 'name': name, 'type': 'file', 'size': _stat[6], 'date': (_date, time.strftime("%x %X", time.gmtime(_date))) } return results def writefile(self, name, contents): self.log("Writing file '"+name+"' bytes "+`len(contents)`) file(os.path.join(self._fs_path, name), 'wb').write(contents) def getfilecontents(self, name, use_cache=False): self.log("Getting file contents '"+name+"'") try: return file(os.path.join(self._fs_path, name), 'rb').read() except: raise BrewNoSuchFileException def _setmodebrew(self): self.log('_setmodebrew: in mode BREW') return True def sendbrewcommand(self, request, responseclass, callsetmode=True): raise NotImplemetedError def log(self, s): print s def logdata(self, s, data, klass=None): print s class RealBrewProtocol: "Talk to a phone using the 'brew' protocol" MODEBREW="modebrew" brewterminator="\x7e" # phone uses Jan 1, 1980 as epoch. Python uses Jan 1, 1970. This is difference # plus a fudge factor of 4 days, 17 hours for no reason I can find _brewepochtounix=315532800+406800 def __init__(self): pass ## phone_path=os.environ.get('PHONE_FS', None) ## if phone_path: ## print 'Debug Phone File System:',phone_path ## DebugBrewProtocol._fs_path=os.path.normpath(phone_path) ## if self.__class__==BrewProtocol: ## self.__class__=DebugBrewProtocol ## else: ## self._update_base_class(self.__class__) ## def _update_base_class(self, klass): ## _bases=[] ## found=False ## for e in klass.__bases__: ## if e==BrewProtocol: ## _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 getfirmwareinformation(self): self.log("Getting firmware information") req=p_brew.firmwarerequest() res=self.sendbrewcommand(req, p_brew.firmwareresponse) def explore0c(self): self.log("Trying stuff with command 0x0c") req=p_brew.testing0crequest() res=self.sendbrewcommand(req, p_brew.testing0cresponse) def offlinerequest(self, reset=False): req=p_brew.setmoderequest() req.request=1 self.log("Taking phone offline") self.sendbrewcommand(req, p_brew.setmoderesponse) if reset: req=p_brew.setmoderequest() req.request=2 self.log("Resetting phone") self.sendbrewcommand(req, p_brew.setmoderesponse) def modemmoderequest(self): # Perhaps we should modify sendbrewcommand to have an option to # not be picky about response. 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) # Response could be text or a packet self.comm.readsome(numchars=5) self.mode=self.MODENONE # Probably should add a modem mode 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])) # basically mkdir -p 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 getfilesystem(self, dir="", recurse=0): if getattr(self.protocolclass, 'BREW_FILESYSTEM_TYPE', 0) == 1: return self.getfilesystem_type1(dir, recurse) results={} self.log("Listing dir '"+dir+"'") # self.log("file listing 0x0b command") for i in xrange(10000): try: req=p_brew.listfilerequest() req.entrynumber=i req.dirname=dir 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: # invalid date - see SF bug #833517 results[res.filename]['date']=(0, "") except BrewNoMoreEntriesException: break # i tried using 0x0a command to list subdirs but that fails when # mingled with 0x0b commands req=p_brew.listdirectoriesrequest() req.dirname=dir res=self.sendbrewcommand(req, p_brew.listdirectoriesresponse) for i in range(res.numentries): subdir=res.items[i].subdir # sometimes subdir can already include the parent directory f=subdir.rfind("/") if f>=0: subdir=subdir[f+1:] if len(dir): subdir=dir+"/"+subdir results[subdir]={ 'name': subdir, 'type': 'directory' } if recurse>0: results.update(self.getfilesystem(subdir, recurse-1)) return results def getfilesystem_type1(self, dir="", recurse=0): results={} self.log("Listing dir '"+dir+"'") req=p_brew.listdirectoriesrequest() req.dirname=dir for i in xrange(10000): try: req=p_brew.listdirectoryrequest() req.entrynumber=i req.dirname=dir res=self.sendbrewcommand(req,p_brew.listdirectoryresponse) # sometimes subdir can already include the parent directory 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' } if recurse>0: results.update(self.getfilesystem(subdir, recurse-1)) except BrewNoMoreEntriesException: break # self.log("file listing 0x0b command") for i in xrange(10000): try: req=p_brew.listfilerequest() req.entrynumber=i req.dirname=dir 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: # invalid date - see SF bug #833517 results[res.filename]['date']=(0, "") except BrewNoMoreEntriesException: break return results def statfile(self, name): # return the status of the file 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 } 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: # invalid date - see SF bug #833517 results['date']=(0, '') return results except: # something happened, we don't have any info on this file if __debug__: raise return None 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) # do remaining blocks 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() # give the download speed if we got a non-trivial amount of data 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 class DirCache: """This is a class that lets you do various filesystem manipulations and it remembers the data. Typical usage would be if you make changes to files (adding, removing, rewriting) and then have to keep checking if files exist, add sizes etc. This class saves the hassle of rereading the directory every single time. Note that it will only see changes you make via this class. If you go directly to the Brew class then those won't be seen. """ def __init__(self, target): "@param target: where operations should be done after recording them here" self.__target=target self.__cache={} def rmfile(self, filename): res=self.__target.rmfile(filename) node=self._getdirectory(brewdirname(filename)) if node is None: # we didn't have it return del node[brewbasename(filename)] return res def stat(self, filename): node=self._getdirectory(brewdirname(filename), ensure=True) return node.get(brewbasename(filename), None) def readfile(self, filename): node=self._getdirectory(brewdirname(filename), ensure=True) file=node.get(brewbasename(filename), None) if file is None: raise BrewNoSuchFileException() # This class only populates the 'data' portion of the file obj when needed data=file.get('data', None) if data is None: data=self.__target.getfilecontents(filename) file['data']=data return data def writefile(self, filename, contents): res=self.__target.writefile(filename, contents) node=self._getdirectory(brewdirname(filename), ensure=True) # we can't put the right date in since we have no idea # what the timezone (or the time for that matter) on the # phone is stat=node.get(brewbasename(filename), {'name': filename, 'type': 'file', 'date': (0, "")}) stat['size']=len(contents) stat['data']=contents node[brewbasename(filename)]=stat return res def _getdirectory(self, dirname, ensure=False): if not ensure: return self.__cache.get(dirname, None) node=self.__cache.get(dirname, None) if node is not None: return node node={} fs=self.__target.getfilesystem(dirname) for filename in fs.keys(): node[brewbasename(filename)]=fs[filename] self.__cache[dirname]=node return node 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 # send AT$CDMG at various speeds 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: # some issue during writing such as user pulling cable out self.mode=self.MODENONE self.comm.shouldloop=True raise try: # if we got OK back then it was success if self.comm.readsome().find("OK")>=0: break except modeignoreerrortypes: self.log("No response to setting QCDMG mode") # verify if we are in DM 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: # we logged above, and below 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 # 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 packets in data - taking last one starting at "+`d+1`) self.logdata("Original 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(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:] # take off crc and terminator 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) # log it self.logdata("brew response", data, responseclass) if firsttwo=="Y\x0c" and data==firsttwo: # we are getting an echo - the modem port has been selected # instead of diagnostics port 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) # look for errors 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() raise BrewCommandException(err) # parse data buffer=prototypes.buffer(data) res=responseclass() try: res.readfrombuffer(buffer) except: # we had an exception so log the data even if protocol log # view is not available self.log(formatpacketerrorlog("Error decoding response", origdata, data, responseclass)) raise return res class BrewProtocol(RealBrewProtocol): """This is just a wrapper class that allows the manipulation between RealBrewProtocol and DebugBrewProtocol classes. """ def __init__(self): # if the env var PHONE_FS is set, we're debugging! phone_path=os.environ.get('PHONE_FS', None) if __debug__ and phone_path: print 'Debug Phone File System:',phone_path # we probably need to do this only once for the whole class, # but what the heck! DebugBrewProtocol._fs_path=os.path.normpath(phone_path) self._update_base_class(self.__class__) def _update_base_class(self, klass): # update the RealBrewProtocol class to DebugBrewProtocol one. _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 formatpacketerrorlog(str, origdata, data, klass): # copied from guiwidgets.LogWindow.logdata 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 """ 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() # there are several cases this code has to deal with # # The data is ordered like this: # # optional spurious zero (sz) # dirlen # fulllen # name # # These are the various possibilities. The first two # are a file in the root directory (dirlen=0), with the other # two being a file in a subdirectory (dirlen>0). fulllen # is always >0 # # A: dirlen=0 fulllen name # B: sz dirlen=0 fulllen name # C: dirlen>0 fulllen name # D: sz dirlen>0 fulllen name while True: # this is just used so we can break easily # CASE C if buf.peeknextbyte()!=0: self._value=-1 break # CASE B if buf.peeknextbyte(1)==0: self._value=buf.getnextbyte() # consume sz break # A & D are harder to distinguish since they both consist of a zero # followed by non-zero. Consequently we examine the data for # consistency all=buf.peeknextbytes(min(max(2+buf.peeknextbyte(1), 3+buf.peeknextbyte(2)), buf.howmuchmore())) # are the values consistent for D? 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() # consume sz break # case C, do nothing 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 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 # set the paths 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: # something's wrong, disable caching 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: # entry does not exist, create a new one 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 # entry exists, just update the data 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: # failed to write to cache file, drop this entry self._read_index() except: if __debug__: raise def clear(self, file_name): try: # clear this entry if it exists e=self._entry(file_name) if e: try: # remove the cache file os.remove(os.path.join(self._path, e['cache'])) except: pass # and remove the entry 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 # set the paths 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
com_lgvx8100.py.diff
(application/octet-stream, 982 B)
Index: com_lgvx8100.py
===================================================================
RCS file: /cvsroot/bitpim/bitpim/com_lgvx8100.py,v
retrieving revision 1.7
diff -u -r1.7 com_lgvx8100.py
--- com_lgvx8100.py 24 Sep 2005 03:18:24 -0000 1.7
+++ com_lgvx8100.py 24 Sep 2005 17:39:12 -0000
@@ -431,11 +431,11 @@
WALLPAPER_WIDTH=176
WALLPAPER_HEIGHT=184
MAX_WALLPAPER_BASENAME_LENGTH=32
- WALLPAPER_FILENAME_CHARS="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 ."
+ WALLPAPER_FILENAME_CHARS="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 ._-@"
WALLPAPER_CONVERT_FORMAT="jpg"
MAX_RINGTONE_BASENAME_LENGTH=32
- RINGTONE_FILENAME_CHARS="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 ."
+ RINGTONE_FILENAME_CHARS="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 ._-@"
# there is an origin named 'aod' - no idea what it is for except maybe
# 'all other downloads'
com_brew.py.diff
(application/octet-stream, 2.7 KB)
Index: com_brew.py
===================================================================
RCS file: /cvsroot/bitpim/bitpim/com_brew.py,v
retrieving revision 1.45
diff -u -r1.45 com_brew.py
--- com_brew.py 19 Sep 2005 22:23:45 -0000 1.45
+++ com_brew.py 25 Sep 2005 03:15:50 -0000
@@ -278,8 +278,9 @@
self.rmfile(k)
self.rmdir(path)
-
def getfilesystem(self, dir="", recurse=0):
+ if getattr(self.protocolclass, 'BREW_FILESYSTEM_TYPE', 0) == 1:
+ return self.getfilesystem_type1(dir, recurse)
results={}
self.log("Listing dir '"+dir+"'")
@@ -324,6 +325,56 @@
results.update(self.getfilesystem(subdir, recurse-1))
return results
+ def getfilesystem_type1(self, dir="", recurse=0):
+ results={}
+
+ self.log("Listing dir '"+dir+"'")
+
+ req=p_brew.listdirectoriesrequest()
+ req.dirname=dir
+
+ for i in xrange(10000):
+ try:
+ req=p_brew.listdirectoryrequest()
+ req.entrynumber=i
+ req.dirname=dir
+ res=self.sendbrewcommand(req,p_brew.listdirectoryresponse)
+ # sometimes subdir can already include the parent directory
+ 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' }
+ if recurse>0:
+ results.update(self.getfilesystem(subdir, recurse-1))
+ except BrewNoMoreEntriesException:
+ break
+
+ # self.log("file listing 0x0b command")
+ for i in xrange(10000):
+ try:
+ req=p_brew.listfilerequest()
+ req.entrynumber=i
+ req.dirname=dir
+ 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:
+ # invalid date - see SF bug #833517
+ results[res.filename]['date']=(0, "")
+
+ except BrewNoMoreEntriesException:
+ break
+
+ return results
+
def statfile(self, name):
# return the status of the file
try:
p_lgvx8100.p
(application/octet-stream, 9.7 KB) - not displayed
p_lgvx8100.p.diff
(application/octet-stream, 425 B)
Index: p_lgvx8100.p =================================================================== RCS file: /cvsroot/bitpim/bitpim/p_lgvx8100.p,v retrieving revision 1.7 diff -u -r1.7 p_lgvx8100.p --- p_lgvx8100.p 12 Sep 2005 05:23:42 -0000 1.7 +++ p_lgvx8100.p 25 Sep 2005 03:07:16 -0000 @@ -30,6 +30,8 @@ SPEEDDIALINDEX=1 MAXCALENDARDESCRIPTION=32 +BREW_FILESYSTEM_TYPE=1 + SMS_CANNED_MAX_ITEMS=18 SMS_CANNED_MAX_LENGTH=101
p_brew.p
(application/octet-stream, 6.1 KB) - not displayed
p_brew.p.diff
(application/octet-stream, 976 B)
Index: p_brew.p
===================================================================
RCS file: /cvsroot/bitpim/bitpim/p_brew.p,v
retrieving revision 1.11
diff -u -r1.11 p_brew.p
--- p_brew.p 8 Aug 2005 23:54:30 -0000 1.11
+++ p_brew.p 25 Sep 2005 03:26:37 -0000
@@ -107,6 +107,18 @@
1 UINT dirnamelen "which portion of the filename is the directory, including the last /"
* STRING {'terminator': None, 'pascal': True} filename
+PACKET listdirectoryrequest:
+ "This gets one directory entry (directory only) at a time"
+ * requestheader {'command': 0x0a} +header
+ 4 UINT entrynumber
+ * STRING {'terminator': 0, 'pascal': True} dirname
+
+PACKET listdirectoryresponse:
+ * responseheader header
+ 4 UINT entrynumber
+ 17 UNKNOWN unknown1 "probably the directory attributes"
+ * STRING {'terminator': None, 'pascal': True} subdir
+
PACKET statfilerequest:
"Get the status of the file"
* requestheader { 'command': 7 } +header