Package phones :: Module com_lgvx4650
[hide private]
[frames] | no frames]

Source Code for Module phones.com_lgvx4650

  1  ### BITPIM 
  2  ### 
  3  ### Copyright (C) 2005 Joe Pham <djpham@bitpim.org> 
  4  ### 
  5  ### This program is free software; you can redistribute it and/or modify 
  6  ### it under the terms of the BitPim license as detailed in the LICENSE file. 
  7  ### 
  8  ### $Id: com_lgvx4650.py 4370 2007-08-21 21:39:36Z djpham $ 
  9   
 10  """Communicate with the LG VX4650 cell phone 
 11   
 12  The VX4600 is substantially similar to the VX4400. 
 13   
 14  """ 
 15   
 16  # standard modules 
 17  from __future__ import with_statement 
 18  import contextlib 
 19  import datetime 
 20  import time 
 21  import cStringIO 
 22  import re 
 23  import sha 
 24   
 25  # my modules 
 26  import bpcalendar 
 27  import call_history 
 28  import common 
 29  import conversions 
 30  import copy 
 31  import p_brew 
 32  import p_lgvx4650 
 33  import com_lgvx4400 
 34  import com_brew 
 35  import com_phone 
 36  import com_lg 
 37  import commport 
 38  import helpids 
 39  import memo 
 40  import prototypes 
 41  import sms 
 42   
