VX-8700 support update

Nathan Hjelm <[email protected]>
Newsgroups gmane.comp.mobile.bitpim.devel
Message-ID <[email protected]>
Hopefully this is the last update that will be needed for VX-8700  
support. Every supported function has been tested and should be ready  
for release :).

Changes:
   LG VX-8700:
     - Fixed calendar support
     - Phonebook support updates and groups support (correct  
ringtones, pictures)

   LG Phonebook:
     - Identify and throw LG phonebook busy error.

   Brew2:
     - Corrected stat implementation. It was incorrectly identifying  
files on external media.

I am still prepping my VX-9400 support files. I expect to be able to  
submit a patch sometime tomorrow.


-Nathan Hjelm

-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/

_______________________________________________
BitPim-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/bitpim-devel
vx8700_final.patch (application/octet-stream, 32.6 KB)
Index: src/phones/com_brew.py
===================================================================
--- src/phones/com_brew.py	(revision 4235)
+++ src/phones/com_brew.py	(working copy)
@@ -1034,14 +1034,15 @@
         res=self.sendbrewcommand(req, p_brew.new_statfileresponse)
         if res.flags==2:
             raise BrewNoSuchFileException
-        if res.type==1:
+        if res.type==1 or res.type==0x86:
+            # files on external media have type 0x86
             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' }
+        if res.created_date==0:
+            results['date']=(0, '')
+        else:
+            results['date']=(res.created_date, time.strftime("%x %X", time.localtime(res.created_date)))
         return results
 
 class BrewProtocol(RealBrewProtocol):
Index: src/phones/p_lgvx8700.p
===================================================================
--- src/phones/p_lgvx8700.p	(revision 4235)
+++ src/phones/p_lgvx8700.p	(working copy)
@@ -16,29 +16,57 @@
 # we are the same as lgvx9900 except as noted below
 from p_lgvx9900 import *
 from p_lgvx8500 import t9udbfile
- 
+
 # We use LSB for all integer like fields
 UINT=UINTlsb
 BOOL=BOOLlsb
 
 BREW_FILE_SYSTEM=2
 
+# Phonebook stuff
+RTPathIndexFile='pim/pbRingIdSetAsPath.dat'
+WPPathIndexFile='pim/pbPictureIdSetAsPath.dat'
+pb_file_name='pim/pbentry.dat'
+
 T9USERDBFILENAME='t9udb/t9udb_eng.dat'
 
 %}
 
+# phonebook
 PACKET pbgroup:
-    36 USTRING {'encoding': PHONE_ENCODING, 'raiseonunterminatedread': False, 'raiseontruncate': False } name
+    33 USTRING {'encoding': PHONE_ENCODING, 'raiseonunterminatedread': False, 'raiseontruncate': False } name
+    2  UINT groupid
+    1  UINT {'default': 0} +unknown0
 
 PACKET pbgroups:
     "Phonebook groups"
     * LIST {'elementclass': pbgroup} +groups
 
+PACKET pbfileentry:
+    4   UINT    serial1
+    2   UINT    entrynumber
+    133 DATA    data1
+    2   UINT    ringtone
+    2   UINT    wallpaper
+    15  DATA    data2
+
+PACKET pbfile:
+    * LIST { 'elementclass': pbfileentry } items
+
+PACKET PathIndexEntry:
+    255 USTRING { 'encoding': PHONE_ENCODING,
+                  'default': '' } +pathname
+PACKET PathIndexFile:
+    * LIST { 'elementclass': PathIndexEntry,
+             'createdefault': True,
+             'length': NUMPHONEBOOKENTRIES } +items
+
+# calendar
 PACKET scheduleevent:
     4  UINT pos "position within file, used as an event id"
     33 USTRING {'encoding': PHONE_ENCODING, 'raiseonunterminatedread': False, 'raiseontruncate': False } description
-    4  GPSDATE cdate      # creation date
-    4  GPSDATE mdate      # modification date
+    4  GPSDATE { 'default': GPSDATE.now() } +cdate      # creation date
+    4  GPSDATE { 'default': GPSDATE.now() } +mdate      # modification date
     4  LGCALDATE start
     4  LGCALDATE end_time
     4  LGCALDATE end_date
Index: src/phones/com_lgvx8700.py
===================================================================
--- src/phones/com_lgvx8700.py	(revision 4235)
+++ src/phones/com_lgvx8700.py	(working copy)
@@ -20,12 +20,13 @@
 import commport
 import p_brew
 import helpids
