PyXR

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



0001 #!/usr/bin/env python
0002 
0003 ### BITPIM
0004 ###
0005 ### 
0006 ###
0007 ### This program is free software; you can redistribute it and/or modify
0008 ### it under the terms of the BitPim license as detailed in the LICENSE file.
0009 ### by David Ritter 7/10/07
0010 ### Write to phonebook working msg ringtones not supported
0011 ### Write to Calendar, wallpaper, and ringtones is working
0012 ###
0013 ### $Id: com_lgax8600.py 4595 2008-02-14 03:04:01Z djpham $
0014 
0015 """
0016 Communicate with the LG AX8600 cell phone
0017 """
0018 # standard modules
0019 import re
0020 import time
0021 import cStringIO
0022 import sha
0023 import datetime
0024 
0025 # BitPim modules
0026 import common
0027 import commport
0028 import fileinfo
0029 import guihelper
0030 import os
0031 import copy
0032 import com_lgvx4400
0033 import p_brew
0034 import p_lgax8600
0035 import com_lgvx8100
0036 import com_brew
0037 import com_phone
0038 import com_lg
0039 import prototypes
0040 import bpcalendar
0041 import call_history
0042 import sms
0043 import memo
0044 import playlist
0045 import helpids
0046 
0047 #-------------------------------------------------------------------------------
0048 #Went back to vx8100 to inherit to avoid LGUncountedIndexedMedia
0049 
0050 parentphone=com_lgvx8100.Phone
0051 class Phone(parentphone):
0052     "Talk to LG AX-8600 cell phone"
0053 
0054     desc="LG-AX8600"
0055     helpid=helpids.ID_PHONE_LGAX8600
0056     protocolclass=p_lgax8600
0057     serialsname='lgax8600'
0058 
0059     external_storage_root='mmc1/'
0060 
0061     my_model='AX8600'
0062 #Media locations for reading FROM the phone
0063     builtinringtones= ()
0064     ringtonelocations= (
0065        # type       index-file   size-file directory-to-use lowest-index-to-use maximum-entries type-major icon index_offset
0066  
0067         ( 'sounds', 'dload/lg_mysound.dat', 'dload/lg_mysoundsize.dat', 'brew/media/lk/ms', 150, 100, 0x402, 0, 0),
0068 
0069  #       ( 'sounds(sd)', 'dload/sd_sound.dat',  'mmc1/lg_media/other_sounds', '', 100, 0x02,  None),
0070 
0071         )
0072 
0073     calendarlocation="sch/schedule.dat"
0074     calendarexceptionlocation="sch/schexception.dat"
0075     calenderrequiresreboot=1
0076     memolocation="sch/memo.dat"
0077 
0078     builtinwallpapers = ()
0079     wallpaperlocations= (
0080 
0081         # type       index-file   size-file directory-to-use lowest-index-to-use maximum-entries type-major icon index_offset
0082         ( 'images', 'dload/lg_image.dat', 'dload/lg_imagesize.dat', 'brew/media/lk/mp', 150 , 100, 0x400, 0, 0),
0083 
0084  #       ( 'images(sd)', 'dload/sd_image.dat', 'mmc1/lg_media/other_image',    '',          100, 0x10, None),
0085  #       ( 'video',      'dload/lg_video.dat', 'brew/media/lk/mf', '',          100, 0x10, None),
0086  #       ( 'video(sd)',  'dload/sd_video.dat', 'mmc1/lg_media/other_video',   '',          100, 0x13, None),
0087         )
0088 #    _rs_path=()
0089     # for removable media (miniSD cards)
0090     _rs_path='mmc1/'
0091     _rs_ringers_path=_rs_path+'lg_media/other_sounds'
0092     _rs_images_path=_rs_path+'lg_media/other_image'
0093 
0094 #Media locations for writing TO the phone
0095 
0096     media_info={ 'sounds': {
0097              'localpath': 'brew/media/lk/ms',
0098              'rspath': None,
0099              'vtype': protocolclass.MEDIA_TYPE_SOUND,
0100              'icon': protocolclass.MEDIA_IMAGE_DEFAULT_ICON,
0101              'index': 150,
0102              'maxsize': 100,
0103              'indexfile': 'dload/lg_mysound.dat',
0104              'sizefile': 'dload/lg_mysoundsize.dat',
0105              'dunno': 0,
0106              'date': False,
0107              'dunno1': 0 },
0108          'images': {
0109              'localpath': 'brew/media/lk/mp',
0110              'rspath': None,
0111              'vtype': protocolclass.MEDIA_TYPE_IMAGE,
0112              'icon': protocolclass.MEDIA_IMAGE_DEFAULT_ICON,
0113              'index': 150,
0114              'maxsize': 100,
0115              'indexfile': 'dload/lg_image.dat',
0116              'sizefile': 'dload/lg_imagesize.dat',
0117              'dunno': 0,
0118              'date': False,
0119              'dunno1': 0 },
0120 #         'video': {
0121 #             'localpath': 'brew/16452/mf',
0122 #             'rspath': None,
0123 #             'vtype': protocolclass.MEDIA_TYPE_VIDEO,
0124 #             'icon': protocolclass.MEDIA_VIDEO_DEFAULT_ICON,
0125 #             'index': 1000,
0126 #             'maxsize': 155,
0127 #             'indexfile': 'dload/video.dat',
0128 #             'sizefile': 'dload/videosize.dat',
0129 #             'dunno': 0, 'date': True },
0130          }
0131         
0132 
0133 
0134     def __init__(self, logtarget, commport):
0135         parentphone.__init__(self, logtarget, commport)
0136         p_brew.PHONE_ENCODING=self.protocolclass.PHONE_ENCODING
0137         self.mode=self.MODENONE
0138 
0139 
0140     def setDMversion(self):
0141         self._DMv5=True
0142         self._timeout = 30
0143 
0144     def get_esn(self, data=None):
0145         # return the ESN of this phone
0146         return self.get_brew_esn()
0147 
0148     def get_detect_data(self, res):
0149         com_lgvx8100.Phone.get_detect_data(self, res)
0150         res[self.esn_file_key]=self.get_esn()
0151 
0152     #------------------------------------------------------
0153     # must be included for difference between alltel and verizon
0154     def getcallhistory(self, result):
0155         res={}
0156         # read the incoming call history file
0157         # the telus lg8100 programmers were on something when they wrote their code.
0158         if hasattr(self.protocolclass, 'this_takes_the_prize_for_the_most_brain_dead_call_history_file_naming_ive_seen'):
0159             self._readhistoryfile("pim/missed_log.dat", 'Incoming', res)
0160             self._readhistoryfile("pim/outgoing_log.dat", 'Missed', res)
0161             self._readhistoryfile("pim/incoming_log.dat", 'Outgoing', res)
0162         else:
0163             self._readhistoryfile("pim/missed_log.dat", 'Missed', res)
0164             self._readhistoryfile("pim/outgoing_log.dat", 'Outgoing', res)
0165             self._readhistoryfile("pim/incoming_log.dat", 'Incoming', res)
0166             self._readhistoryfile("pim/data_log.data", 'Data', res)
0167         result['call_history']=res
0168         return result
0169 
0170     # Don't need this if there're no changes
0171 ##    def _readhistoryfile(self, fname, folder, res):
0172 ##        try:
0173 ##            buf=prototypes.buffer(self.getfilecontents(fname))
0174 ##            ch=self.protocolclass.callhistory()
0175 ##            ch.readfrombuffer(buf, logtitle="Call History")
0176 ##            for call_idx in range(ch.numcalls):
0177 ##                call=ch.calls[call_idx]
0178 ##                if call.number=='' and call.name=='':
0179 ##                        continue
0180 ##                entry=call_history.CallHistoryEntry()
0181 ##                entry.folder=folder
0182 ##                if call.duration:
0183 ##                    entry.duration=call.duration
0184 ##                entry.datetime=((call.GPStime))
0185 ##                if call.number=='': # restricted calls have no number
0186 ##                    entry.number=call.name
0187 ##                else:
0188 ##                    entry.number=call.number
0189 ##                    if call.name:
0190 ##                        entry.name=call.name
0191 ##                res[entry.id]=entry
0192 ##        except (com_brew.BrewNoSuchFileException,
0193 ##                IndexError):
0194 ##            pass # do nothing if file doesn't exist or is corrupted
0195 ##        return
0196 
0197     def getcalendar(self,result):
0198         res={}
0199         # Read exceptions file first
0200         try:
0201             buf=prototypes.buffer(self.getfilecontents(self.calendarexceptionlocation))
0202             ex=self.protocolclass.scheduleexceptionfile()
0203             ex.readfrombuffer(buf, logtitle="Calendar exceptions")
0204             exceptions={}
0205             for i in ex.items:
0206                 try:
0207                     exceptions[i.pos].append( (i.year,i.month,i.day) )
0208                 except KeyError:
0209                     exceptions[i.pos]=[ (i.year,i.month,i.day) ]
0210         except com_brew.BrewNoSuchFileException:
0211             exceptions={}
0212 
0213         # Now read schedule
0214         try:
0215             buf=prototypes.buffer(self.getfilecontents(self.calendarlocation))
0216             if len(buf.getdata())<3:
0217                 # file is empty, and hence same as non-existent
0218                 raise com_brew.BrewNoSuchFileException()
0219             sc=self.protocolclass.schedulefile()
0220             sc.readfrombuffer(buf, logtitle="Calendar")
0221             for event in sc.events:
0222                 # the vx8100 has a bad entry when the calender is empty
0223                 # stop processing the calender when we hit this record
0224                 if event.pos==0: #invalid entry
0225                     continue
0226                 entry=bpcalendar.CalendarEntry()
0227                 entry.desc_loc=event.description
0228                 try: # delete events are still in the calender file but have garbage dates
0229                     entry.start=event.start
0230                     if self.protocolclass.CALENDAR_HAS_SEPARATE_END_TIME_AND_DATE:
0231                         if event.repeat[0] == 0:           # MIC:  If non-repeating event
0232                             entry.end = event.end_time     # MIC:  Set entry.end to full end_time
0233                         else:
0234                             _,_,_,hour,minute=event.end_time
0235                             year,month,day,_,_=event.end_date
0236                             entry.end=(year,month,day,hour,minute)
0237                     else:
0238                         entry.end=event.end
0239                 except ValueError:
0240                     continue
0241                 if event.alarmindex_vibrate&0x1:
0242                     entry.vibrate=0 # vibarate bit is inverted in phone 0=on, 1=off
0243                 else:
0244                     entry.vibrate=1
0245                 entry.repeat = self.makerepeat(event.repeat)
0246                 min=event.alarmminutes
0247                 hour=event.alarmhours
0248                 if min==0x64 or hour==0x64:
0249                     entry.alarm=None # no alarm set
0250                 else:
0251                     entry.alarm=hour*60+min
0252                 if self.protocolclass.CALENDAR_HAS_SEPARATE_END_TIME_AND_DATE:
0253                     # MIC Unlike previous phones, the VX8300 passes the ringtone
0254                     # via both the index, and a path.  If the index is set to 100
0255                     # (0x64), then the ringtone information will be found in the
0256                     # "ringpath", the last 256 bytes of the calendar packet.  If
0257                     # the index is between 0 and 15, inclusive, then it is using
0258                     # one of the builtin ringers, and the ringpath is set to
0259                     # null.
0260                     try:
0261                         if (event.ringtone == 100):   # MIC Ringer is downloaded to phone or microSD
0262                             entry.ringtone = common.basename(event.ringpath)
0263                         else:                         # MIC Ringer is built-in
0264                             entry.ringtone=self.builtinringtones[event.ringtone]
0265                     except:
0266                         # hack, not having a phone makes it hard to figure out the best approach
0267                         if entry.alarm==None:
0268                             entry.ringtone='No Ring'
0269                         else:
0270                             entry.ringtone='Loud Beeps'
0271                 else:
0272                     #hack for alltel
0273                     if entry.alarm==None:
0274                         entry.ringtone='No Ring'
0275                     else:
0276                         entry.ringtone='Loud Beeps'
0277 #                    entry.ringtone=result['ringtone-index'][event.ringtone]['name']  ## This doesn't work on alltel
0278                 entry.snoozedelay=0
0279                 # check for exceptions and remove them
0280                 if event.repeat[3] and exceptions.has_key(event.pos):
0281                     for year, month, day in exceptions[event.pos]:
0282                         entry.suppress_repeat_entry(year, month, day)
0283                 res[entry.id]=entry
0284 
0285             assert sc.numactiveitems==len(res)
0286         except com_brew.BrewNoSuchFileException:
0287             pass # do nothing if file doesn't exist
0288         result['calendar']=res
0289         return result
0290 
0291     def _build_pb_info(self, fundamentals):
0292         # build a dict of info to update pbentry
0293         pbook=fundamentals.get('phonebook', {})
0294         wallpaper_index=fundamentals.get('wallpaper-index', {})
0295         ringtone_index=fundamentals.get('ringtone-index', {})
0296         r1={}
0297         for k,e in pbook.items():
0298             r1[e['bitpimserial']['id']]={ 'wallpaper': \
0299                                           self._findmediainindex(wallpaper_index,
0300                                                                  e['wallpaper'],
0301                                                                  e['name'],
0302                                                                  'wallpaper'),
0303                                           'msgringtone': \
0304                                           self._findmediainindex(ringtone_index,
0305                                                                  e['msgringtone'],
0306                                                                  e['name'],
0307                                                                  'message ringtone')}
0308         serialupdates=fundamentals.get("serialupdates", [])
0309         r2={}
0310         for bps, serials in serialupdates:
0311             r2[serials['serial1']]=r1[bps['id']]
0312         return r2
0313 
0314     def _update_pb_file(self, pb, fundamentals, pbinfo):
0315         # update the pbentry file
0316         update_flg=False
0317         for e in pb.items:
0318             _info=pbinfo.get(e.serial1, None)
0319             if _info:
0320                 wp=_info.get('wallpaper', None)
0321                 if wp is not None and wp!=e.wallpaper:
0322                     update_flg=True
0323                     e.wallpaper=wp
0324                 rt=_info.get('ringtone', None)
0325                 if rt is not None and rt!=e.ringtone:
0326                     update_flg=True
0327                     e.ringtone=rt
0328         if update_flg:
0329             self.log('Updating wallpaper index')
0330             buf=prototypes.buffer()
0331             pb.writetobuffer(buf, logtitle="Updated index "+self.protocolclass.pb_file_name)
0332             self.writefile(self.protocolclass.pb_file_name, buf.getvalue())
0333 
0334 
0335     def _update_pb_info(self, pbentries, fundamentals):
0336         # Manually update phonebook data that the normal protocol should have
0337         _pbinfo=self._build_pb_info(fundamentals)
0338         self._update_pb_file(pbentries, fundamentals, _pbinfo)
0339 
0340     def _write_path_index(self, pbentries, pbmediakey, media_index,
0341                           index_file, invalid_values):
0342         _path_entry=self.protocolclass.PathIndexEntry()
0343         _path_file=self.protocolclass.PathIndexFile()
0344         for _ in range(self.protocolclass.NUMPHONEBOOKENTRIES):
0345             _path_file.items.append(_path_entry)
0346         for _entry in pbentries.items:
0347             _idx=getattr(_entry, pbmediakey)
0348             if _idx in invalid_values or not media_index.has_key(_idx):
0349                 continue
0350             if media_index[_idx].get('origin', None)=='builtin':
0351                 _filename=media_index[_idx]['name']
0352             elif media_index[_idx].get('filename', None):
0353                 _filename=media_index[_idx]['filename']
0354             else:
0355                 continue
0356             _path_file.items[_entry.entrynumber]=self.protocolclass.PathIndexEntry(
0357                 pathname=_filename)
0358         _buf=prototypes.buffer()
0359         _path_file.writetobuffer(_buf, logtitle='Writing Path ID')
0360         self.writefile(index_file, _buf.getvalue())
0361 
0362 # Must be included due to changed indexfile format
0363     def _write_index_file(self, type):
0364         _info=self.media_info.get(type, None)
0365 
0366         if not _info:
0367             return
0368         _files={}
0369         _local_dir=_info['localpath']
0370 
0371         _rs_dir=_info['rspath']
0372         _vtype=_info['vtype']
0373         _icon=_info['icon']
0374         _index=_info['index']
0375         _maxsize=_info['maxsize']
0376         _dunno=_info['dunno']
0377         _dunno1=_info['dunno1']
0378         indexfile=_info['indexfile']
0379         sizefile=_info['sizefile']
0380         _need_date=_info['date']
0381         try:
0382 
0383             _files=self.listfiles(_local_dir)
0384         except (com_brew.BrewNoSuchDirectoryException,
0385                 com_brew.BrewBadPathnameException):
0386             pass
0387         try:
0388             if _rs_dir:
0389                 _rs_files=self.listfiles(_rs_dir)
0390 
0391                 if type=='ringers':
0392                     self._mark_files(_files, _rs_files, _local_dir)
0393                 _files.update(_rs_files)
0394         except (com_brew.BrewNoSuchDirectoryException,
0395                 com_brew.BrewBadPathnameException):
0396             # dir does not exist, no media files available
0397             pass
0398         # del all the markers (empty files) ringers
0399         if type=='ringers':
0400             _keys=_files.keys()
0401             for _key in _keys:
0402                 if not _files[_key]['size']:
0403                     del _files[_key]
0404         # dict of all indices
0405         _idx_keys={}
0406         for _i in xrange(_index, _index+_maxsize):
0407             _idx_keys[_i]=True
0408         # assign existing indices
0409         for _item in self.getindex(indexfile):
0410             if _files.has_key(_item.filename):
0411 
0412                 _files[_item.filename]['index']=_item.index
0413                 _idx_keys[_item.index]=False
0414         # available new indices
0415         _idx_keys_list=[k for k,x in _idx_keys.items() if x]
0416         _idx_keys_list.sort()
0417         _idx_cnt=0
0418         # assign new indices
0419         _file_list=[x for x in _files if not _files[x].get('index', None)]
0420         _file_list.sort()
0421 
0422         if len(_file_list)>len(_idx_keys_list):
0423             _file_list=_file_list[:len(_idx_keys_list)]
0424         for i in _file_list:
0425             _files[i]['index']=_idx_keys_list[_idx_cnt]
0426             _idx_cnt+=1
0427         # (index, file name) list for writing
0428         _res_list=[(x['index'],k) for k,x in _files.items() if x.get('index', None)]
0429         _res_list.sort()
0430         _res_list.reverse()
0431 
0432         # writing the index file
0433         ifile=self.protocolclass.indexfile()
0434         _file_size=0
0435         for index,idx in _res_list:
0436             _fs_size=_files[idx]['size']
0437             ie=self.protocolclass.indexentry()
0438             ie.index=index
0439             ie.type=_vtype
0440             ie.filename=idx
0441             if _need_date:
0442                 # need to fill in the date value
0443                 _stat=self.statfile(_files[idx]['name'])
0444                 if _stat:
0445                     ie.date=_stat['datevalue']-time.timezone
0446             ie.dunno=_dunno
0447             ie.dunno1=_dunno1
0448             ie.icon=_icon
0449             ie.size=_fs_size
0450 
0451             ifile.items.append(ie)
0452             if not self._is_rs_file(idx):
0453                 _file_size+=_fs_size
0454         buf=prototypes.buffer()
0455 
0456         ifile.writetobuffer(buf, logtitle="Index file "+indexfile)
0457         self.log("Writing index file "+indexfile+" for type "+type+" with "+`len(_res_list)`+" entries.")
0458         self.writefile(indexfile, buf.getvalue())
0459         # writing the size file
0460         if sizefile:
0461             szfile=self.protocolclass.sizefile()
0462             szfile.size=_file_size
0463             buf=prototypes.buffer()
0464             szfile.writetobuffer(buf, logtitle="Updated size file for "+type)
0465             self.log("You are using a total of "+`_file_size`+" bytes for "+type)
0466             self.writefile(sizefile, buf.getvalue())
0467  
0468 # Must be there since there are no msg ringtones on ax8600
0469 
0470     def savephonebook(self, data):
0471         "Saves out the phonebook"
0472 
0473         res=com_lgvx4400.Phone.savephonebook(self, data)
0474         # retrieve the phonebook entries
0475 
0476         _buf=prototypes.buffer(self.getfilecontents(self.protocolclass.pb_file_name))
0477         _pb_entries=self.protocolclass.pbfile()
0478         _pb_entries.readfrombuffer(_buf, logtitle="Read phonebook file "+self.protocolclass.pb_file_name)
0479 
0480         # update info that the phone software failed to do!!
0481         self._update_pb_info(_pb_entries, data)
0482  
0483         return res
0484 
0485     # Misc Stuff----------------------------------------------------------------
0486     def get_firmware_version(self):
0487         # return the firmware version
0488         req=p_brew.firmwarerequest()
0489         res=self.sendbrewcommand(req, self.protocolclass.firmwareresponse)
0490         return res.firmware
0491 
0492     def _unlock_key(self):
0493         _req=self.protocolclass.LockKeyReq(lock=1)
0494         self.sendbrewcommand(_req, self.protocolclass.data)
0495     def _lock_key(self):
0496         _req=self.protocolclass.LockKeyReq()
0497         self.sendbrewcommand(_req, self.protocolclass.data)
0498 
0499     def _press_key(self, keys):
0500         # simulate a series of keypress
0501         if not keys:
0502             return
0503         _req=self.protocolclass.KeyPressReq()
0504         for _k in keys:
0505             _req.key=_k
0506             self.sendbrewcommand(_req, self.protocolclass.data)
0507 
0508 
0509 #-------------------------------------------------------------------------------
0510 parentprofile=com_lgvx8100.Profile
0511 class Profile(parentprofile):
0512     protocolclass=Phone.protocolclass
0513     serialsname=Phone.serialsname
0514 
0515     BP_Calendar_Version=3
0516     phone_manufacturer='LG Electronics Inc'
0517     phone_model='AX8600'
0518     # inside screen resoluation
0519     WALLPAPER_WIDTH=176
0520     WALLPAPER_HEIGHT=220
0521 
0522     MAX_WALLPAPER_BASENAME_LENGTH=32
0523     WALLPAPER_FILENAME_CHARS="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_() ."
0524     WALLPAPER_CONVERT_FORMAT="jpg"
0525 
0526     # the 8300 uses "W" for wait in the dialstring, it does not support "T"
0527     DIALSTRING_CHARS="[^0-9PW#*]"
0528 
0529     MAX_RINGTONE_BASENAME_LENGTH=32
0530     RINGTONE_FILENAME_CHARS="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_() ."
0531     RINGTONE_LIMITS= {
0532         'MAXSIZE': 200000
0533     }
0534 #    MSGRINGTONE=None
0535 
0536     imageorigins={}
0537     imageorigins.update(common.getkv(parentprofile.stockimageorigins, "images"))
0538 #    imageorigins.update(common.getkv(parentprofile.stockimageorigins, "video"))
0539 #    imageorigins.update(common.getkv(parentprofile.stockimageorigins, "images(sd)"))
0540 #    imageorigins.update(common.getkv(parentprofile.stockimageorigins, "video(sd)"))
0541 
0542     # our targets are the same for all origins
0543     imagetargets={}
0544 ##    imagetargets.update(common.getkv(parentprofile.stockimagetargets, "fullscreen",
0545 ##                                      {'width': 176, 'height': 220, 'format': "JPEG"}))
0546     imagetargets.update(common.getkv(parentprofile.stockimagetargets, "wallpaper",
0547                                       {'width': 176, 'height': 220, 'format': "JPEG"}))
0548 #    imagetargets.update(common.getkv(parentprofile.stockimagetargets, "outsidelcd",
0549 #                                      {'width': 128, 'height': 160, 'format': "JPEG"}))
0550 ##    imagetargets.update(common.getkv(parentprofile.stockimagetargets, "pictureid",
0551 ##                                      {'width': 128, 'height': 142, 'format': "JPEG"}))
0552 
0553 
0554     def GetImageOrigins(self):
0555         return self.imageorigins
0556 
0557     ringtoneorigins=('ringers', 'sounds')
0558     excluded_ringtone_origins=('ringers')
0559     excluded_wallpaper_origins=('video')
0560 
0561 
0562     def GetTargetsForImageOrigin(self, origin):
0563         return self.imagetargets
0564 
0565     def QueryAudio(self, origin, currentextension, afi):
0566         _max_size=self.RINGTONE_LIMITS['MAXSIZE']
0567         setattr(afi, 'MAXSIZE', _max_size)
0568         # we don't modify any of these
0569         if afi.format in ("MIDI", "QCP", "PMD", "WMA"):
0570             return currentextension, afi
0571         # examine mp3
0572         if afi.format=="MP3":
0573             if afi.channels==1 and 8<=afi.bitrate<=64 and 16000<=afi.samplerate<=22050:
0574                 return currentextension, afi
0575         # convert it
0576         return ("mp3", fileinfo.AudioFileInfo(afi, **{'format': 'MP3',
0577                                                       'channels': 2,
0578                                                       'bitrate': 48,
0579                                                       'samplerate': 44100,
0580                                                       'MAXSIZE': _max_size }))
0581 
0582     def __init__(self):
0583         parentprofile.__init__(self)
0584 
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 ##        ('t9_udb', 'read', 'OVERWRITE'),
0603 ##        ('t9_udb', '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, 'details': 5 },
0613             'email': 2,
0614             'address': {
0615                 'type': 0, 'company': 0, 'street': 0, 'street2': 0,
0616                 'city': 0, 'state': 0, 'postalcode': 0, 'country': 0,
0617                 'details': 0 },
0618             'url': 0,
0619             'memo': 0,
0620             'category': 1,
0621             'wallpaper': 1,
0622             'ringtone': 2,
0623             'storage': 0,
0624             },
0625         'calendar': {
0626             'description': True, 'location': False, 'allday': False,
0627             'start': True, 'end': True, 'priority': False,
0628             'alarm': True, 'vibrate': True,
0629             'repeat': True,
0630             'memo': False,
0631             'category': False,
0632             'wallpaper': False,
0633             'ringtone': True,
0634             },
0635         'memo': {
0636             'subject': True,
0637             'date': True,
0638             'secret': False,
0639             'category': False,
0640             'memo': True,
0641             },
0642         'todo': {
0643             'summary': False,
0644             'status': False,
0645             'due_date': False,
0646             'percent_complete': False,
0647             'completion_date': False,
0648             'private': False,
0649             'priority': False,
0650             'category': False,
0651             'memo': False,
0652             },
0653         }
0654 

Generated by PyXR 0.9.4