43 -class Phone(com_lgvx4400.Phone):
44 "Talk to the LG VX4650 cell phone" 45 46 desc="LG-VX4650" 47 helpid=helpids.ID_PHONE_LGVX4650 48 protocolclass=p_lgvx4650 49 serialsname='lgvx4650' 50 51 # 4650 index files 52 imagelocations=( 53 # offset, index file, files location, type, maximumentries 54 ( 30, "download/dloadindex/brewImageIndex.map", "dload/img", "images", 30), 55 ) 56 57 ringtonelocations=( 58 # offset, index file, files location, type, maximumentries 59 ( 50, "download/dloadindex/brewRingerIndex.map", "user/sound/ringer", "ringers", 30), 60 ) 61 62 builtinimages={ 80: ('Large Pic. 1', 'Large Pic. 2', 'Large Pic. 3', 63 'Large Pic. 4', 'Large Pic. 5', 'Large Pic. 6', 64 'Large Pic. 7', 'Large Pic. 8', 'Large Pic. 9', 65 'Large Pic. 10', 'Large Pic. 11', 'Large Pic. 12', 66 'Large Pic. 13', 'Large Pic. 14', 'Large Pic. 15', 67 'Large Pic. 16', 'Large Pic. 17', 'Large Pic. 18', 68 'Large Pic. 19', 'Large Pic. 20', 'Large Pic. 21', 69 'Large Pic. 22', 'Large Pic. 23', 'Large Pic. 24', 70 'Large Pic. 25', 'Large Pic. 26', 'Large Pic. 27', 71 'Large Pic. 28', 'Large Pic. 29', 'Large Pic. 30', 72 'Large Pic. 31', 'Large Pic. 32', 'Large Pic. 33' ) } 73 74 builtinringtones={ 1: ('Ring 1', 'Ring 2', 'Ring 3', 'Ring 4', 'Ring 5', 75 'VZW Default Tone', 'Arabesque', 'Piano Sonata', 76 'Latin', 'When the saints go', 'Bach Cello suite', 77 'Speedy Way', 'CanCan', 'Grand Waltz', 'Toccata and Fugue', 78 'Bumble Bee', 'March', 'Circus Band', 79 'Sky Garden', 'Carmen Habanera', 'Hallelujah', 80 'Sting', 'Farewell', 'Pachelbel Canon', 'Carol 1', 81 'Carol 2'), # 'Vibrate', 'Lamp' ), 82 100: ( 'Chimes high', 'Chimes low', 'Ding', 'TaDa', 83 'Notify', 'Drum', 'Claps', 'FanFare', 'Chord high', 84 'Chord low' ) 85 } 86 VoiceMemoDir='VoiceDB/All/Memos' 87
88 - def __init__(self, logtarget, commport):
89 com_lgvx4400.Phone.__init__(self, logtarget, commport) 90 self.mode=self.MODENONE
91
92 - def getfirmwareinformation(self):
93 self.log("Getting firmware information") 94 req=self.protocolclass.firmwarerequest() 95 res=self.sendbrewcommand(req, self.protocolclass.firmwareresponse) 96 return res
97
98 - def getmediaindex(self, builtins, maps, results, key):
99 """Gets the media (wallpaper/ringtone) index 100 101 @param builtins: the builtin list on the phone 102 @param results: places results in this dict 103 @param maps: the list of index files and locations 104 @param key: key to place results in 105 """ 106 media=com_lgvx4400.Phone.getmediaindex(self, (), maps, results, key) 107 108 # builtins 109 for k,e in builtins.items(): 110 c=k 111 for name in e: 112 media[c]={ 'name': name, 'origin': 'builtin' } 113 c+=1 114 # voice memos index 115 if key=='ringtone-index': 116 try: 117 vmemo_files=self.listfiles(self.VoiceMemoDir) 118 keys=vmemo_files.keys() 119 keys.sort() 120 _idx_cnt=210 121 for k in keys: 122 if k.endswith('.qcp'): 123 num_str=k[-8:-4] 124 media[_idx_cnt]={ 'name': 'VoiceMemo'+num_str, 125 'origin': 'voicememo' } 126 _idx_cnt+=1 127 except: 128 if __debug__: 129 raise 130 return media
131 132 # Ringtone stuff------------------------------------------------------------
133 - def getringtones(self, result):
134 result=com_lgvx4400.Phone.getringtones(self, result) 135 if not conversions.helperavailable('pvconv'): 136 return result 137 media=result['ringtone'] 138 # get& convert the voice memo files 139 with contextlib.nested(common.usetempfile('qcp'), 140 common.usetempfile('wav')) as (_qcp_file, _wav_file): 141 try: 142 vmemo_files=self.listfiles(self.VoiceMemoDir) 143 keys=vmemo_files.keys() 144 for k in keys: 145 if k.endswith('.qcp'): 146 key_name='VoiceMemo'+k[-8:-4] 147 file(_qcp_file, 'wb').write(self.getfilecontents(k, True)) 148 conversions.convertqcptowav(_qcp_file, _wav_file) 149 media[key_name]=file(_wav_file, 'rb').read() 150 except: 151 if __debug__: 152 raise 153 result['ringtone']=media 154 return result
155
156 - def saveringtones(self, results, merge):
157 _new_ringtones=results.get('ringtone', {}) 158 _rt_index=results.get('ringtone-index', {}) 159 # list of voicememo names 160 _voice_memo_l=[x['name'] for k,x in _rt_index.items() \ 161 if x.get('origin', '')=='voicememo'] 162 # list of media to delete 163 _del_keys=[k for k,x in _new_ringtones.items() \ 164 if x.get('name', None) in _voice_memo_l] 165 for k in _del_keys: 166 del _new_ringtones[k] 167 results['ringtone']=_new_ringtones 168 return com_lgvx4400.Phone.saveringtones(self, results, merge)
169 170 # Phonebook stuff-----------------------------------------------------------
171 - def savephonebook(self, data):
172 "Saves out the phonebook" 173 res=com_lgvx4400.Phone.savephonebook(self, data) 174 # build a dict to manually update the wp index 175 pbook=res.get('phonebook', {}) 176 wallpaper_index=res.get('wallpaper-index', {}) 177 r1={} 178 for k,e in pbook.items(): 179 r1[e['bitpimserial']['id']]={ 'wallpaper': \ 180 self._findmediainindex(wallpaper_index, 181 e['wallpaper'], 182 e['name'], 183 'wallpaper'), 184 'group': e['group'] } 185 serialupdates=data.get("serialupdates", []) 186 r2={} 187 for bps, serials in serialupdates: 188 r2[serials['serial1']]=r1[bps['id']] 189 if self._update_wallpaper_index(r2): 190 data["rebootphone"]=True 191 return res
192
193 - def _update_wallpaper_index(self, wpi):
194 # manually update wallpaper indices since the normal update process 195 # does not seem to work 196 buf=prototypes.buffer(self.getfilecontents( 197 self.protocolclass.pb_file_name)) 198 pb=self.protocolclass.pbfile() 199 pb.readfrombuffer(buf, logtitle="Read "+self.protocolclass.pb_file_name) 200 update_flg=False 201 for e in pb.items: 202 _info=wpi.get(e.serial1, None) 203 if _info: 204 wp=_info.get('wallpaper', None) 205 if wp is not None and wp!=e.wallpaper: 206 update_flg=True 207 e.wallpaper=wp 208 gr=_info.get('group', None) 209 if gr is not None and gr!=e.group: 210 update_flg=True 211 e.group=gr 212 if update_flg: 213 self.log('Updating wallpaper index') 214 buf=prototypes.buffer() 215 pb.writetobuffer(buf, logtitle="Updated index "+self.protocolclass.pb_file_name) 216 self.writefile(self.protocolclass.pb_file_name, buf.getvalue()) 217 return update_flg
218 219 # Calendar stuff------------------------------------------------------------ 220 # all taken care by the VX4400 221 222 # Text Memo stuff----------------------------------------------------------- 223 # all taken care by the VX4400 224 225 # Call History stuff-------------------------------------------------------- 226 _call_history_info={ 227 call_history.CallHistoryEntry.Folder_Incoming: protocolclass.incoming_call_file, 228 call_history.CallHistoryEntry.Folder_Outgoing: protocolclass.outgoing_call_file, 229 call_history.CallHistoryEntry.Folder_Missed: protocolclass.missed_call_file 230 }
231 - def getcallhistory(self, result):
232 # read the call history files 233 res={} 234 for _folder, _file_name in Phone._call_history_info.items(): 235 try: 236 buf=prototypes.buffer(self.getfilecontents(_file_name)) 237 hist_file=self.protocolclass.callhistoryfile() 238 hist_file.readfrombuffer(buf, logtitle="Read call history") 239 for i in range(hist_file.itemcount): 240 hist_call=hist_file.items[i] 241 entry=call_history.CallHistoryEntry() 242 entry.folder=_folder 243 entry.datetime=hist_call.datetime 244 entry.number=hist_call.number 245 entry.name=hist_call.name 246 if _folder!=call_history.CallHistoryEntry.Folder_Missed: 247 entry.duration=hist_call.duration 248 res[entry.id]=entry 249 except com_brew.BrewNoSuchFileException: 250 pass 251 result['call_history']=res 252 return result
253 254 # SMS stuff-----------------------------------------------------------------
255 - def _setquicktext(self, result):
256 canned_file=Phone.SMSCannedFile() 257 canned_file.set_sms_canned_data(result.get('canned_msg', [])) 258 buf=prototypes.buffer() 259 canned_file.writetobuffer(buf, logtitle="Updated "+self.protocolclass.sms_canned_file) 260 self.writefile(self.protocolclass.sms_canned_file, buf.getvalue())
261
262 - def _getquicktext(self):
263 try: 264 buf=prototypes.buffer(self.getfilecontents( 265 self.protocolclass.sms_canned_file)) 266 canned_file=Phone.SMSCannedFile() 267 canned_file.readfrombuffer(buf, logtitle="Read SMS canned text") 268 return canned_file.get_sms_canned_data() 269 except: 270 if __debug__: 271 raise 272 return []
273 274 my_model='VX4650' 275
276 - class SMSCannedFile(protocolclass.SMSCannedFile):
277 - def __init__(self, *args, **kwargs):
278 Phone.protocolclass.SMSCannedFile.__init__(self, *args, **kwargs)
279
280 - def get_sms_canned_data(self):
281 return [{ 'text': e.text, 282 'type': sms.CannedMsgEntry.user_type } for e in self.items]
283
284 - def set_sms_canned_data(self, canned_list):
285 msg_lst=[x['text'] for x in canned_list \ 286 if x['type']==sms.CannedMsgEntry.user_type] 287 item_count=min(Phone.protocolclass.SMS_CANNED_MAX_ITEMS, len(msg_lst)) 288 for i in range(item_count): 289 entry=Phone.protocolclass.SMSCannedMsg() 290 entry.text=msg_lst[i] 291 self.items.append(entry) 292 entry=Phone.protocolclass.SMSCannedMsg() 293 entry.text='' 294 for i in range(item_count, Phone.protocolclass.SMS_CANNED_MAX_ITEMS): 295 self.items.append(entry)
296 297 # Phone Info stuff----------------------------------------------------------
298 - def _get_phone_number(self):
299 # return the phone number of this phone 300 s='' 301 try: 302 buf=self.getfilecontents('nvm/nvm/nvm_0000') 303 ofs=0x240 304 if buf[ofs]=='\x01': 305 ofs+=1 306 while buf[ofs]!='\x01': 307 s+=buf[ofs] 308 ofs+=1 309 except: 310 if __debug__: 311 raise 312 return s
313 - def getphoneinfo(self, phone_info):
314 # returning some basic phone info 315 # double check if this's the right phone. 316 try: 317 if self.getfilecontents(self.brew_version_file)[:len(self.my_model)]==self.my_model: 318 phone_info.model=self.my_model 319 phone_info.manufacturer=Profile.phone_manufacturer 320 phone_info.phone_number=self._get_phone_number() 321 phone_info.firmware_version=self.getfirmwareinformation().firmwareversion 322 phone_info.esn=self.get_esn() 323 except: 324 if __debug__: 325 raise
326 327 #------------------------------------------------------------------------------ 328 parentprofile=com_lgvx4400.Profile
329 -class Profile(parentprofile):
330 protocolclass=Phone.protocolclass 331 serialsname=Phone.serialsname 332 333 WALLPAPER_WIDTH=128 334 WALLPAPER_HEIGHT=128 335 MAX_WALLPAPER_BASENAME_LENGTH=19 336 WALLPAPER_FILENAME_CHARS="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 ." 337 WALLPAPER_CONVERT_FORMAT="bmp" 338 339 MAX_RINGTONE_BASENAME_LENGTH=19 340 RINGTONE_FILENAME_CHARS="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 ." 341 342 BP_Calendar_Version=3 343 phone_manufacturer='LG Electronics Inc' 344 phone_model='VX4650' 345 346 imageorigins={} 347 imageorigins.update(common.getkv(parentprofile.stockimageorigins, "images"))
348 - def GetImageOrigins(self):
349 return self.imageorigins
350 351 # our targets are the same for all origins 352 imagetargets={} 353 imagetargets.update(common.getkv(parentprofile.stockimagetargets, "wallpaper", 354 {'width': 128, 'height': 114, 'format': "JPEG"})) 355 imagetargets.update(common.getkv(parentprofile.stockimagetargets, "fullscreen", 356 {'width': 128, 'height': 128, 'format': "JPEG"})) 357
358 - def GetTargetsForImageOrigin(self, origin):
359 return self.imagetargets
360 361 _supportedsyncs=( 362 ('phonebook', 'read', None), # all phonebook reading 363 ('calendar', 'read', None), # all calendar reading 364 ('wallpaper', 'read', None), # all wallpaper reading 365 ('ringtone', 'read', None), # all ringtone reading 366 ('phonebook', 'write', 'OVERWRITE'), # only overwriting phonebook 367 ('calendar', 'write', 'OVERWRITE'), # only overwriting calendar 368 ('wallpaper', 'write', 'MERGE'), # merge and overwrite wallpaper 369 ('wallpaper', 'write', 'OVERWRITE'), 370 ('ringtone', 'write', 'MERGE'), # merge and overwrite ringtone 371 ('ringtone', 'write', 'OVERWRITE'), 372 ('memo', 'read', None), # all memo list reading DJP 373 ('memo', 'write', 'OVERWRITE'), # all memo list writing DJP 374 ('call_history', 'read', None), 375 ('sms', 'read', None), 376 ('sms', 'write', 'OVERWRITE'), 377 ) 378
379 - def __init__(self):
380 parentprofile.__init__(self)
381