updated code for the LG PM325

"Brent Roettger" <[email protected]>
Newsgroups gmane.comp.mobile.bitpim.devel
Message-ID <[email protected]>
Here is the updated code for the LG PM325 phone. It currently supports reading and writing of the phonebook. I have cleaned up the code quite a bit from the previous version by removing a lot of unused and untested code.

The biggest problem right now is that the phone it is not currently being auto-detected. If I set brew_required=True the phone is not detected at all. If I set it to false, the phone is detected , but on the modem port instead.

Can I get this code checked in? Does anyone have time to do some testing and let me know how it works for you?

Thanks,

Brent Roettger
com_lgpm325.py (text/plain, 26.7 KB)
### BITPIM
###
### Copyright (C) 2005 Brent Roettger <[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_lgpm325.py,v 1.3 2005/11/20

"""Communicate with the LG LX325/PM325 (Sprint) cell phone"""

# standard modules
import re
import time
import cStringIO
import sha

# my modules
import p_lgpm325
import p_brew
import common
import commport
import com_brew
import com_phone
import com_lg
import com_lgvx4400
import prototypes


class Phone(com_lgvx4400.Phone):
    "Talk to the LG LX325/PM325 cell phone"

    desc="LG LX325/PM325"
    wallpaperindexfilename="setas/amsImageIndex.map"
    ringerindexfilename="setas/amsRingerIndex.map"
    protocolclass=p_lgpm325
    serialsname='lgpm325'

    ringtonelocations=(
        # offset, index file, files location, type, maximumentries
        ( 2, ringerindexfilename, "user/sound/ringer", "ringers", 30),
        )

    builtinimages=('Starfish', 'Goldfish', 'Leaves', 'Bicycle', 'Speed',
                   'Autumn', 'Island', 'Winter', 'Bamboo', 'Yellow Flowers', 
'Snow')

    builtinringtones=( 'Tone 1', 'Tone 2', 'Tone 3', 'Tone 4', 'Tone 5', 
'Tone 6',
                       'Alert 1', 'Alert 2', 'Alert 3', 'Alert 4', 'Alert 
5', 'Alert 6',
                       'Jazztic', 'Rock & Roll', 'Grand Waltz', 'Toccata and 
Fugue',
                       'Sunday Afternoon', 'Bumble Bee', 'Circus Band', 
'Cuckoo Waltz',
                       'Latin', 'CanCan', 'Play tag', 'Eine kleine 
Nachtmusik',
                       'Symphony No.25 in G Minor', 'Capriccio a minor', 
'Moonlight',
                       'A Nameless Girl', 'From the New World', 'They Called 
Me Elvis')

    def __init__(self, logtarget, commport):
        "Calls all the constructors and sets initial modes"
        com_phone.Phone.__init__(self, logtarget, commport)
        com_brew.BrewProtocol.__init__(self)
        com_lg.LGPhonebook.__init__(self)
        self.log("Attempting to contact phone")
        self.mode=self.MODENONE

#----- PhoneBook 
-----------------------------------------------------------------------

    def getfundamentals(self, results):
        """Gets information fundamental to interoperating with the phone and 
UI.

        Currently this is:

          - 'uniqueserial'     a unique serial number representing the phone
          - 'groups'           the phonebook groups

        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()
        self.log(results)

        # now read groups
        self.log("Reading group information")
        buf=prototypes.buffer(self.getfilecontents("pim/pbookgroup.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]={ 'group_id': g.groups[i].group_id, 'name': 
g.groups[i].name }
        results['groups']=groups
        self.getwallpaperindices(results)
        self.getringtoneindices(results)
        self.log("Fundamentals retrieved")
        return results

    def syncbegin(self):
       self.mode = self.MODEPHONEBOOK
       self.sendpbcommand(self.protocolclass.pbstartsyncrequest(), 
self.protocolclass.pbstartsyncresponse)

    def syncend(self):
       req=self.protocolclass.pbendsyncrequest()
       self.sendpbcommand(req, self.protocolclass.pbendsyncresponse)

    def getphonebook(self,result):
        """Reads the phonebook data.  The L{getfundamentals} information 
will
        already be in result."""
        # Read speed dials first
        speeds={}
        try:
            if self.protocolclass.NUMSPEEDDIALS:
                self.log("Reading speed dials")
                
buf=prototypes.buffer(self.getfilecontents("pim/pbooksdial.dat"))
                sd=self.protocolclass.speeddials()
                sd.readfrombuffer(buf)
                for i in range(self.protocolclass.FIRSTSPEEDDIAL, 
self.protocolclass.LASTSPEEDDIAL+1):
                    if sd.speeddials[i].entry<0 or 
sd.speeddials[i].entry>self.protocolclass.NUMPHONEBOOKENTRIES:
                        continue
                    l=speeds.get(sd.speeddials[i].entry, [])
                    l.append((i, sd.speeddials[i].number))
                    speeds[sd.speeddials[i].entry]=l
        except com_brew.BrewNoSuchFileException:
            pass

        pbook={}
        # Bug in the phone.  if you repeatedly read the phone book it starts
        # returning a random number as the number of entries.  We get around
        # this by switching into brew mode which clears that.
        self.mode=self.MODENONE
        self.setmode(self.MODEBREW)

        self.log("Reading number of phonebook entries")
        self.mode = self.MODEBREW
        res=self.sendpbcommand(self.protocolclass.pbinforequest(), 
self.protocolclass.pbinforesponse)
        numentries = res.numentries
        self.log("There are %d entries" % (numentries,))
        for i in range(0, numentries):
            ### Read current entry
            req=self.protocolclass.pbreadentryrequest()
            res=self.sendpbcommand(req, 
self.protocolclass.pbreadentryresponse)
            self.log("Read entry "+`i`+" - "+res.entry.name)
            entry=self.extractphonebookentry(res.entry, speeds, result)
            pbook[i]=entry
            self.progress(i, numentries, res.entry.name)
            #### Advance to next entry
            req=self.protocolclass.pbnextentryrequest()
            self.sendpbcommand(req, self.protocolclass.pbnextentryresponse)

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

        result['phonebook']=pbook

        cats=[]
        for i in result['groups']:
            if result['groups'][i]['name']!='No Group':
                cats.append(result['groups'][i]['name'])
        result['categories']=cats
        print "returning keys",result.keys()
        return pbook

    def extractphonebookentry(self, entry, speeds, fundamentals):
        """Return a phonebook entry in BitPim format.  This is called from 
getphonebook."""
        res={}
        # serials
        res['serials']=[ {'sourcetype': self.serialsname, 'serial1': 
entry.serial1,
                          'sourceuniqueid': fundamentals['uniqueserial']} ]
        # only one name
        res['names']=[ {'full': entry.name} ]
        # only one category
        cat=fundamentals['groups'].get(entry.group, {'name': "No 
Group"})['name']
        if cat!="No Group":
            res['categories']=[ {'category': cat} ]
        # emails
        res['emails']=[]
        for i in entry.emails:
            if len(i.email):
                res['emails'].append( {'email': i.email} )
        if not len(res['emails']): del res['emails'] # it was empty
        # urls
        if 'url' in entry.getfields() and len(entry.url):
            res['urls']=[ {'url': entry.url} ]
        # private
        if 'secret' in entry.getfields() and entry.secret:
            # we only supply secret if it is true
            res['flags']=[ {'secret': entry.secret } ]
        # memos
        if  'memo' in entry.getfields() and len(entry.memo):
            res['memos']=[ {'memo': entry.memo } ]
        # wallpapers
        if entry.wallpaper!=self.protocolclass.NOWALLPAPER:
            try:
                
paper=fundamentals['wallpaper-index'][entry.wallpaper]['name']
                res['wallpapers']=[ {'wallpaper': paper, 'use': 'call'} ]
            except:
                print "can't find wallpaper for index",entry.wallpaper
                pass

        # ringtones
        res['ringtones']=[]
        if 'ringtone' in entry.getfields() and 
entry.ringtone!=self.protocolclass.NORINGTONE:
            try:
                tone=fundamentals['ringtone-index'][entry.ringtone]['name']
                res['ringtones'].append({'ringtone': tone, 'use': 'call'})
            except:
                print "can't find ringtone for index",entry.ringtone

        if len(res['ringtones'])==0:
            del res['ringtones']

        if(getattr(self.protocolclass, 'SPEEDDIALINDEX', 0)==0):
            res=self._assignpbtypeandspeeddialsbyposition(entry, speeds, 
res)
        else:
            res=self._assignpbtypeandspeeddialsbytype(entry, speeds, res)
        return res

    def makeentry(self, counter, entry, data):
        """Creates pbentry object

        @param counter: The new entry number
        @param entry:   The phonebook object (as returned from 
convertphonebooktophone) that we
                        are using as the source
        @param data:    The main dictionary, which we use to get access to 
media indices amongst
                        other things
                        """
        e=self.protocolclass.pbentry()
        e.entrynumber=counter

        for k in entry:
            # special treatment for lists
            if k in ('emails', 'numbers', 'numbertypes','numberspeeds'):
                l=getattr(e,k)
                for item in entry[k]:
                    l.append(item)
            elif k=='ringtone':
                e.ringtone=self._findmediainindex(data['ringtone-index'], 
entry['ringtone'], entry['name'], 'ringtone')
            elif k=='msgringtone':
                e.msgringtone=self._findmediainindex(data['ringtone-index'], 
entry['msgringtone'], entry['name'], 'message ringtone')
            elif k=='wallpaper':
                e.wallpaper=self._findmediainindex(data['wallpaper-index'], 
entry['wallpaper'], entry['name'], 'wallpaper')
            elif k in e.getfields():
                # everything else we just set
                setattr(e,k,entry[k])

        return e

    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.group_id=groups[k]['group_id']
            e.rectype = 0x30
            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/pbookgroup.dat", buffer.getvalue())

    def savephonebook(self, data):
        "Saves out the phonebook"
        self.savegroups(data)

        progressmax=len(data['phonebook'].keys())
        # if we are going to write out speeddials, we have to re-read the 
entire
        # phonebook again
        if data.get('speeddials',None) is not None:
            progressmax+=len(data['phonebook'].keys())

        # To write the phone book, we scan through all existing entries
        # and record their record number and serials.
        # We then delete any entries that aren't in data
        # We then write out our records, using overwrite or append
        # commands as necessary
        serialupdates=[]
        existingpbook={} # keep track of the phonebook that is on the phone
        self.mode=self.MODENONE
        self.setmode(self.MODEBREW) # see note in getphonebook() for why 
this is necessary
        self.setmode(self.MODEPHONEBOOK)
        # similar loop to reading
        req=self.protocolclass.pbinforequest()
        res=self.sendpbcommand(req, self.protocolclass.pbinforesponse)
        numexistingentries=res.numentries
        self.log("There are %d existing entries" % (numexistingentries,))
        progressmax+=numexistingentries
        loop=xrange(0, numexistingentries)
        progresscur=0

        # reset cursor
        self.sendpbcommand(self.protocolclass.pbinitrequest(), 
self.protocolclass.pbinitresponse)
        for i in loop:
            ### Read current entry
            req=self.protocolclass.pbreadentryrequest()
            res=self.sendpbcommand(req, 
self.protocolclass.pbreadentryresponse)

            entry={ 'number':  res.entry.entrynumber, 'serial1':  
res.entry.serial1, 'name': res.entry.name}

            self.log("Reading entry "+`i`+" - "+str(entry['serial1'])+" - 
"+entry['name'])
            existingpbook[i]=entry
            self.progress(progresscur, progressmax, "existing 
"+entry['name'])
            #### Advance to next entry
            req=self.protocolclass.pbnextentryrequest()
            res=self.sendpbcommand(req, 
self.protocolclass.pbnextentryresponse)
            progresscur+=1
        # we have now looped around back to begining

        # Find entries that have been deleted
        pbook=data['phonebook']
        dellist=[]
        for i in loop:
            ii=existingpbook[i]
            serial=ii['serial1']
            item=self._findserial(serial, pbook)
            if item is None:
                dellist.append(i)

        progressmax+=len(dellist) # more work to do

        # Delete those entries
        for i in dellist:
            progresscur+=1
            numexistingentries-=1  # keep count right
            ii=existingpbook[i]
            self.log("Deleting entry "+`i`+" - "+str(ii['serial1'])+" - 
"+ii['name'])
            req=self.protocolclass.pbdeleteentryrequest()
            req.serial1=ii['serial1']
            req.serial2=ii['serial1']
            req.entrynumber=ii['number']
            self.sendpbcommand(req, 
self.protocolclass.pbdeleteentryresponse)
            self.progress(progresscur, progressmax, "Deleting "+ii['name'])
            # also remove them from existingpbook
            del existingpbook[i]

        # counter to keep track of record number (otherwise appends don't 
work)
        counter=0
        # Now rewrite out existing entries
        self.log("Rewrite existing entries")
        keys=existingpbook.keys()
        existingserials=[]
        keys.sort()  # do in same order as existingpbook
        for i in keys:
            progresscur+=1
            ii=pbook[self._findserial(existingpbook[i]['serial1'], pbook)]
            self.log("Rewriting entry "+`i`+" - "+ii['name'])
            self.progress(progresscur, progressmax, "Rewriting "+ii['name'])
            entry=self.makeentry(counter, ii, data)
            counter+=1
            existingserials.append(existingpbook[i]['serial1'])
            req=self.protocolclass.pbupdateentryrequest()
            req.entry=entry
            res=self.sendpbcommand(req, 
self.protocolclass.pbupdateentryresponse)
            serialupdates.append( ( ii["bitpimserial"],
                                    {'sourcetype': self.serialsname,
                                     'serial1': res.serial1,
                                     'sourceuniqueid': 
data['uniqueserial']})
                                  )
            assert ii['serial1']==res.serial1 # serial should stay the same

        # Finally write out new entries
        keys=pbook.keys()
        self.log("Write new entries")
        keys.sort()
        for i in keys:
            ii=pbook[i]
            if ii['serial1'] in existingserials:
                continue # already wrote this one out
            progresscur+=1
            entry=self.makeentry(counter, ii, data)
            counter+=1
            self.log("Appending entry "+ii['name'])
            self.progress(progresscur, progressmax, "Writing "+ii['name'])
            req=self.protocolclass.pbappendentryrequest()
            req.entry=entry
            res=self.sendpbcommand(req, 
self.protocolclass.pbappendentryresponse)
            serialupdates.append( ( ii["bitpimserial"],
                                     {'sourcetype': self.serialsname,
                                      'serial1': res.newserial,
                                     'sourceuniqueid': 
data['uniqueserial']})
                                  )
        data["serialupdates"]=serialupdates
        # deal with the speeddials
        if data.get("speeddials",None) is not None:
            # Yes, we have to read the ENTIRE phonebook again.  This
            # is because we don't know which entry numbers actually
            # got assigned to the various entries, and we need the
            # actual numbers to assign to the speed dials
            newspeeds={}
            if len(data['speeddials']):
                # Move cursor to begining of phonebook
                self.mode=self.MODENONE
                self.setmode(self.MODEBREW) # see note in getphonebook() for 
why this is necessary
                self.setmode(self.MODEPHONEBOOK)
                self.log("Searching for speed dials")
                self.sendpbcommand(self.protocolclass.pbinitrequest(), 
self.protocolclass.pbinitresponse)
                for i in range(len(pbook)):
                    ### Read current entry
                    req=self.protocolclass.pbreadentryrequest()
                    res=self.sendpbcommand(req, 
self.protocolclass.pbreadentryresponse)
                    self.log("Scanning "+res.entry.name)
                    progresscur+=1
                    # we have to turn the entry serial number into a bitpim 
serial
                    serial=res.entry.serial1
                    found=False
                    for bps, serials in serialupdates:
                        if serials['serial1']==serial:
                            # found the entry
                            for sd in data['speeddials']:
                                xx=data['speeddials'][sd]
                                if xx[0]==bps:
                                    found=True
                                    if(getattr(self.protocolclass, 
'SPEEDDIALINDEX', 0)==0):
                                        
newspeeds[sd]=(res.entry.entrynumber, xx[1])
                                    else:
                                        
newspeeds[sd]=(res.entry.entrynumber, 
res.entry.numbertypes[xx[1]].numbertype)
                                    
nt=self.protocolclass.numbertypetab[res.entry.numbertypes[xx[1]].numbertype]
                                    self.log("Speed dial #%d = %s (%s/%d)" % 
(sd, res.entry.name, nt, xx[1]))
                                    self.progress(progresscur, progressmax, 
"Speed dial #%d = %s (%s/%d)" % (sd, res.entry.name, nt, xx[1]))
                    if not found:
                        self.progress(progresscur, progressmax, "Scanning 
"+res.entry.name)
                    # move to next entry
                    
self.sendpbcommand(self.protocolclass.pbnextentryrequest(), 
self.protocolclass.pbnextentryresponse)

            self.progress(progressmax, progressmax, "Finished scanning")
            print "new speed dials is",newspeeds
            req=self.protocolclass.speeddials()
            for i in range(self.protocolclass.NUMSPEEDDIALS):
                sd=self.protocolclass.speeddial()
                if i in newspeeds:
                    sd.entry=newspeeds[i][0]
                    sd.number=newspeeds[i][1]
                req.speeddials.append(sd)
            buffer=prototypes.buffer()
            req.writetobuffer(buffer)

            # We check the existing speed dial file as changes require a 
reboot
            self.log("Checking existing speed dials")
            try:
                if 
buffer.getvalue()!=self.getfilecontents("pim/pbooksdial.dat"):
                    self.logdata("New speed dial file", buffer.getvalue(), 
req)
                    self.writefile("pim/pbooksdial.dat", buffer.getvalue())
                    self.log("Your phone has to be rebooted due to the speed 
dials changing")
                    self.progress(progressmax, progressmax, "Rebooting 
phone")
                    data["rebootphone"]=True
                else:
                    self.log("No changes to speed dials")
            except com_brew.BrewNoSuchFileException:
                self.log("speed dials file not found on phone")

        return data

#----- Calendar  
-----------------------------------------------------------------------

    def getcalendar(self,result): pass
    def savecalendar(self,result): pass

#----- Ringtones 
-----------------------------------------------------------------------

    def getringtones(self, result): pass
    def saveringtones(self, results, merge): pass

#----- Wallpapers 
-----------------------------------------------------------------------

    def getwallpapers(self, result): pass
    savewallpapers=None

#----- Phone Detection 
-----------------------------------------------------------------------

    esn_file_key='esn_file'
    esn_file='nvm/$SYS.ESN'


#----- Profile Class 
-----------------------------------------------------------------------
def phonize(str):
    """Convert the phone number into something the phone understands

    All digits, P, H, T, * and # are kept, everything else is removed"""
    return re.sub("[^0-9HPT#*]", "", str)

parentprofile=com_lgvx4400.Profile
class Profile(parentprofile):
    protocolclass=Phone.protocolclass
    serialsname=Phone.serialsname
    BP_Calendar_Version=3
    phone_manufacturer='LG Electronics Inc.'
    phone_model='LG-LX325'      # aka the PM325 from Sprint
    brew_required=True


    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={}

        speeds={}

        for pbentry in data['phonebook']:
            if len(results)==self.protocolclass.NUMPHONEBOOKENTRIES:
                break
            e={} # entry out
            entry=data['phonebook'][pbentry] # entry in
            try:
                # serials
                serial1=helper.getserial(entry.get('serials', []), 
self.serialsname, data['uniqueserial'], 'serial1', 0)

                e['serial1']=serial1
                for ss in entry["serials"]:
                    if ss["sourcetype"]=="bitpim":
                        e['bitpimserial']=ss
                assert e['bitpimserial']

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

                # categories/groups
                
cat=helper.makeone(helper.getcategory(entry.get('categories', []),0,1,32), 
None)
                if cat is None:
                    e['group']=0
                else:
                    key,value=self._getgroup(cat, data['groups'])
                    if key is not None:
                        e['group']=key
                    else:
                        # sorry no space for this category
                        e['group']=0

                # email addresses
                emails=helper.getemails(entry.get('emails', []) 
,0,self.protocolclass.NUMEMAILS,48)
                e['emails']=helper.filllist(emails, 
self.protocolclass.NUMEMAILS, "")

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

                # memo (-1 is to leave space for null terminator - not all 
software puts it in, but we do)
                e['memo']=helper.makeone(helper.getmemos(entry.get('memos', 
[]), 0, 1, self.protocolclass.MEMOLENGTH-1), "")

                # phone numbers
                # there must be at least one email address or phonenumber
                minnumbers=1
                if len(emails): minnumbers=0
                numbers=helper.getnumbers(entry.get('numbers', 
[]),minnumbers,self.protocolclass.NUMPHONENUMBERS)
                e['numberspeeds']=[]
                e['numbertypes']=[]
                e['numbers']=[]
                for numindex in range(len(numbers)):
                    num=numbers[numindex]
                    # deal with type
                    b4=len(e['numbertypes'])
                    type=num['type']
                    for i,t in enumerate(self.protocolclass.numbertypetab):
                        if type==t:
                            e['numbertypes'].append(i)
                            break
                        if t=='none': # conveniently last entry
                            e['numbertypes'].append(i)
                            break
                    if len(e['numbertypes'])==b4:
                        # we couldn't find a type for the number
                        continue
                    # deal with number
                    number=phonize(num['number'])
                    if len(number)==0:
                        # no actual digits in the number
                        continue
                    if len(number)>48: # get this number from somewhere 