+import com_lgvx8300
 import com_lgvx8500
 import p_lgvx8700
 
 #-------------------------------------------------------------------------------
 parentphone=com_lgvx8500.Phone
-class Phone(parentphone, com_brew.RealBrewProtocol2):
+class Phone(com_brew.RealBrewProtocol2, parentphone):
     "Talk to LG VX-8700 cell phone"
 
     desc="LG-VX8700"
@@ -34,6 +35,9 @@
     serialsname='lgvx8700'
 
     my_model='VX8700'
+    builtinringtones= ('Low Beep Once', 'Low Beeps', 'Loud Beep Once', 'Loud Beeps', 'Door Bell', 'VZW Default Ringtone') + \
+                      tuple(['Ringtone '+`n` for n in range(1,12)]) + \
+                      ('No Ring',)
 
     ringtonelocations= (
         # type           index file             default dir                 external dir  max  type   index
@@ -72,12 +76,88 @@
         """
         if not self._in_DM:
             self.enter_DM()
-        return parentphone.getfundamentals(self, results)
+        results = parentphone.getfundamentals(self, results)
 
+        if self.my_model=='VX8700':
+            self.getgroups(results)
+        return results
+
+    # phonebook
+    def _update_pb_file(self, pb, fundamentals, pbinfo):
+        # update the pbentry file
+        update_flg=False
+        for e in pb.items:
+            _info=pbinfo.get(e.serial1, None)
+            if _info:
+                wp=_info.get('wallpaper', None)
+                if wp is not None and wp!=e.wallpaper:
+                    update_flg=True
+                    e.wallpaper=wp
+        if update_flg:
+            self.log('Updating wallpaper index')
+            buf=prototypes.buffer()
+            pb.writetobuffer(buf, logtitle="Updated index "+self.protocolclass.pb_file_name)
+            self.writefile(self.protocolclass.pb_file_name, buf.getvalue())
+
+    def savephonebook(self, data):
+        "Saves out the phonebook"
+        res=com_lgvx8300.Phone.savephonebook(self, data)
+        # retrieve the phonebook entries
+        _buf=prototypes.buffer(self.getfilecontents(self.protocolclass.pb_file_name))
+        _pb_entries=self.protocolclass.pbfile()
+        _pb_entries.readfrombuffer(_buf, logtitle="Read phonebook file "+self.protocolclass.pb_file_name)
+        _rt_index=data.get('ringtone-index', {})
+        _wp_index=data.get('wallpaper-index', {})
+        # update info that the phone software failed to do!!
+        self._update_pb_info(_pb_entries, data)
+        # fix up ringtone index
+        self._write_path_index(_pb_entries, 'ringtone',
+                               _rt_index,
+                               self.protocolclass.RTPathIndexFile,
+                               (0xffff,))
+        # fix up wallpaer index
+        self._write_path_index(_pb_entries, 'wallpaper',
+                               _wp_index,
+                               self.protocolclass.WPPathIndexFile,
+                               (0, 0xffff,))
+        return res
+
+    # groups
+    def getgroups(self, results):
+        "Read groups"
+        # Reads groups that use explicit IDs
+        self.log("Reading group information")
+        buf=prototypes.buffer(self.getfilecontents("pim/pbgroup.dat"))
+        g=self.protocolclass.pbgroups()
+        g.readfrombuffer(buf, logtitle="Groups read")
+        groups={}
+        for i in range(len(g.groups)):
+            if len(g.groups[i].name) and (g.groups[i].groupid or i==0):
+                groups[g.groups[i].groupid]={'name': g.groups[i].name }
+        results['groups'] = groups
+        return groups
+
+    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']
+            if 'groupid' in e.getfields():
+                e.groupid = k
+                if k != 0:
+                    e.unknown0 = 1
+            g.groups.append(e)
+        buffer=prototypes.buffer()
+        g.writetobuffer(buffer, logtitle="New group file")
+        self.writefile("pim/pbgroup.dat", buffer.getvalue())
+
     def is_mode_brew(self):
         req=p_brew.memoryconfigrequest()
         respc=p_brew.memoryconfigresponse
-        
+
         for baud in 0, 38400, 115200:
             if baud:
                 if not self.comm.setbaudrate(baud):
@@ -97,11 +177,7 @@
             # enter DM to enable file reading/writing
             self.enter_DM()
         return com_brew.RealBrewProtocol2.listfiles(self, dir)
-
-    def getfilesystem(self, dir="", recurse=0, directories=1, files=1):
-        # BREW2's get filesystem is used here because BREW1's does not appear not to work well on the vx8700
-        return com_brew.RealBrewProtocol2.getfilesystem(self, dir, recurse, directories, files)
-
+    
     def enter_DM (self):
         # request challenge
         req = self.protocolclass.ULReq(unlock_key=0)
@@ -118,33 +194,6 @@
         else:
             self.log('Failed to enter DM mode')
 
-    def sendbrewcommand(self, request, responseclass, callsetmode=True):
-        if callsetmode:
-            self.setmode(self.MODEBREW)
-        buffer=prototypes.buffer()
-        request.writetobuffer(buffer, logtitle="com_lgvx8700: sendbrewcommand")
-        data=buffer.getvalue()
-
-        # the memory config request does not need to be unlocked
-        if (data[0]=="\x59" or data[0]=="\x4b") and data[1]!="\x0c":
-            # "unlock" the brew command by sending a 0x5c command with the same data
-            # unlocking works with the LG vx9400 as well (tested)
-            if data[0]=="\x59":
-                uldata = "\x5c" + data[1:]
-            else:
-                # do we need to drop a character from a brew2 command? it works.
-                uldata = "\x5c" + data[2:]
-            uldata=common.pppescape(uldata+common.crcs(uldata))+common.pppterminator
-            self.logdata("Unlock brew command", uldata, None)
-            try:
-                data=self.comm.writethenreaduntil(uldata, False, common.pppterminator, logreaduntilsuccess=False) 
-            except modeignoreerrortypes:
-                self.mode=self.MODENONE
-                self.raisecommsdnaexception("unlocking filesystem command")
-            self.logdata("Unlock brew command response", data, None)
-        return com_brew.RealBrewProtocol.sendbrewcommand(self, request, responseclass, callsetmode=False)
-
-
 #-------------------------------------------------------------------------------
 parentprofile=com_lgvx8500.Profile
 class Profile(parentprofile):
Index: src/phones/p_lgvx8700.py
===================================================================
--- src/phones/p_lgvx8700.py	(revision 4235)
+++ src/phones/p_lgvx8700.py	(working copy)
@@ -8,17 +8,22 @@
 # we are the same as lgvx9900 except as noted below
 from p_lgvx9900 import *
 from p_lgvx8500 import t9udbfile
- 
+
 # We use LSB for all integer like fields
 UINT=UINTlsb
 BOOL=BOOLlsb
 
 BREW_FILE_SYSTEM=2
 
+# Phonebook stuff
+RTPathIndexFile='pim/pbRingIdSetAsPath.dat'
+WPPathIndexFile='pim/pbPictureIdSetAsPath.dat'
+pb_file_name='pim/pbentry.dat'
+
 T9USERDBFILENAME='t9udb/t9udb_eng.dat'
 
 class pbgroup(BaseProtogenClass):
-    __fields=['name']
+    __fields=['name', 'groupid', 'unknown0']
 
     def __init__(self, *args, **kwargs):
         dict={}
@@ -44,11 +49,7 @@
         # Were any unrecognized kwargs passed in?
         if __debug__:
             self._complainaboutunusedargs(pbgroup,kwargs)
-        if len(args):
-            dict2={'sizeinbytes': 36, 'encoding': PHONE_ENCODING, 'raiseonunterminatedread': False, 'raiseontruncate': False }
-            dict2.update(kwargs)
-            kwargs=dict2
-            self.__field_name=USTRING(*args,**dict2)
+        if len(args): raise TypeError('Unexpected arguments supplied: '+`args`)
         # Make all P fields that haven't already been constructed
 
 
@@ -56,6 +57,11 @@
         'Writes this packet to the supplied buffer'
         self._bufferstartoffset=buf.getcurrentoffset()
         self.__field_name.writetobuffer(buf)
+        self.__field_groupid.writetobuffer(buf)
+        try: self.__field_unknown0
+        except:
+            self.__field_unknown0=UINT(**{'sizeinbytes': 1, 'default': 0})
+        self.__field_unknown0.writetobuffer(buf)
         self._bufferendoffset=buf.getcurrentoffset()
         if autolog and self._bufferstartoffset==0: self.autologwrite(buf, logtitle=logtitle)
 
@@ -64,8 +70,12 @@
         'Reads this packet from the supplied buffer'
         self._bufferstartoffset=buf.getcurrentoffset()
         if autolog and self._bufferstartoffset==0: self.autologread(buf, logtitle=logtitle)
-        self.__field_name=USTRING(**{'sizeinbytes': 36, 'encoding': PHONE_ENCODING, 'raiseonunterminatedread': False, 'raiseontruncate': False })
+        self.__field_name=USTRING(**{'sizeinbytes': 33, 'encoding': PHONE_ENCODING, 'raiseonunterminatedread': False, 'raiseontruncate': False })
         self.__field_name.readfrombuffer(buf)
+        self.__field_groupid=UINT(**{'sizeinbytes': 2})
+        self.__field_groupid.readfrombuffer(buf)
+        self.__field_unknown0=UINT(**{'sizeinbytes': 1, 'default': 0})
+        self.__field_unknown0.readfrombuffer(buf)
         self._bufferendoffset=buf.getcurrentoffset()
 
 
@@ -76,17 +86,48 @@
         if isinstance(value,USTRING):
             self.__field_name=value
         else:
-            self.__field_name=USTRING(value,**{'sizeinbytes': 36, 'encoding': PHONE_ENCODING, 'raiseonunterminatedread': False, 'raiseontruncate': False })
+            self.__field_name=USTRING(value,**{'sizeinbytes': 33, 'encoding': PHONE_ENCODING, 'raiseonunterminatedread': False, 'raiseontruncate': False })
 
     def __delfield_name(self): del self.__field_name
 
     name=property(__getfield_name, __setfield_name, __delfield_name, None)
 
+    def __getfield_groupid(self):
+        return self.__field_groupid.getvalue()
+
+    def __setfield_groupid(self, value):
+        if isinstance(value,UINT):
+            self.__field_groupid=value
+        else:
+            self.__field_groupid=UINT(value,**{'sizeinbytes': 2})
+
+    def __delfield_groupid(self): del self.__field_groupid
+
+    groupid=property(__getfield_groupid, __setfield_groupid, __delfield_groupid, None)
+
+    def __getfield_unknown0(self):
+        try: self.__field_unknown0
+        except:
+            self.__field_unknown0=UINT(**{'sizeinbytes': 1, 'default': 0})
+        return self.__field_unknown0.getvalue()
+
+    def __setfield_unknown0(self, value):
+        if isinstance(value,UINT):
+            self.__field_unknown0=value
+        else:
+            self.__field_unknown0=UINT(value,**{'sizeinbytes': 1, 'default': 0})
+
+    def __delfield_unknown0(self): del self.__field_unknown0
+
+    unknown0=property(__getfield_unknown0, __setfield_unknown0, __delfield_unknown0, None)
+
     def iscontainer(self):
         return True
 
     def containerelements(self):
         yield ('name', self.__field_name, None)
+        yield ('groupid', self.__field_groupid, None)
+        yield ('unknown0', self.__field_unknown0, None)
 
 
 
@@ -172,6 +213,395 @@
 
 
 
+class pbfileentry(BaseProtogenClass):
+    __fields=['serial1', 'entrynumber', 'data1', 'ringtone', 'wallpaper', 'data2']
+
+    def __init__(self, *args, **kwargs):
+        dict={}
+        # What was supplied to this function
+        dict.update(kwargs)
+        # Parent constructor
+        super(pbfileentry,self).__init__(**dict)
+        if self.__class__ is pbfileentry:
+            self._update(args,dict)
+
+
+    def getfields(self):
+        return self.__fields
+
+
+    def _update(self, args, kwargs):
+        super(pbfileentry,self)._update(args,kwargs)
+        keys=kwargs.keys()
+        for key in keys:
+            if key in self.__fields:
+                setattr(self, key, kwargs[key])
+                del kwargs[key]
+        # Were any unrecognized kwargs passed in?
+        if __debug__:
+            self._complainaboutunusedargs(pbfileentry,kwargs)
+        if len(args): raise TypeError('Unexpected arguments supplied: '+`args`)
+        # Make all P fields that haven't already been constructed
+
+
+    def writetobuffer(self,buf,autolog=True,logtitle="<written data>"):
+        'Writes this packet to the supplied buffer'
+        self._bufferstartoffset=buf.getcurrentoffset()
+        self.__field_serial1.writetobuffer(buf)
+        self.__field_entrynumber.writetobuffer(buf)
+        self.__field_data1.writetobuffer(buf)
+        self.__field_ringtone.writetobuffer(buf)
+        self.__field_wallpaper.writetobuffer(buf)
+        self.__field_data2.writetobuffer(buf)
+        self._bufferendoffset=buf.getcurrentoffset()
+        if autolog and self._bufferstartoffset==0: self.autologwrite(buf, logtitle=logtitle)
+
+
+    def readfrombuffer(self,buf,autolog=True,logtitle="<read data>"):
+        'Reads this packet from the supplied buffer'
+        self._bufferstartoffset=buf.getcurrentoffset()
+        if autolog and self._bufferstartoffset==0: self.autologread(buf, logtitle=logtitle)
+        self.__field_serial1=UINT(**{'sizeinbytes': 4})
+        self.__field_serial1.readfrombuffer(buf)
+        self.__field_entrynumber=UINT(**{'sizeinbytes': 2})
+        self.__field_entrynumber.readfrombuffer(buf)
+        self.__field_data1=DATA(**{'sizeinbytes': 133})
+        self.__field_data1.readfrombuffer(buf)
+        self.__field_ringtone=UINT(**{'sizeinbytes': 2})
+        self.__field_ringtone.readfrombuffer(buf)
+        self.__field_wallpaper=UINT(**{'sizeinbytes': 2})
+        self.__field_wallpaper.readfrombuffer(buf)
+        self.__field_data2=DATA(**{'sizeinbytes': 15})
+        self.__field_data2.readfrombuffer(buf)
+        self._bufferendoffset=buf.getcurrentoffset()
+
+
+    def __getfield_serial1(self):
+        return self.__field_serial1.getvalue()
+
+    def __setfield_serial1(self, value):
+        if isinstance(value,UINT):
+            self.__field_serial1=value
+        else:
+            self.__field_serial1=UINT(value,**{'sizeinbytes': 4})
+
+    def __delfield_serial1(self): del self.__field_serial1
+
+    serial1=property(__getfield_serial1, __setfield_serial1, __delfield_serial1, None)
+
+    def __getfield_entrynumber(self):
+        return self.__field_entrynumber.getvalue()
+
+    def __setfield_entrynumber(self, value):
+        if isinstance(value,UINT):
+            self.__field_entrynumber=value
+        else:
+            self.__field_entrynumber=UINT(value,**{'sizeinbytes': 2})
+
+    def __delfield_entrynumber(self): del self.__field_entrynumber
+
+    entrynumber=property(__getfield_entrynumber, __setfield_entrynumber, __delfield_entrynumber, None)
+
+    def __getfield_data1(self):
+        return self.__field_data1.getvalue()
+
+    def __setfield_data1(self, value):
+        if isinstance(value,DATA):
+            self.__field_data1=value
+        else:
+            self.__field_data1=DATA(value,**{'sizeinbytes': 133})
+
+    def __delfield_data1(self): del self.__field_data1
+
+    data1=property(__getfield_data1, __setfield_data1, __delfield_data1, None)
+
+    def __getfield_ringtone(self):
+        return self.__field_ringtone.getvalue()
+
+    def __setfield_ringtone(self, value):
+        if isinstance(value,UINT):
+            self.__field_ringtone=value
+        else:
+            self.__field_ringtone=UINT(value,**{'sizeinbytes': 2})
+
+    def __delfield_ringtone(self): del self.__field_ringtone
+
+    ringtone=property(__getfield_ringtone, __setfield_ringtone, __delfield_ringtone, None)
+
+    def __getfield_wallpaper(self):
+        return self.__field_wallpaper.getvalue()
+
+    def __setfield_wallpaper(self, value):
+        if isinstance(value,UINT):
+            self.__field_wallpaper=value
+        else:
+            self.__field_wallpaper=UINT(value,**{'sizeinbytes': 2})
+
+    def __delfield_wallpaper(self): del self.__field_wallpaper
+
+    wallpaper=property(__getfield_wallpaper, __setfield_wallpaper, __delfield_wallpaper, None)
+
+    def __getfield_data2(self):
+        return self.__field_data2.getvalue()
+
+    def __setfield_data2(self, value):
+        if isinstance(value,DATA):
+            self.__field_data2=value
+        else:
+            self.__field_data2=DATA(value,**{'sizeinbytes': 15})
+
+    def __delfield_data2(self): del self.__field_data2
+
+    data2=property(__getfield_data2, __setfield_data2, __delfield_data2, None)
+
+    def iscontainer(self):
+        return True
+
+    def containerelements(self):
+        yield ('serial1', self.__field_serial1, None)
+        yield ('entrynumber', self.__field_entrynumber, None)
+        yield ('data1', self.__field_data1, None)
+        yield ('ringtone', self.__field_ringtone, None)
+        yield ('wallpaper', self.__field_wallpaper, None)
+        yield ('data2', self.__field_data2, None)
+
+
+
+
+class pbfile(BaseProtogenClass):
+    __fields=['items']
+
+    def __init__(self, *args, **kwargs):
+        dict={}
+        # What was supplied to this function
+        dict.update(kwargs)
+        # Parent constructor
+        super(pbfile,self).__init__(**dict)
+        if self.__class__ is pbfile:
+            self._update(args,dict)
+
+
+    def getfields(self):
+        return self.__fields
+
+
+    def _update(self, args, kwargs):
+        super(pbfile,self)._update(args,kwargs)
+        keys=kwargs.keys()
+        for key in keys:
+            if key in self.__fields:
+                setattr(self, key, kwargs[key])
+                del kwargs[key]
+        # Were any unrecognized kwargs passed in?
+        if __debug__:
+            self._complainaboutunusedargs(pbfile,kwargs)
+        if len(args):
+            dict2={ 'elementclass': pbfileentry }
+            dict2.update(kwargs)
+            kwargs=dict2
+            self.__field_items=LIST(*args,**dict2)
+        # Make all P fields that haven't already been constructed
+
+
+    def writetobuffer(self,buf,autolog=True,logtitle="<written data>"):
+        'Writes this packet to the supplied buffer'
+        self._bufferstartoffset=buf.getcurrentoffset()
+        self.__field_items.writetobuffer(buf)
+        self._bufferendoffset=buf.getcurrentoffset()
+        if autolog and self._bufferstartoffset==0: self.autologwrite(buf, logtitle=logtitle)
+
+
+    def readfrombuffer(self,buf,autolog=True,logtitle="<read data>"):
+        'Reads this packet from the supplied buffer'
+        self._bufferstartoffset=buf.getcurrentoffset()
+        if autolog and self._bufferstartoffset==0: self.autologread(buf, logtitle=logtitle)
+        self.__field_items=LIST(**{ 'elementclass': pbfileentry })
+        self.__field_items.readfrombuffer(buf)
+        self._bufferendoffset=buf.getcurrentoffset()
+
+
+    def __getfield_items(self):
+        return self.__field_items.getvalue()
+
+    def __setfield_items(self, value):
+        if isinstance(value,LIST):
+            self.__field_items=value
+        else:
+            self.__field_items=LIST(value,**{ 'elementclass': pbfileentry })
+
+    def __delfield_items(self): del self.__field_items
+
+    items=property(__getfield_items, __setfield_items, __delfield_items, None)
+
+    def iscontainer(self):
+        return True
+
+    def containerelements(self):
+        yield ('items', self.__field_items, None)
+
+
+
+
+class PathIndexEntry(BaseProtogenClass):
+    __fields=['pathname']
+
+    def __init__(self, *args, **kwargs):
+        dict={}
+        # What was supplied to this function
+        dict.update(kwargs)
+        # Parent constructor
+        super(PathIndexEntry,self).__init__(**dict)
+        if self.__class__ is PathIndexEntry:
+            self._update(args,dict)
+
+
+    def getfields(self):
+        return self.__fields
+
+
+    def _update(self, args, kwargs):
+        super(PathIndexEntry,self)._update(args,kwargs)
+        keys=kwargs.keys()
+        for key in keys:
+            if key in self.__fields:
+                setattr(self, key, kwargs[key])
+                del kwargs[key]
+        # Were any unrecognized kwargs passed in?
+        if __debug__:
+            self._complainaboutunusedargs(PathIndexEntry,kwargs)
+        if len(args):
+            dict2={'sizeinbytes': 255,  'encoding': PHONE_ENCODING,                  'default': '' }
+            dict2.update(kwargs)
+            kwargs=dict2
+            self.__field_pathname=USTRING(*args,**dict2)
+        # Make all P fields that haven't already been constructed
+
+
+    def writetobuffer(self,buf,autolog=True,logtitle="<written data>"):
+        'Writes this packet to the supplied buffer'
+        self._bufferstartoffset=buf.getcurrentoffset()
+        try: self.__field_pathname
+        except:
+            self.__field_pathname=USTRING(**{'sizeinbytes': 255,  'encoding': PHONE_ENCODING,                  'default': '' })
+        self.__field_pathname.writetobuffer(buf)
+        self._bufferendoffset=buf.getcurrentoffset()
+        if autolog and self._bufferstartoffset==0: self.autologwrite(buf, logtitle=logtitle)
+
+
+    def readfrombuffer(self,buf,autolog=True,logtitle="<read data>"):
+        'Reads this packet from the supplied buffer'
+        self._bufferstartoffset=buf.getcurrentoffset()
+        if autolog and self._bufferstartoffset==0: self.autologread(buf, logtitle=logtitle)
+        self.__field_pathname=USTRING(**{'sizeinbytes': 255,  'encoding': PHONE_ENCODING,                  'default': '' })
+        self.__field_pathname.readfrombuffer(buf)
+        self._bufferendoffset=buf.getcurrentoffset()
+
+
+    def __getfield_pathname(self):
+        try: self.__field_pathname
+        except:
+            self.__field_pathname=USTRING(**{'sizeinbytes': 255,  'encoding': PHONE_ENCODING,                  'default': '' })
+        return self.__field_pathname.getvalue()
+
+    def __setfield_pathname(self, value):
+        if isinstance(value,USTRING):
+            self.__field_pathname=value
+        else:
+            self.__field_pathname=USTRING(value,**{'sizeinbytes': 255,  'encoding': PHONE_ENCODING,                  'default': '' })
+
+    def __delfield_pathname(self): del self.__field_pathname
+
+    pathname=property(__getfield_pathname, __setfield_pathname, __delfield_pathname, None)
+
+    def iscontainer(self):
+        return True
+
+    def containerelements(self):
+        yield ('pathname', self.__field_pathname, None)
+
+
+
+
+class PathIndexFile(BaseProtogenClass):
+    __fields=['items']
+
+    def __init__(self, *args, **kwargs):
+        dict={}
+        # What was supplied to this function
+        dict.update(kwargs)
+        # Parent constructor
+        super(PathIndexFile,self).__init__(**dict)
+        if self.__class__ is PathIndexFile:
+            self._update(args,dict)
+
+
+    def getfields(self):
+        return self.__fields
+
+
+    def _update(self, args, kwargs):
+        super(PathIndexFile,self)._update(args,kwargs)
+        keys=kwargs.keys()
+        for key in keys:
+            if key in self.__fields:
+                setattr(self, key, kwargs[key])
+                del kwargs[key]
+        # Were any unrecognized kwargs passed in?
+        if __debug__:
+            self._complainaboutunusedargs(PathIndexFile,kwargs)
+        if len(args):
+            dict2={ 'elementclass': PathIndexEntry,             'createdefault': True,             'length': NUMPHONEBOOKENTRIES }
+            dict2.update(kwargs)
+            kwargs=dict2
+            self.__field_items=LIST(*args,**dict2)
+        # Make all P fields that haven't already been constructed
+
+
+    def writetobuffer(self,buf,autolog=True,logtitle="<written data>"):
+        'Writes this packet to the supplied buffer'
+        self._bufferstartoffset=buf.getcurrentoffset()
+        try: self.__field_items
+        except:
+            self.__field_items=LIST(**{ 'elementclass': PathIndexEntry,             'createdefault': True,             'length': NUMPHONEBOOKENTRIES })
+        self.__field_items.writetobuffer(buf)
+        self._bufferendoffset=buf.getcurrentoffset()
+        if autolog and self._bufferstartoffset==0: self.autologwrite(buf, logtitle=logtitle)
+
+
+    def readfrombuffer(self,buf,autolog=True,logtitle="<read data>"):
+        'Reads this packet from the supplied buffer'
+        self._bufferstartoffset=buf.getcurrentoffset()
+        if autolog and self._bufferstartoffset==0: self.autologread(buf, logtitle=logtitle)
+        self.__field_items=LIST(**{ 'elementclass': PathIndexEntry,             'createdefault': True,             'length': NUMPHONEBOOKENTRIES })
+        self.__field_items.readfrombuffer(buf)
+        self._bufferendoffset=buf.getcurrentoffset()
+
+
+    def __getfield_items(self):
+        try: self.__field_items
+        except:
+            self.__field_items=LIST(**{ 'elementclass': PathIndexEntry,             'createdefault': True,             'length': NUMPHONEBOOKENTRIES })
+        return self.__field_items.getvalue()
+
+    def __setfield_items(self, value):
+        if isinstance(value,LIST):
+            self.__field_items=value
+        else:
+            self.__field_items=LIST(value,**{ 'elementclass': PathIndexEntry,             'createdefault': True,             'length': NUMPHONEBOOKENTRIES })
+
+    def __delfield_items(self): del self.__field_items
+
+    items=property(__getfield_items, __setfield_items, __delfield_items, None)
+
+    def iscontainer(self):
+        return True
+
+    def containerelements(self):
+        yield ('items', self.__field_items, None)
+
+
+
+
 class scheduleevent(BaseProtogenClass):
     __fields=['pos', 'description', 'cdate', 'mdate', 'start', 'end_time', 'end_date', 'repeat', 'alarmindex_vibrate', 'ringtone', 'unknown1', 'alarmminutes', 'alarmhours', 'unknown2', 'unknown3', 'unknown4']
 
@@ -208,7 +638,13 @@
         self._bufferstartoffset=buf.getcurrentoffset()
         self.__field_pos.writetobuffer(buf)
         self.__field_description.writetobuffer(buf)
+        try: self.__field_cdate
+        except:
+            self.__field_cdate=GPSDATE(**{'sizeinbytes': 4,  'default': GPSDATE.now() })
         self.__field_cdate.writetobuffer(buf)
+        try: self.__field_mdate
+        except:
+            self.__field_mdate=GPSDATE(**{'sizeinbytes': 4,  'default': GPSDATE.now() })
         self.__field_mdate.writetobuffer(buf)
         self.__field_start.writetobuffer(buf)
         self.__field_end_time.writetobuffer(buf)
@@ -243,9 +679,9 @@
         self.__field_pos.readfrombuffer(buf)
         self.__field_description=USTRING(**{'sizeinbytes': 33, 'encoding': PHONE_ENCODING, 'raiseonunterminatedread': False, 'raiseontruncate': False })
         self.__field_description.readfrombuffer(buf)
-        self.__field_cdate=GPSDATE(**{'sizeinbytes': 4})
+        self.__field_cdate=GPSDATE(**{'sizeinbytes': 4,  'default': GPSDATE.now() })
         self.__field_cdate.readfrombuffer(buf)
-        self.__field_mdate=GPSDATE(**{'sizeinbytes': 4})
+        self.__field_mdate=GPSDATE(**{'sizeinbytes': 4,  'default': GPSDATE.now() })
         self.__field_mdate.readfrombuffer(buf)
         self.__field_start=LGCALDATE(**{'sizeinbytes': 4})
         self.__field_start.readfrombuffer(buf)
@@ -301,26 +737,32 @@
     description=property(__getfield_description, __setfield_description, __delfield_description, None)
 
     def __getfield_cdate(self):
+        try: self.__field_cdate
+        except:
+            self.__field_cdate=GPSDATE(**{'sizeinbytes': 4,  'default': GPSDATE.now() })
         return self.__field_cdate.getvalue()
 
     def __setfield_cdate(self, value):
         if isinstance(value,GPSDATE):
             self.__field_cdate=value
         else:
-            self.__field_cdate=GPSDATE(value,**{'sizeinbytes': 4})
+            self.__field_cdate=GPSDATE(value,**{'sizeinbytes': 4,  'default': GPSDATE.now() })
 
     def __delfield_cdate(self): del self.__field_cdate
 
     cdate=property(__getfield_cdate, __setfield_cdate, __delfield_cdate, None)
 
     def __getfield_mdate(self):
+        try: self.__field_mdate
+        except:
+            self.__field_mdate=GPSDATE(**{'sizeinbytes': 4,  'default': GPSDATE.now() })
         return self.__field_mdate.getvalue()
 
     def __setfield_mdate(self, value):
         if isinstance(value,GPSDATE):
             self.__field_mdate=value
         else:
-            self.__field_mdate=GPSDATE(value,**{'sizeinbytes': 4})
+            self.__field_mdate=GPSDATE(value,**{'sizeinbytes': 4,  'default': GPSDATE.now() })
 
     def __delfield_mdate(self): del self.__field_mdate
 
Index: src/phones/com_lg.py
===================================================================
--- src/phones/com_lg.py	(revision 4235)
+++ src/phones/com_lg.py	(working copy)
@@ -104,6 +104,11 @@
         # turn it back to normal
         data=common.pppunescape(data)
 
+        if data[:2] != firsttwo:
+            # phonebook is busy
+            self.logdata("LG Phonebook busy response", data, None)
+            raise common.PhoneBookBusyException()
+
         # take off crc and terminator
         crc=data[-3:-1]
         data=data[:-3]
Index: help/phone-lgvx8700.htd
===================================================================
--- help/phone-lgvx8700.htd	(revision 4235)
+++ help/phone-lgvx8700.htd	(working copy)
@@ -2,7 +2,7 @@
 
 <h2>What works</h2>
 
-<p>Phonebook, wallpaper, ringers, calendar, memo, call history, SMS, Play List, and file system.  BitPim can autodetect this phone if it is connected to the PC via a straight USB cable.  BitPim can also make use of ringtone files stored on the microSD card.<BR>
+<p>Phonebook, wallpaper, ringers, calendar, memo, call history, SMS, and file system.  BitPim can autodetect this phone if it is connected to the PC via a straight USB cable.<BR>
 
 <P>Due to their similarities, please see the <a href="phone-lgvx8600.htm">LG VX8600 Help</a> for more details.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.