PyXR

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



0001 ### BITPIM
0002 ###
0003 ### Copyright (C) 2005 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_lgvx4650.py 4370 2007-08-21 21:39:36Z djpham $
0009 
0010 """Communicate with the LG VX4650 cell phone
0011 
0012 The VX4600 is substantially similar to the VX4400.
0013 
0014 """
0015 
0016 # standard modules
0017 from __future__ import with_statement
0018 import contextlib
0019 import datetime
0020 import time
0021 import cStringIO
0022 import re
0023 import sha
0024 
0025 # my modules
0026 import bpcalendar
0027 import call_history
0028 import common
0029 import conversions
0030 import copy
0031 import p_brew
0032 import p_lgvx4650
0033 import com_lgvx4400
0034 import com_brew
0035 import com_phone
0036 import com_lg
0037 import commport
0038 import helpids
0039 import memo
0040 import prototypes
0041 import sms
0042 
0043 class Phone(com_lgvx4400.Phone):
0044     "Talk to the LG VX4650 cell phone"
0045 
0046     desc="LG-VX4650"
0047     helpid=helpids.ID_PHONE_LGVX4650
0048     protocolclass=p_lgvx4650
0049     serialsname='lgvx4650'
0050 
0051     # 4650 index files
0052     imagelocations=(
0053         # offset, index file, files location, type, maximumentries
0054         ( 30, "download/dloadindex/brewImageIndex.map", "dload/img", "images", 30),
0055         )
0056 
0057     ringtonelocations=(
0058         # offset, index file, files location, type, maximumentries
0059         ( 50, "download/dloadindex/brewRingerIndex.map", "user/sound/ringer", "ringers", 30),
0060         )
0061 
0062     builtinimages={ 80: ('Large Pic. 1', 'Large Pic. 2', 'Large Pic. 3',
0063                          'Large Pic. 4', 'Large Pic. 5', 'Large Pic. 6',
0064                          'Large Pic. 7', 'Large Pic. 8', 'Large Pic. 9', 
0065                          'Large Pic. 10', 'Large Pic. 11', 'Large Pic. 12',
0066                          'Large Pic. 13', 'Large Pic. 14', 'Large Pic. 15', 
0067                          'Large Pic. 16', 'Large Pic. 17', 'Large Pic. 18',
0068                          'Large Pic. 19', 'Large Pic. 20', 'Large Pic. 21', 
0069                          'Large Pic. 22', 'Large Pic. 23', 'Large Pic. 24',
0070                          'Large Pic. 25', 'Large Pic. 26', 'Large Pic. 27', 
0071                          'Large Pic. 28', 'Large Pic. 29', 'Large Pic. 30',
0072                          'Large Pic. 31', 'Large Pic. 32', 'Large Pic. 33' ) }
0073 
0074     builtinringtones={ 1: ('Ring 1', 'Ring 2', 'Ring 3', 'Ring 4', 'Ring 5',
0075                            'VZW Default Tone', 'Arabesque', 'Piano Sonata',
0076                            'Latin', 'When the saints go', 'Bach Cello suite',
0077                            'Speedy Way', 'CanCan', 'Grand Waltz', 'Toccata and Fugue',
0078                            'Bumble Bee', 'March', 'Circus Band',
0079                            'Sky Garden', 'Carmen Habanera', 'Hallelujah',
0080                            'Sting', 'Farewell', 'Pachelbel Canon', 'Carol 1',
0081                            'Carol 2'), # 'Vibrate', 'Lamp' ),
0082                        100: ( 'Chimes high', 'Chimes low', 'Ding', 'TaDa',
0083                               'Notify', 'Drum', 'Claps', 'FanFare', 'Chord high',
0084                               'Chord low' )
0085                        }
0086     VoiceMemoDir='VoiceDB/All/Memos'
0087 
0088     def __init__(self, logtarget, commport):
0089         com_lgvx4400.Phone.__init__(self, logtarget, commport)
0090         self.mode=self.MODENONE
0091 
0092     def getfirmwareinformation(self):
0093         self.log("Getting firmware information")
0094         req=self.protocolclass.firmwarerequest()
0095         res=self.sendbrewcommand(req, self.protocolclass.firmwareresponse)
0096         return res
0097 
0098     def getmediaindex(self, builtins, maps, results, key):
0099         """Gets the media (wallpaper/ringtone) index
0100 
0101         @param builtins: the builtin list on the phone
0102         @param results: places results in this dict
0103         @param maps: the list of index files and locations
0104         @param key: key to place results in
0105         """
0106         media=com_lgvx4400.Phone.getmediaindex(self, (), maps, results, key)
0107 
0108         # builtins
0109         for k,e in builtins.items():
0110             c=k
0111             for name in e:
0112                 media[c]={ 'name': name, 'origin': 'builtin' }
0113                 c+=1
0114         # voice memos index
0115         if key=='ringtone-index':
0116             try:
0117                 vmemo_files=self.listfiles(self.VoiceMemoDir)
0118                 keys=vmemo_files.keys()
0119                 keys.sort()
0120                 _idx_cnt=210
0121                 for k in keys:
0122                     if k.endswith('.qcp'):
0123                         num_str=k[-8:-4]
0124                         media[_idx_cnt]={ 'name': 'VoiceMemo'+num_str,
0125                                                   'origin': 'voicememo' }
0126                         _idx_cnt+=1
0127             except:
0128                 if __debug__:
0129                     raise
0130         return media
0131 
0132     # Ringtone stuff------------------------------------------------------------
0133     def getringtones(self, result):
0134         result=com_lgvx4400.Phone.getringtones(self, result)
0135         if not conversions.helperavailable('pvconv'):
0136             return result
0137         media=result['ringtone']
0138         # get& convert the voice memo files
0139         with contextlib.nested(common.usetempfile('qcp'),
0140                                common.usetempfile('wav')) as (_qcp_file, _wav_file):
0141             try:
0142                 vmemo_files=self.listfiles(self.VoiceMemoDir)
0143                 keys=vmemo_files.keys()
0144                 for k in keys:
0145                     if k.endswith('.qcp'):
0146                         key_name='VoiceMemo'+k[-8:-4]
0147                         file(_qcp_file, 'wb').write(self.getfilecontents(k, True))
0148                         conversions.convertqcptowav(_qcp_file, _wav_file)
0149                         media[key_name]=file(_wav_file, 'rb').read()
0150             except:
0151                 if __debug__:
0152                     raise
0153         result['ringtone']=media
0154         return result
0155 
0156     def saveringtones(self, results, merge):
0157         _new_ringtones=results.get('ringtone', {})
0158         _rt_index=results.get('ringtone-index', {})
0159         # list of voicememo names
0160         _voice_memo_l=[x['name'] for k,x in _rt_index.items() \
0161                        if x.get('origin', '')=='voicememo']
0162         # list of media to delete
0163         _del_keys=[k for k,x in _new_ringtones.items() \
0164                    if x.get('name', None) in _voice_memo_l]
0165         for k in _del_keys:
0166             del _new_ringtones[k]
0167         results['ringtone']=_new_ringtones
0168         return com_lgvx4400.Phone.saveringtones(self, results, merge)
0169 
0170     # Phonebook stuff-----------------------------------------------------------
0171     def savephonebook(self, data):
0172         "Saves out the phonebook"
0173         res=com_lgvx4400.Phone.savephonebook(self, data)
0174         # build a dict to manually update the wp index
0175         pbook=res.get('phonebook', {})
0176         wallpaper_index=res.get('wallpaper-index', {})
0177         r1={}
0178         for k,e in pbook.items():
0179             r1[e['bitpimserial']['id']]={ 'wallpaper': \
0180                                           self._findmediainindex(wallpaper_index,
0181                                                                  e['wallpaper'],
0182                                                                  e['name'],
0183                                                                  'wallpaper'),
0184                                           'group': e['group'] }
0185         serialupdates=data.get("serialupdates", [])
0186         r2={}
0187         for bps, serials in serialupdates:
0188             r2[serials['serial1']]=r1[bps['id']]
0189         if self._update_wallpaper_index(r2):
0190             data["rebootphone"]=True
0191         return res
0192 
0193     def _update_wallpaper_index(self, wpi):
0194         # manually update wallpaper indices since the normal update process
0195         # does not seem to work
0196         buf=prototypes.buffer(self.getfilecontents(
0197             self.protocolclass.pb_file_name))
0198         pb=self.protocolclass.pbfile()
0199         pb.readfrombuffer(buf, logtitle="Read "+self.protocolclass.pb_file_name)
0200         update_flg=False
0201         for e in pb.items:
0202             _info=wpi.get(e.serial1, None)
0203             if _info:
0204                 wp=_info.get('wallpaper', None)
0205                 if wp is not None and wp!=e.wallpaper:
0206                     update_flg=True
0207                     e.wallpaper=wp
0208                 gr=_info.get('group', None)
0209                 if gr is not None and gr!=e.group:
0210                     update_flg=True
0211                     e.group=gr
0212         if update_flg:
0213             self.log('Updating wallpaper index')
0214             buf=prototypes.buffer()
0215             pb.writetobuffer(buf, logtitle="Updated index "+self.protocolclass.pb_file_name)
0216             self.writefile(self.protocolclass.pb_file_name, buf.getvalue())
0217         return update_flg
0218 
0219     # Calendar stuff------------------------------------------------------------
0220     # all taken care by the VX4400
0221 
0222     # Text Memo stuff-----------------------------------------------------------
0223     # all taken care by the VX4400
0224 
0225     # Call History stuff--------------------------------------------------------
0226     _call_history_info={
0227         call_history.CallHistoryEntry.Folder_Incoming: protocolclass.incoming_call_file,
0228         call_history.CallHistoryEntry.Folder_Outgoing: protocolclass.outgoing_call_file,
0229         call_history.CallHistoryEntry.Folder_Missed: protocolclass.missed_call_file
0230         }
0231     def getcallhistory(self, result):
0232         # read the call history files
0233         res={}
0234         for _folder, _file_name in Phone._call_history_info.items():
0235             try:
0236                 buf=prototypes.buffer(self.getfilecontents(_file_name))
0237                 hist_file=self.protocolclass.callhistoryfile()
0238                 hist_file.readfrombuffer(buf, logtitle="Read call history")
0239                 for i in range(hist_file.itemcount):
0240                     hist_call=hist_file.items[i]
0241                     entry=call_history.CallHistoryEntry()
0242                     entry.folder=_folder
0243                     entry.datetime=hist_call.datetime
0244                     entry.number=hist_call.number
0245                     entry.name=hist_call.name
0246                     if _folder!=call_history.CallHistoryEntry.Folder_Missed:
0247                         entry.duration=hist_call.duration
0248                     res[entry.id]=entry
0249             except com_brew.BrewNoSuchFileException:
0250                 pass
0251         result['call_history']=res
0252         return result
0253 
0254     # SMS stuff-----------------------------------------------------------------
0255     def _setquicktext(self, result):
0256         canned_file=Phone.SMSCannedFile()
0257         canned_file.set_sms_canned_data(result.get('canned_msg', []))
0258         buf=prototypes.buffer()
0259         canned_file.writetobuffer(buf, logtitle="Updated "+self.protocolclass.sms_canned_file)
0260         self.writefile(self.protocolclass.sms_canned_file, buf.getvalue())
0261 
0262     def _getquicktext(self):
0263         try:
0264             buf=prototypes.buffer(self.getfilecontents(
0265                 self.protocolclass.sms_canned_file))
0266             canned_file=Phone.SMSCannedFile()
0267             canned_file.readfrombuffer(buf, logtitle="Read SMS canned text")
0268             return canned_file.get_sms_canned_data()
0269         except:
0270             if __debug__:
0271                 raise
0272             return []
0273 
0274     my_model='VX4650'
0275 
0276     class SMSCannedFile(protocolclass.SMSCannedFile):
0277         def __init__(self, *args, **kwargs):
0278             Phone.protocolclass.SMSCannedFile.__init__(self, *args, **kwargs)
0279 
0280         def get_sms_canned_data(self):
0281             return [{ 'text': e.text,
0282                       'type': sms.CannedMsgEntry.user_type } for e in self.items]
0283 
0284         def set_sms_canned_data(self, canned_list):
0285             msg_lst=[x['text'] for x in canned_list \
0286                      if x['type']==sms.CannedMsgEntry.user_type]
0287             item_count=min(Phone.protocolclass.SMS_CANNED_MAX_ITEMS, len(msg_lst))
0288             for i in range(item_count):
0289                 entry=Phone.protocolclass.SMSCannedMsg()
0290                 entry.text=msg_lst[i]
0291                 self.items.append(entry)
0292             entry=Phone.protocolclass.SMSCannedMsg()
0293             entry.text=''
0294             for i in range(item_count, Phone.protocolclass.SMS_CANNED_MAX_ITEMS):
0295                 self.items.append(entry)
0296 
0297     # Phone Info stuff----------------------------------------------------------
0298     def _get_phone_number(self):
0299         # return the phone number of this phone
0300         s=''
0301         try:
0302             buf=self.getfilecontents('nvm/nvm/nvm_0000')
0303             ofs=0x240
0304             if buf[ofs]=='\x01':
0305                 ofs+=1
0306                 while buf[ofs]!='\x01':
0307                     s+=buf[ofs]
0308                     ofs+=1
0309         except:
0310             if __debug__:
0311                 raise
0312         return s
0313     def getphoneinfo(self, phone_info):
0314         # returning some basic phone info
0315         # double check if this's the right phone.
0316         try:
0317             if self.getfilecontents(self.brew_version_file)[:len(self.my_model)]==self.my_model:
0318                 phone_info.model=self.my_model
0319                 phone_info.manufacturer=Profile.phone_manufacturer
0320                 phone_info.phone_number=self._get_phone_number()
0321                 phone_info.firmware_version=self.getfirmwareinformation().firmwareversion
0322                 phone_info.esn=self.get_esn()
0323         except:
0324             if __debug__:
0325                 raise
0326 
0327 #------------------------------------------------------------------------------
0328 parentprofile=com_lgvx4400.Profile
0329 class Profile(parentprofile):
0330     protocolclass=Phone.protocolclass
0331     serialsname=Phone.serialsname
0332 
0333     WALLPAPER_WIDTH=128
0334     WALLPAPER_HEIGHT=128
0335     MAX_WALLPAPER_BASENAME_LENGTH=19
0336     WALLPAPER_FILENAME_CHARS="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 ."
0337     WALLPAPER_CONVERT_FORMAT="bmp"
0338 
0339     MAX_RINGTONE_BASENAME_LENGTH=19
0340     RINGTONE_FILENAME_CHARS="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 ."
0341 
0342     BP_Calendar_Version=3
0343     phone_manufacturer='LG Electronics Inc'
0344     phone_model='VX4650'
0345 
0346     imageorigins={}
0347     imageorigins.update(common.getkv(parentprofile.stockimageorigins, "images"))
0348     def GetImageOrigins(self):
0349         return self.imageorigins
0350 
0351     # our targets are the same for all origins
0352     imagetargets={}
0353     imagetargets.update(common.getkv(parentprofile.stockimagetargets, "wallpaper",
0354                                       {'width': 128, 'height': 114, 'format': "JPEG"}))
0355     imagetargets.update(common.getkv(parentprofile.stockimagetargets, "fullscreen",
0356                                       {'width': 128, 'height': 128, 'format': "JPEG"}))
0357 
0358     def GetTargetsForImageOrigin(self, origin):
0359         return self.imagetargets
0360 
0361     _supportedsyncs=(
0362         ('phonebook', 'read', None),  # all phonebook reading
0363         ('calendar', 'read', None),   # all calendar reading
0364         ('wallpaper', 'read', None),  # all wallpaper reading
0365         ('ringtone', 'read', None),   # all ringtone reading
0366         ('phonebook', 'write', 'OVERWRITE'),  # only overwriting phonebook
0367         ('calendar', 'write', 'OVERWRITE'),   # only overwriting calendar
0368         ('wallpaper', 'write', 'MERGE'),      # merge and overwrite wallpaper
0369         ('wallpaper', 'write', 'OVERWRITE'),
0370         ('ringtone', 'write', 'MERGE'),      # merge and overwrite ringtone
0371         ('ringtone', 'write', 'OVERWRITE'),
0372         ('memo', 'read', None),     # all memo list reading DJP
0373         ('memo', 'write', 'OVERWRITE'),  # all memo list writing DJP
0374         ('call_history', 'read', None),
0375         ('sms', 'read', None),
0376         ('sms', 'write', 'OVERWRITE'),
0377        )
0378 
0379     def __init__(self):
0380         parentprofile.__init__(self)
0381 

Generated by PyXR 0.9.4