sensible
                        # ::TODO:: number is too long and we have to either 
truncate it or ignore it?
                        number=number[:48] # truncate for moment
                    e['numbers'].append(number)
                    # deal with speed dial
                    sd=num.get("speeddial", -1)
                    if self.protocolclass.NUMSPEEDDIALS:
                        if sd>=self.protocolclass.FIRSTSPEEDDIAL and 
sd<=self.protocolclass.LASTSPEEDDIAL:
                            speeds[sd]=(e['bitpimserial'], numindex)

                e['numberspeeds']=helper.filllist(e['numberspeeds'], 5, 0)
                e['numbertypes']=helper.filllist(e['numbertypes'], 5, 0)
                e['numbers']=helper.filllist(e['numbers'], 5, "")

                # ringtones, wallpaper
                e['ringtone']=helper.getringtone(entry.get('ringtones', []), 
'call', None)
#                e['msgringtone']=helper.getringtone(entry.get('ringtones', 
[]), 'message', None)
                e['wallpaper']=helper.getwallpaper(entry.get('wallpapers', 
[]), 'call', None)

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

                results[pbentry]=e

            except helper.ConversionFailed:
                continue

        if self.protocolclass.NUMSPEEDDIALS:
            data['speeddials']=speeds
        data['phonebook']=results
        return data

    _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
         ('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
        )
p_lgpm325.p (application/octet-stream, 3.3 KB) - not displayed
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.