PyXR

c:\projects\bitpim\src \ phones \ com_lglx570.py



0001 ### BITPIM
0002 ###
0003 ### Copyright (C) 2008 Joe Pham <djpham@bitpim.org>
0004 ###
0005 ### This program is free software; you can redistribute it and/or modify
0006 ### it under the terms of the BitPim license as detailed in the LICENSE file.
0007 ###
0008 ### $Id: com_lglx570.py 4678 2008-08-13 23:46:56Z djpham $
0009 
0010 """Communicate with the LG LX570 (Musiq) cell phone"""
0011 
0012 import common
0013 import com_brew
0014 import com_lg
0015 import com_lgvx4400
0016 import p_lglx570
0017 import prototypes
0018 import helpids
0019 import sms
0020 
0021 #-------------------------------------------------------------------------------
0022 parentphone=com_lgvx4400.Phone
0023 class Phone(com_brew.RealBrewProtocol2, parentphone):
0024     "Talk to the LG LX570 (Musiq) cell phone"
0025 
0026     desc="LG-LX570"
0027     helpid=helpids.ID_PHONE_LGLX570
0028     protocolclass=p_lglx570
0029     serialsname='lglx570'
0030     my_model='LX570'
0031 
0032     builtinringtones=( 'Tone 1', 'Tone 2', 'Tone 3', 'Tone 4', 'Tone 5', 'Tone 6',
0033                        'Tone 7', 'Tone 8', 'Tone 9', 'Tone 10',
0034                        'Alert 1', 'Alert 2', 'Alert 3', 'Alert 4', 'Alert 5')
0035     ringtonelocations=(
0036         # offset, index file, files location, type, maximumentries
0037         (0x1100, "setas/voicememoRingerIndex.map", "VoiceDB/All/Memos", "voice memo", 35),
0038         (0x1200, "setas/mcRingerIndex.map", "melodyComposer", "my melodies", 20),
0039         )
0040     builtinimages=()
0041     imagelocations=(
0042         # offset, index file, files location, type, maximumentries
0043         (0x600, "setas/dcamIndex.map", "Dcam/Wallet", "images", 255),
0044         )
0045     wallpaperdirs=('Dcam/Review', 'Dcam/Wallet')
0046 
0047     def __init__(self, logtarget, commport):
0048         parentphone.__init__(self, logtarget, commport)
0049 
0050     # supporting routines for getfundamentals
0051     def get_esn(self, data=None):
0052         # return the ESN of this phone
0053         return self.get_brew_esn()
0054 
0055     def getgroups(self, result):
0056         self.log("Reading group information")
0057         _buf=prototypes.buffer(self.getfilecontents2(
0058             self.protocolclass.PB_FILENAME, 0x1E000, 2016))
0059         _groups={}
0060         _grp=self.protocolclass.pbgroup()
0061         while True:
0062             _grp.readfrombuffer(_buf)
0063             if _grp.valid:
0064                 _groups[_grp.groupid]={ 'name': _grp.name }
0065             else:
0066                 break
0067         result['groups']=_groups
0068         return _groups
0069 
0070     # Media stuff---------------------------------------------------------------
0071     def getwallpaperindices(self, results):
0072         # index the list of files in known camera dirs
0073         _res={}
0074         _idx=1
0075         for _dir in self.wallpaperdirs:
0076             for _file in self.listfiles(_dir):
0077                 _res[_idx]={ 'name': common.basename(_file),
0078                              'filename': _file,
0079                              'origin': 'images' }
0080                 _idx+=1
0081         results['wallpaper-index']=_res
0082         return results
0083 
0084     def getwallpapers(self, result):
0085         # retrieve all camera images
0086         _media={}
0087         for _wp in result.get('wallpaper-index', {}).values():
0088             _media[_wp['name']]=self.getfilecontents(_wp['filename'], True)
0089         result['wallpapers']=_media
0090         return result
0091 
0092     def getringtoneindices(self, results):
0093         return self.getmediaindex(self.builtinringtones,
0094                                   self.ringtonelocations,
0095                                   results, 'ringtone-index')
0096 
0097     def _fix_melodies_filename(self, name):
0098         # the "My Melodies" file name must have '.mid' extension and
0099         # no other '.' character.
0100         if name[-4:]=='.mid':
0101             # name already has the correct extenstion
0102             _new_name=name[:-4]
0103         else:
0104             _new_name=name
0105         return _new_name.replace('.', '_')+'.mid'
0106 
0107     def _update_media_file(self, name, data):
0108         # Check the if the size of the media file is different than the data
0109         # and rewrite the file if necessary.
0110         self.log('Updating media file: %s'%name)
0111         _filename='%s/%s'%(self.protocolclass.RT_MC_PATH, name)
0112         try:
0113             _stat=self.statfile(_filename)
0114         except com_brew.BrewNoSuchFileException:
0115             _stat=None
0116         if _stat and _stat.get('size', None)==len(data):
0117             # file size and data size are the same, bail
0118             self.log('File %s is unchanged'%_filename)
0119             return
0120         self.writefile(_filename, data)
0121 
0122     def saveringtones(self, results, merge):
0123         # Saving My Melodies media files to be used as ringtones
0124         _media_index=results.get('ringtone-index', {})
0125         _media=results.get('ringtone', {})
0126         # build a dict of my "my melodies" (file) name and data
0127         _melodies_data={}
0128         for _item in _media.values():
0129             if _item.get('origin', None)=='my melodies':
0130                 _melodies_data[self._fix_melodies_filename(_item['name'])]=_item['data']
0131         # read the existing index file
0132         _indexfile=self.readobject(self.protocolclass.RT_MC_INDEX_FILENAME,
0133                                    self.protocolclass.indexfile,
0134                                    logtitle='Reading MC Index File',
0135                                    uselocalfs=False)
0136         # go through the index file and rewrite media files as needed
0137         self.log('Updating media files')
0138         for _idx in range(_indexfile.numactiveitems):
0139             _item=_indexfile.items[_idx]
0140             if _item.name and _melodies_data.has_key(_item.name):
0141                 # check the file size and rewrite the file as needed
0142                 self._update_media_file(_item.name, _melodies_data[_item.name])
0143                 # remove the entry from the dict
0144                 del _melodies_data[_item.name]
0145         # go through the index file and add new items
0146         _empty_index=range(_indexfile.numactiveitems, len(_indexfile.items))
0147         _available_media=_melodies_data.keys()
0148         self.log('Adding new media files')
0149         for _idx, _name in zip(_empty_index, _available_media):
0150             # update the index entry
0151             _indexfile.items[_idx].name=_name
0152             # write out the media file
0153             self._update_media_file(_name, _melodies_data[_name])
0154             # update the count
0155             _indexfile.numactiveitems+=1
0156         # write the new index file
0157         self.writeobject(self.protocolclass.RT_MC_INDEX_FILENAME,
0158                          _indexfile, logtitle='Writing new MC Index file',
0159                          uselocalfs=False)
0160         # and re-read the index file
0161         self.getringtoneindices(results)
0162         return results
0163 
0164     # Phonebook stuff-----------------------------------------------------------
0165     def _assignpbtypeandspeeddialsbyposition(self, entry, speeds, res):
0166         # numbers
0167         res['numbers']=[]
0168         for i in range(self.protocolclass.NUMPHONENUMBERS):
0169             num=entry.numbers[i].number
0170             numtype=entry.numbertypes[i].numbertype
0171             if len(num):
0172                 t=self.protocolclass.numbertypetab[numtype]
0173                 if t[-1]=='2':
0174                     t=t[:-1]
0175                 _numdict={ 'number': num, 'type': t }
0176                 if entry.speeddials[i].speeddial!=0xff:
0177                     _numdict['speeddial']=entry.speeddials[i].speeddial
0178                 res['numbers'].append(_numdict)
0179         return res
0180 
0181     # Copy this from the VX4400 module, with changes to support for
0182     # different handling of speed dials data
0183     def savephonebook(self, data):
0184         "Saves out the phonebook"
0185         # we can't save groups 
0186         progressmax=len(data['phonebook'].keys())
0187 
0188         # To write the phone book, we scan through all existing entries
0189         # and record their record number and serials.
0190         # We then delete any entries that aren't in data
0191         # We then write out our records, using overwrite or append
0192         # commands as necessary
0193         serialupdates=[]
0194         existingpbook={} # keep track of the phonebook that is on the phone
0195         self.mode=self.MODENONE
0196         self.setmode(self.MODEBREW) # see note in getphonebook() for why this is necessary
0197         self.setmode(self.MODEPHONEBOOK)
0198         # similar loop to reading
0199         req=self.protocolclass.pbinforequest()
0200         res=self.sendpbcommand(req, self.protocolclass.pbinforesponse)
0201         numexistingentries=res.numentries
0202         if numexistingentries<0 or numexistingentries>1000:
0203             self.log("The phone is lying about how many entries are in the phonebook so we are doing it the hard way")
0204             numexistingentries=0
0205             firstserial=None
0206             loop=xrange(0,1000)
0207             hardway=True
0208         else:
0209             self.log("There are %d existing entries" % (numexistingentries,))
0210             progressmax+=numexistingentries
0211             loop=xrange(0, numexistingentries)
0212             hardway=False
0213         progresscur=0
0214         # reset cursor
0215         self.sendpbcommand(self.protocolclass.pbinitrequest(), self.protocolclass.pbinitresponse)
0216         for i in loop:
0217             ### Read current entry
0218             if hardway:
0219                 numexistingentries+=1
0220                 progressmax+=1
0221             req=self.protocolclass.pbreadentryrequest()
0222             res=self.sendpbcommand(req, self.protocolclass.pbreadentryresponse)
0223             
0224             entry={ 'number':  res.entry.entrynumber, 'serial1':  res.entry.serial1,
0225                     'serial2': res.entry.serial2, 'name': res.entry.name}
0226             assert entry['serial1']==entry['serial2'] # always the same
0227             self.log("Reading entry "+`i`+" - "+entry['name'])
0228             if hardway and firstserial is None:
0229                 firstserial=res.entry.serial1
0230             existingpbook[i]=entry 
0231             self.progress(progresscur, progressmax, "existing "+entry['name'])
0232             #### Advance to next entry
0233             req=self.protocolclass.pbnextentryrequest()
0234             res=self.sendpbcommand(req, self.protocolclass.pbnextentryresponse)
0235             progresscur+=1
0236             if hardway:
0237                 # look to see if we have looped
0238                 if res.serial==firstserial or res.serial==0:
0239                     break
0240         # we have now looped around back to begining
0241 
0242         # Find entries that have been deleted
0243         pbook=data['phonebook']
0244         dellist=[]
0245         for i in range(0, numexistingentries):
0246             ii=existingpbook[i]
0247             serial=ii['serial1']
0248             item=self._findserial(serial, pbook)
0249             if item is None:
0250                 dellist.append(i)
0251 
0252         progressmax+=len(dellist) # more work to do
0253 
0254         # Delete those entries
0255         for i in dellist:
0256             progresscur+=1
0257             numexistingentries-=1  # keep count right
0258             ii=existingpbook[i]
0259             self.log("Deleting entry "+`i`+" - "+ii['name'])
0260             req=self.protocolclass.pbdeleteentryrequest()
0261             req.serial1=ii['serial1']
0262             req.serial2=ii['serial2']
0263             req.entrynumber=ii['number']
0264             self.sendpbcommand(req, self.protocolclass.pbdeleteentryresponse)
0265             self.progress(progresscur, progressmax, "Deleting "+ii['name'])
0266             # also remove them from existingpbook
0267             del existingpbook[i]
0268 
0269         # counter to keep track of record number (otherwise appends don't work)
0270         counter=0
0271         # Now rewrite out existing entries
0272         keys=existingpbook.keys()
0273         existingserials=[]
0274         keys.sort()  # do in same order as existingpbook
0275         for i in keys:
0276             progresscur+=1
0277             ii=pbook[self._findserial(existingpbook[i]['serial1'], pbook)]
0278             self.log("Rewriting entry "+`i`+" - "+ii['name'])
0279             self.progress(progresscur, progressmax, "Rewriting "+ii['name'])
0280             entry=self.makeentry(counter, ii, data)
0281             counter+=1
0282             existingserials.append(existingpbook[i]['serial1'])
0283             req=self.protocolclass.pbupdateentryrequest()
0284             req.entry=entry
0285             res=self.sendpbcommand(req, self.protocolclass.pbupdateentryresponse)
0286             serialupdates.append( ( ii["bitpimserial"],
0287                                     {'sourcetype': self.serialsname, 'serial1': res.serial1, 'serial2': res.serial1,
0288                                      'sourceuniqueid': data['uniqueserial']})
0289                                   )
0290             assert ii['serial1']==res.serial1 # serial should stay the same
0291 
0292         # Finally write out new entries
0293         keys=pbook.keys()
0294         keys.sort()
0295         for i in keys:
0296             try:
0297                 ii=pbook[i]
0298                 if ii['serial1'] in existingserials:
0299                     continue # already wrote this one out
0300                 progresscur+=1
0301                 entry=self.makeentry(counter, ii, data)
0302                 counter+=1
0303                 self.log("Appending entry "+ii['name'])
0304                 self.progress(progresscur, progressmax, "Writing "+ii['name'])
0305                 req=self.protocolclass.pbappendentryrequest()
0306                 req.entry=entry
0307                 res=self.sendpbcommand(req, self.protocolclass.pbappendentryresponse)
0308                 serialupdates.append( ( ii["bitpimserial"],
0309                                          {'sourcetype': self.serialsname, 'serial1': res.newserial, 'serial2': res.newserial,
0310                                          'sourceuniqueid': data['uniqueserial']})
0311                                   )
0312             except:
0313                 self.log('Failed to write entry: '+ii['name'])
0314                 if __debug__:
0315                     raise
0316         data["serialupdates"]=serialupdates
0317         self.progress(progressmax, progressmax, "Rebooting phone")
0318         data["rebootphone"]=True
0319         return data
0320                     
0321     def makeentry(self, counter, entry, data):
0322         """Creates pbentry object
0323 
0324         @param counter: The new entry number
0325         @param entry:   The phonebook object (as returned from convertphonebooktophone) that we
0326                         are using as the source
0327         @param data:    The main dictionary, which we use to get access to media indices amongst
0328                         other things
0329                         """
0330         e=self.protocolclass.pbentry()
0331         e.entrynumber=counter
0332         for k in entry:
0333             # special treatment for lists
0334             if k in ('emails', 'numbers', 'numbertypes', 'speeddials'):
0335                 l=getattr(e,k)
0336                 for item in entry[k]:
0337                     l.append(item)
0338             elif k=='ringtone':
0339                 e.ringtone=self._findmediainindex(data['ringtone-index'], entry['ringtone'], entry['name'], 'ringtone')
0340             elif k in e.getfields():
0341                 # everything else we just set
0342                 setattr(e,k,entry[k])
0343         return e
0344 
0345     # SMS Stuff ----------------------------------------------------------------
0346     def _getquicktext(self):
0347         quicks=[]
0348         try:
0349             sf=self.readobject(self.protocolclass.SMS_CANNED_FILENAME,
0350                                self.protocolclass.sms_canned_file,
0351                                logtitle="SMS quicktext file sms/mediacan000.dat",
0352                                uselocalfs=False)
0353             for rec in sf.msgs:
0354                 if rec.msg:
0355                     quicks.append({ 'text': rec.msg,
0356                                     'type': sms.CannedMsgEntry.user_type })
0357         except com_brew.BrewNoSuchFileException:
0358             pass # do nothing if file doesn't exist
0359         return quicks
0360 
0361     def _getinboxmessage(self, sf):
0362         entry=sms.SMSEntry()
0363         entry.folder=entry.Folder_Inbox
0364         entry.datetime="%d%02d%02dT%02d%02d%02d" % (sf.GPStime)
0365         entry._from=self._getsender(sf.sender, sf.sender_length)
0366         entry.subject=sf.subject
0367         entry.locked=sf.locked
0368         entry.priority=sms.SMSEntry.Priority_Normal
0369         entry.read=sf.read
0370         entry.text=sf.msg
0371         entry.callback=sf.callback
0372         return entry
0373 
0374     def _getoutboxmessage(self, sf):
0375         entry=sms.SMSEntry()
0376         entry.folder=entry.Folder_Saved if sf.saved \
0377                       else entry.Folder_Sent
0378         entry.datetime="%d%02d%02dT%02d%02d00" % ((sf.timesent))
0379         # add all the recipients
0380         for r in sf.recipients:
0381             if r.number:
0382                 confirmed=(r.status==2)
0383                 confirmed_date=None
0384                 if confirmed:
0385                     confirmed_date="%d%02d%02dT%02d%02d00" % r.time
0386                 entry.add_recipient(r.number, confirmed, confirmed_date)
0387         entry.subject=sf.msg[:28]
0388         entry.text=sf.msg
0389         entry.priority=entry.Priority_High if sf.priority else \
0390                         entry.Priority_Normal
0391         entry.locked=sf.locked
0392         entry.callback=sf.callback
0393         return entry
0394 
0395     def _readsms(self):
0396         res={}
0397         # go through the sms directory looking for messages
0398         for item in self.listfiles("sms").values():
0399             folder=None
0400             for f,pat in self.protocolclass.SMS_PATTERNS.items():
0401                 if pat.match(item['name']):
0402                     folder=f
0403                     break
0404             if folder:
0405                 buf=prototypes.buffer(self.getfilecontents(item['name'], True))
0406                 self.logdata("SMS message file " +item['name'], buf.getdata())
0407             if folder=='Inbox':
0408                 sf=self.protocolclass.sms_in()
0409                 sf.readfrombuffer(buf, logtitle="SMS inbox item")
0410                 entry=self._getinboxmessage(sf)
0411                 res[entry.id]=entry
0412             elif folder=='Sent':
0413                 sf=self.protocolclass.sms_out()
0414                 sf.readfrombuffer(buf, logtitle="SMS sent item")
0415                 entry=self._getoutboxmessage(sf)
0416                 res[entry.id]=entry
0417 
0418         return res 
0419 
0420     def _setquicktext(self, result):
0421         sf=self.protocolclass.sms_canned_file()
0422         quicktext=result.get('canned_msg', [])[:self.protocolclass.SMS_CANNED_MAX_ITEMS]
0423         if quicktext:
0424             for entry in quicktext:
0425                 msg_entry=self.protocolclass.sms_quick_text()
0426                 msg_entry.msg=entry['text'][:self.protocolclass.SMS_CANNED_MAX_LENGTH-1]
0427                 sf.msgs.append(msg_entry)
0428             self.writeobject(self.protocolclass.SMS_CANNED_FILENAME,
0429                              sf, logtitle="Writing quicktext",
0430                              uselocalfs=False)
0431 
0432 #-------------------------------------------------------------------------------
0433 parentprofile=com_lgvx4400.Profile
0434 class Profile(parentprofile):
0435     protocolclass=Phone.protocolclass
0436     serialsname=Phone.serialsname
0437 
0438     BP_Calendar_Version=3
0439     phone_manufacturer='LG Electronics Inc'
0440     phone_model='LX570'
0441 
0442     # Need to update this
0443     WALLPAPER_WIDTH=176
0444     WALLPAPER_HEIGHT=220
0445     # outside LCD: 128x160
0446 
0447     imageorigins={}
0448     imageorigins.update(common.getkv(parentprofile.stockimageorigins, "images"))
0449     def GetImageOrigins(self):
0450         return self.imageorigins
0451 
0452     ringtoneorigins=('my melodies', 'voice memo')
0453     excluded_ringtone_origins=('ringers', 'sounds', 'my melodies', 'voice memo')
0454     excluded_wallpaper_origins=('images',)
0455 
0456     # our targets are the same for all origins
0457     # Need to work the correct resolutions
0458     imagetargets={}
0459     imagetargets.update(common.getkv(parentprofile.stockimagetargets, "wallpaper",
0460                                       {'width': 176, 'height': 220, 'format': "JPEG"}))
0461     imagetargets.update(common.getkv(parentprofile.stockimagetargets, "outsidelcd",
0462                                       {'width': 128, 'height': 160, 'format': "JPEG"}))
0463 
0464     def GetTargetsForImageOrigin(self, origin):
0465         return self.imagetargets
0466 
0467            
0468     def convertphonebooktophone(self, helper, data):
0469         """Converts the data to what will be used by the phone
0470 
0471         @param data: contains the dict returned by getfundamentals
0472                      as well as where the results go"""
0473         results={}
0474 
0475         self.normalisegroups(helper, data)
0476 
0477         for pbentry in data['phonebook']:
0478             if len(results)==self.protocolclass.NUMPHONEBOOKENTRIES:
0479                 break
0480             e={} # entry out
0481             entry=data['phonebook'][pbentry] # entry in
0482             try:
0483                 # serials
0484                 serial1=helper.getserial(entry.get('serials', []), self.serialsname, data['uniqueserial'], 'serial1', 0)
0485                 serial2=helper.getserial(entry.get('serials', []), self.serialsname, data['uniqueserial'], 'serial2', serial1)
0486 
0487                 e['serial1']=serial1
0488                 e['serial2']=serial2
0489                 for ss in entry["serials"]:
0490                     if ss["sourcetype"]=="bitpim":
0491                         e['bitpimserial']=ss
0492                 assert e['bitpimserial']
0493 
0494                 # name
0495                 e['name']=helper.getfullname(entry.get('names', []),1,1,22)[0]
0496 
0497                 # categories/groups
0498                 cat=helper.makeone(helper.getcategory(entry.get('categories', []),0,1,22), None)
0499                 if cat is None:
0500                     e['group']=0
0501                 else:
0502                     key,value=self._getgroup(cat, data['groups'])
0503                     if key is not None:
0504                         e['group']=key
0505                     else:
0506                         # sorry no space for this category
0507                         e['group']=0
0508 
0509                 # email addresses
0510                 emails=helper.getemails(entry.get('emails', []) ,0,self.protocolclass.NUMEMAILS,48)
0511                 e['emails']=helper.filllist(emails, self.protocolclass.NUMEMAILS, "")
0512 
0513                 # url
0514                 e['url']=helper.makeone(helper.geturls(entry.get('urls', []), 0,1,48), "")
0515 
0516                 # memo (-1 is to leave space for null terminator - not all software puts it in, but we do)
0517                 e['memo']=helper.makeone(helper.getmemos(entry.get('memos', []), 0, 1, self.protocolclass.MEMOLENGTH-1), "")
0518 
0519                 # phone numbers
0520                 # there must be at least one email address or phonenumber
0521                 minnumbers=1
0522                 if len(emails): minnumbers=0
0523                 numbers=helper.getnumbers(entry.get('numbers', []),minnumbers,self.protocolclass.NUMPHONENUMBERS)
0524                 e['numbertypes']=[]
0525                 e['numbers']=[]
0526                 e['speeddials']=[]
0527                 for numindex in range(len(numbers)):
0528                     num=numbers[numindex]
0529                     # deal with type
0530                     b4=len(e['numbertypes'])
0531                     type=num['type']
0532                     for i,t in enumerate(self.protocolclass.numbertypetab):
0533                         if type==t:
0534                             # some voodoo to ensure the second home becomes home2
0535                             if i in e['numbertypes'] and t[-1]!='2':
0536                                 type+='2'
0537                                 continue
0538                             e['numbertypes'].append(i)
0539                             break
0540                         if t=='none': # conveniently last entry
0541                             e['numbertypes'].append(i)
0542                             break
0543                     if len(e['numbertypes'])==b4:
0544                         # we couldn't find a type for the number
0545                         helper.add_error_message('Number %s (%s/%s) not supported and ignored.'%
0546                                                  (num['number'], e['name'], num['type']))
0547                         continue 
0548                     # deal with number
0549                     number=self.phonize(num['number'])
0550                     if len(number)==0:
0551                         # no actual digits in the number
0552                         continue
0553                     if len(number)>48: # get this number from somewhere sensible
0554                         # ::TODO:: number is too long and we have to either truncate it or ignore it?
0555                         number=number[:48] # truncate for moment
0556                     e['numbers'].append(number)
0557                     # deal with speed dial
0558                     sd=num.get("speeddial", -1)
0559                     if self.protocolclass.NUMSPEEDDIALS:
0560                         if sd>=self.protocolclass.FIRSTSPEEDDIAL and sd<=self.protocolclass.LASTSPEEDDIAL:
0561                             e['speeddials'].append(sd)
0562                         else:
0563                             e['speeddials'].append(0xff)
0564 
0565                 if len(e['numbers'])<minnumbers:
0566                     # we couldn't find any numbers
0567                     # for this entry, so skip it, entries with no numbers cause error
0568                     helper.add_error_message("Name: %s. No suitable numbers or emails found" % e['name'])
0569                     continue 
0570                 e['numbertypes']=helper.filllist(e['numbertypes'], 5, 0)
0571                 e['numbers']=helper.filllist(e['numbers'], 5, "")
0572                 e['speeddials']=helper.filllist(e['speeddials'], 5, 0xff)
0573 
0574                 # ringtones, wallpaper
0575                 e['ringtone']=helper.getringtone(entry.get('ringtones', []), 'call', None)
0576 
0577 
0578                 results[pbentry]=e
0579                 
0580             except helper.ConversionFailed:
0581                 continue
0582 
0583         data['phonebook']=results
0584         return data
0585 
0586     _supportedsyncs=(
0587         ('phonebook', 'read', None),   # all phonebook reading
0588 ##        ('calendar', 'read', None),    # all calendar reading
0589         ('wallpaper', 'read', None),   # all wallpaper reading
0590         ('ringtone', 'read', None),    # all ringtone reading
0591 ##        ('call_history', 'read', None),# all call history list reading
0592         ('sms', 'read', None),         # all SMS list reading
0593         ('memo', 'read', None),        # all memo list reading
0594         ('phonebook', 'write', 'OVERWRITE'),  # only overwriting phonebook
0595 ##        ('calendar', 'write', 'OVERWRITE'),   # only overwriting calendar
0596 ##        ('wallpaper', 'write', 'MERGE'),      # merge and overwrite wallpaper
0597 ##        ('wallpaper', 'write', 'OVERWRITE'),
0598         ('ringtone', 'write', 'MERGE'),       # merge and overwrite ringtone
0599 ##        ('ringtone', 'write', 'OVERWRITE'),
0600         ('sms', 'write', 'OVERWRITE'),        # all SMS list writing
0601         ('memo', 'write', 'OVERWRITE'),       # all memo list writing
0602 ##        ('playlist', 'read', 'OVERWRITE'),
0603 ##        ('playlist', 'write', 'OVERWRITE'),
0604         )
0605 
0606     field_color_data={
0607         'phonebook': {
0608             'name': {
0609                 'first': 1, 'middle': 1, 'last': 1, 'full': 1,
0610                 'nickname': 0, 'details': 1 },
0611             'number': {
0612                 'type': 5, 'speeddial': 5, 'number': 5,
0613                 'details': 5,
0614                 'ringtone': False, 'wallpaper': False },
0615             'email': 3,
0616             'email_details': {
0617                 'emailspeeddial': False, 'emailringtone': False,
0618                 'emailwallpaper': False },
0619             'address': {
0620                 'type': 0, 'company': 0, 'street': 0, 'street2': 0,
0621                 'city': 0, 'state': 0, 'postalcode': 0, 'country': 0,
0622                 'details': 0 },
0623             'url': 1,
0624             'memo': 1,
0625             'category': 1,
0626             'wallpaper': 0,
0627             'ringtone': 0,
0628             'storage': 0,
0629             },
0630         'calendar': {
0631             'description': False, 'location': False, 'allday': False,
0632             'start': False, 'end': False, 'priority': False,
0633             'alarm': False, 'vibrate': False,
0634             'repeat': False,
0635             'memo': False,
0636             'category': False,
0637             'wallpaper': False,
0638             'ringtone': False,
0639             },
0640         'memo': {
0641             'subject': False,
0642             'date': False,
0643             'secret': False,
0644             'category': False,
0645             'memo': True,
0646             },
0647         'todo': {
0648             'summary': False,
0649             'status': False,
0650             'due_date': False,
0651             'percent_complete': False,
0652             'completion_date': False,
0653             'private': False,
0654             'priority': False,
0655             'category': False,
0656             'memo': False,
0657             },
0658         }
0659 

Generated by PyXR 0.9.4