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

Source Code for Module phones.com_lglg8100

  1  ### BITPIM 
  2  ### 
  3  ### Copyright (C) 2003-2005 Roger Binns <rogerb@rogerbinns.com> 
  4  ### Copyright (C) 2006 Simon Capper <skyjunky@sbcglobal.net> 
  5  ### 
  6  ### This program is free software; you can redistribute it and/or modify 
  7  ### it under the terms of the BitPim license as detailed in the LICENSE file. 
  8  ### 
  9  ### $Id: com_lglg8100.py 4303 2007-07-13 20:46:53Z djpham $ 
 10   
 11  """Communicate with the LG VX5200 cell phone 
 12   
 13   
 14  The code in this file mainly inherits from VX8100 code and then extends where 
 15  the 5200 has different functionality 
 16   
 17  """ 
 18   
 19  # standard modules 
 20  import time 
 21  import calendar 
 22  import cStringIO 
 23  import sha 
 24   
 25  # my modules 
 26  import common 
 27  import commport 
 28  import copy 
 29  import com_lgvx4400 
 30  import p_brew 
 31  import p_lglg8100 
 32  import com_lgvx8100 
 33  import com_brew 
 34  import com_phone 
 35  import com_lg 
 36  import prototypes 
 37  import bpcalendar 
 38  import call_history 
 39  import sms 
 40  import memo 
 41   
42 -class Phone(com_lgvx8100.Phone):
43 "Talk to the LG LG8100 cell phone (Telus)" 44 45 desc="LG-LG8100" 46 helpid=None 47 protocolclass=p_lglg8100 48 serialsname='lglg8100' 49 50 builtinringtones= ('Low Beep Once', 'Low Beeps', 'Loud Beep Once', 'Loud Beeps') + \ 51 tuple(['Ringtone '+`n` for n in range(1,11)]) + \ 52 ('No Ring',) 53 54 ringtonelocations= ( 55 # type index-file size-file directory-to-use lowest-index-to-use maximum-entries type-major icon 56 ( 'ringers', 'dload/aod.dat', 'dload/aodsize.dat', 'brew/16452/mds', 1000, 150, 6, 1, 0), 57 # the sound index file uses the same index as the ringers, bitpim does not support this (yet) 58 # ( 'sounds', 'dload/mysound.dat', 'dload/mysoundsize.dat', 'brew/16452/ms', 100, 150, 2, 0, 151), 59 ) 60 61 calendarlocation="sch/newschedule.dat" 62 calendarexceptionlocation="sch/newschexception.dat" 63 calenderrequiresreboot=1 64 memolocation="sch/neomemo.dat" 65 66 builtinwallpapers = () # none 67 68 wallpaperlocations= ( 69 ( 'images', 'dload/image.dat', 'dload/imagesize.dat', 'brew/16452/mp', 100, 50, 0x300, 0, 0), 70 #( 'video', 'dload/video.dat', None, 'brew/16452/mf', 1000, 50, 0x0304, 0, 0), 71 ) 72 73 # for removable media (miniSD cards) 74 _rs_path='mmc1/' 75 _rs_ringers_path=_rs_path+'ringers' 76 _rs_images_path=_rs_path+'images' 77 media_info={ 'ringers': { 78 'localpath': 'brew/16452/mds', 79 'rspath': _rs_ringers_path, 80 'vtype': protocolclass.MEDIA_TYPE_RINGTONE, 81 'icon': protocolclass.MEDIA_RINGTONE_DEFAULT_ICON, 82 'index': 1000, # starting index 83 'maxsize': 155, 84 'indexfile': 'dload/aod.dat', 85 'sizefile': 'dload/aodsize.dat', 86 'dunno': 0, 'date': True, 87 }, 88 # 'sounds': { 89 # 'localpath': 'brew/16452/ms', 90 # 'rspath': None, 91 # 'vtype': protocolclass.MEDIA_TYPE_SOUND, 92 # 'icon': protocolclass.MEDIA_IMAGE_DEFAULT_ICON, 93 # 'index': 100, 94 # 'maxsize': 155, 95 # 'indexfile': 'dload/mysound.dat', 96 # 'sizefile': 'dload/mysoundsize.dat', 97 # 'dunno': 0, 'date': False }, 98 'images': { 99 'localpath': 'brew/16452/mp', 100 'rspath': _rs_images_path, 101 'vtype': protocolclass.MEDIA_TYPE_IMAGE, 102 'icon': protocolclass.MEDIA_IMAGE_DEFAULT_ICON, 103 'index': 100, 104 'maxsize': 155, 105 'indexfile': 'dload/image.dat', 106 'sizefile': 'dload/imagesize.dat', 107 'dunno': 0, 'date': True }, 108 # 'video': { 109 # 'localpath': 'brew/16452/mf', 110 # 'rspath': None, 111 # 'vtype': protocolclass.MEDIA_TYPE_VIDEO, 112 # 'icon': protocolclass.MEDIA_VIDEO_DEFAULT_ICON, 113 # 'index': 1000, 114 # 'maxsize': 155, 115 # 'indexfile': 'dload/video.dat', 116 # 'sizefile': 'dload/videosize.dat', 117 # 'dunno': 0, 'date': True }, 118 } 119
120 - def __init__(self, logtarget, commport):
121 com_lgvx4400.Phone.__init__(self,logtarget,commport) 122 self.mode=self.MODENONE
123
124 - def __del__(self):
125 pass
126
127 - def getcalendar(self,result):
128 res={} 129 # Read exceptions file first 130 try: 131 buf=prototypes.buffer(self.getfilecontents(self.calendarexceptionlocation)) 132 ex=self.protocolclass.scheduleexceptionfile() 133 ex.readfrombuffer(buf, logtitle="Calendar exceptions") 134 exceptions={} 135 for i in ex.items: 136 try: 137 exceptions[i.pos].append( (i.year,i.month,i.day) ) 138 except KeyError: 139 exceptions[i.pos]=[ (i.year,i.month,i.day) ] 140 except com_brew.BrewNoSuchFileException: 141 exceptions={} 142 143 # Now read schedule 144 try: 145 buf=prototypes.buffer(self.getfilecontents(self.calendarlocation)) 146 if len(buf.getdata())<3: 147 # file is empty, and hence same as non-existent 148 raise com_brew.BrewNoSuchFileException() 149 sc=self.protocolclass.schedulefile() 150 sc.readfrombuffer(buf, logtitle="Calendar") 151 for event in sc.events: 152 # the vx8100 has a bad entry when the calender is empty 153 # stop processing the calender when we hit this record 154 if event.pos==0: #invalid entry 155 continue 156 entry=bpcalendar.CalendarEntry() 157 entry.desc_loc=event.description 158 try: # delete events are still in the calender file but have garbage dates 159 entry.start=event.start 160 entry.end=event.end 161 except ValueError: 162 continue 163 if event.alarmindex_vibrate&0x1: 164 entry.vibrate=0 # vibarate bit is inverted in phone 0=on, 1=off 165 else: 166 entry.vibrate=1 167 entry.repeat = self.makerepeat(event.repeat, event.start) 168 min=event.alarmminutes 169 hour=event.alarmhours 170 if min==0x64 or hour==0x64: 171 entry.alarm=None # no alarm set 172 else: 173 entry.alarm=hour*60+min 174 entry.ringtone=result['ringtone-index'][event.ringtone]['name'] 175 entry.snoozedelay=0 176 # check for exceptions and remove them 177 if event.repeat[3] and exceptions.has_key(event.pos): 178 for year, month, day in exceptions[event.pos]: 179 entry.suppress_repeat_entry(year, month, day) 180 res[entry.id]=entry 181 182 assert sc.numactiveitems==len(res) 183 except com_brew.BrewNoSuchFileException: 184 pass # do nothing if file doesn't exist 185 result['calendar']=res 186 return result
187
188 - def makerepeat(self, repeat, start):
189 # get all the variables out of the repeat tuple 190 # and convert into a bpcalender RepeatEntry 191 type,dow,interval,interval2,exceptions=repeat 192 #print "repeat "+`repeat`+" start "+`start` 193 if type==0: 194 repeat_entry=None 195 else: 196 repeat_entry=bpcalendar.RepeatEntry() 197 if type==1: #daily 198 repeat_entry.repeat_type=repeat_entry.daily 199 repeat_entry.interval=interval 200 elif type==2: #'monfri' 201 repeat_entry.repeat_type=repeat_entry.daily 202 repeat_entry.interval=0 203 elif type==3: #'weekly' 204 repeat_entry.repeat_type=repeat_entry.weekly 205 repeat_entry.interval=interval 206 elif type==5: #'monthly' 207 repeat_entry.repeat_type=repeat_entry.monthly 208 repeat_entry.interval2=interval2 209 repeat_entry.dow=0 210 elif type==4: #'monthly' #Xth Y day (e.g. 2nd friday each month) 211 repeat_entry.repeat_type=repeat_entry.monthly 212 repeat_entry.interval=interval #X 213 repeat_entry.dow=dow #Y 214 repeat_entry.interval2=interval2 215 elif type==6: #'yearly #Xth Y day of Month (2nd sunday of april)' Not supported by bitpim 216 #repeat_entry.repeat_type=repeat_entry.yearly 217 repeat_entry=None 218 else: # =7 'yearly' 219 repeat_entry.repeat_type=repeat_entry.yearly 220 return repeat_entry
221
222 - def setalarm(self, entry, data):
223 # vx8100 only allows certain repeat intervals, adjust to fit, it also stores an index to the interval 224 rc=True 225 if entry.alarm>=10080: 226 entry.alarm=10080 227 data.alarmminutes=0 228 data.alarmhours=168 # 1 week 229 data.alarmindex_vibrate=0xe 230 elif entry.alarm>=4320: 231 entry.alarm=4320 232 data.alarmminutes=0 233 data.alarmhours=72 # 3 days 234 data.alarmindex_vibrate=0xc 235 elif entry.alarm>=1440: 236 entry.alarm=1440 237 data.alarmminutes=0 238 data.alarmhours=24 # 1 day 239 data.alarmindex_vibrate=0xa 240 elif entry.alarm>=60: 241 entry.alarm=60 242 data.alarmminutes=0 243 data.alarmhours=1 # 1 hour 244 data.alarmindex_vibrate=0x8 245 elif entry.alarm>=30: 246 entry.alarm=30 247 data.alarmminutes=30 248 data.alarmhours=0 # 30 mins 249 data.alarmindex_vibrate=0x6 250 elif entry.alarm>=15: 251 entry.alarm=15 252 data.alarmminutes=15 253 data.alarmhours=0 254 data.alarmindex_vibrate=0x4 255 elif entry.alarm>=0: 256 entry.alarm=0 257 data.alarmminutes=0 258 data.alarmhours=0 259 data.alarmindex_vibrate=0x2 260 else: # no alarm 261 data.alarmminutes=0x64 262 data.alarmhours=0x64 263 data.alarmindex_vibrate=1 264 rc=False 265 # set the vibrate bit 266 if data.alarmindex_vibrate > 1 and entry.vibrate==0: 267 data.alarmindex_vibrate+=1 268 return rc
269 270
271 - def savecalendar(self, dict, merge):
272 # ::TODO:: 273 # what will be written to the files 274 eventsf=self.protocolclass.schedulefile() 275 exceptionsf=self.protocolclass.scheduleexceptionfile() 276 # what are we working with 277 cal=dict['calendar'] 278 newcal={} 279 #sort into start order, makes it possible to see if the calendar has changed 280 keys=[(x.start, k) for k,x in cal.items()] 281 keys.sort() 282 # number of entries 283 eventsf.numactiveitems=len(keys) 284 pos=0 285 contains_alarms=False 286 # play with each entry 287 for (_,k) in keys: 288 # entry is what we will return to user 289 entry=cal[k] 290 data=self.protocolclass.scheduleevent() 291 data.index=pos 292 pos+=1 293 data.pos=eventsf.packetsize() 294 data.description=entry.desc_loc 295 data.start=entry.start 296 data.end=entry.end 297 alarm_set=self.setalarm(entry, data) 298 data.ringtone=0 299 if alarm_set: 300 if entry.ringtone=="No Ring" and not entry.vibrate: 301 alarm_name="Low Beep Once" 302 else: 303 alarm_name=entry.ringtone 304 else:# set alarm to "No Ring" gets rid of alarm icon on phone 305 alarm_name="No Ring" 306 for i in dict['ringtone-index']: 307 if dict['ringtone-index'][i]['name']==alarm_name: 308 data.ringtone=i 309 # check for exceptions and add them to the exceptions list 310 exceptions=0 311 if entry.repeat!=None: 312 if data.end[:3]==entry.no_end_date: 313 data.end=(2100, 12, 31)+data.end[3:] 314 for i in entry.repeat.suppressed: 315 de=self.protocolclass.scheduleexception() 316 de.pos=data.pos 317 de.day=i.date.day 318 de.month=i.date.month 319 de.year=i.date.year 320 exceptions=1 321 exceptionsf.items.append(de) 322 if entry.repeat != None: 323 data.repeat=(self.getrepeattype(entry, exceptions)) 324 else: 325 data.repeat=((0,0,0,0,0)) 326 if data.alarmindex_vibrate!=1: # if alarm set 327 contains_alarms=True 328 # put entry in nice shiny new dict we are building 329 entry=copy.copy(entry) 330 newcal[data.pos]=entry 331 eventsf.events.append(data) 332 333 buf=prototypes.buffer() 334 eventsf.writetobuffer(buf, logtitle="New Calendar") 335 # We check the existing calender as changes require a reboot for the alarms 336 # to work properly, also no point writing the file if it is not changing 337 if buf.getvalue()!=self.getfilecontents(self.calendarlocation): 338 self.writefile(self.calendarlocation, buf.getvalue()) 339 if contains_alarms or self.calenderrequiresreboot: 340 self.log("Your phone has to be rebooted due to the calendar changing") 341 dict["rebootphone"]=True 342 else: 343 self.log("Phone calendar unchanged, no update required") 344 345 buf=prototypes.buffer() 346 exceptionsf.writetobuffer(buf, logtitle="Writing calendar exceptions") 347 self.writefile(self.calendarexceptionlocation, buf.getvalue()) 348 349 # fix passed in dict 350 dict['calendar']=newcal 351 352 return dict
353
354 - def getrepeattype(self, entry, exceptions):
355 #convert the bpcalender type into vx8100 type 356 repeat_entry=bpcalendar.RepeatEntry() 357 interval2=0 358 if entry.repeat.repeat_type==repeat_entry.monthly: 359 dow=entry.repeat.dow 360 interval2=entry.repeat.interval2 361 if entry.repeat.dow==0: 362 # set interval for month type 4 to start day of month, (required by vx8100) 363 interval=entry.start[2] 364 type=5 365 else: 366 interval=entry.repeat.interval 367 type=4 368 elif entry.repeat.repeat_type==repeat_entry.daily: 369 dow=entry.repeat.dow 370 interval=entry.repeat.interval 371 if entry.repeat.interval==0: 372 type=2 373 else: 374 type=1 375 elif entry.repeat.repeat_type==repeat_entry.weekly: 376 dow=entry.repeat.dow 377 interval=entry.repeat.interval 378 type=3 379 elif entry.repeat.repeat_type==repeat_entry.yearly: 380 # set interval to start day of month, (required by vx8100) 381 interval=entry.start[2] 382 # set dow to start month, (required by vx8100) 383 dow=entry.start[1] 384 type=7 385 return (type, dow, interval, interval2, exceptions)
386
387 - def eval_detect_data(self, res):
388 found=False 389 if res.get(self.brew_version_txt_key, None) is not None: 390 found=res[self.brew_version_txt_key][:len(self.my_version_txt)]==self.my_version_txt 391 if found: 392 res['model']=self.my_model 393 res['manufacturer']='LG Electronics Inc' 394 s=res.get(self.esn_file_key, None) 395 if s: 396 res['esn']=self.get_esn(s)
397 398 my_version_txt='CX8100' 399 my_model='LG8100'
400 401 402 # Media stuff--------------------------------------------------------------- 403 # Bypassing the 8100/9800 specific stuff 404 # def getmedia(self, maps, results, key): 405 # return com_lg.LGNewIndexedMedia2.getmedia(self, maps, results, key) 406 # def savemedia(self, mediakey, mediaindexkey, maps, results, merge, reindexfunction): 407 # return com_lg.LGNewIndexedMedia2.savemedia(self, mediakey, mediaindexkey, maps, results, merge, reindexfunction) 408 409 parentprofile=com_lgvx8100.Profile
410 -class Profile(parentprofile):
411 protocolclass=Phone.protocolclass 412 serialsname=Phone.serialsname 413 414 BP_Calendar_Version=3 415 phone_manufacturer='LG Electronics Inc' 416 phone_model='LG8100' 417 418 WALLPAPER_WIDTH=176 419 WALLPAPER_HEIGHT=220 420 MAX_WALLPAPER_BASENAME_LENGTH=32 421 WALLPAPER_FILENAME_CHARS="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789()-_ ." 422 WALLPAPER_CONVERT_FORMAT="jpg" 423 424 # the 8100 uses "W" for wait in the dialstring, it does not support "T" 425 DIALSTRING_CHARS="[^0-9PW#*]" 426 427 MAX_RINGTONE_BASENAME_LENGTH=32 428 RINGTONE_FILENAME_CHARS="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789()-_ ." 429 430 # the 8100 doesn't have seperate origins - they are all dumped in "images" 431 imageorigins={} 432 imageorigins.update(common.getkv(parentprofile.stockimageorigins, "images"))
433 - def GetImageOrigins(self):
434 return self.imageorigins
435 436 # our targets are the same for all origins 437 imagetargets={} 438 imagetargets.update(common.getkv(parentprofile.stockimagetargets, "outsidelcd", 439 {'width': 128, 'height': 128, 'format': "JPEG"})) 440 imagetargets.update(common.getkv(parentprofile.stockimagetargets, "fullscreen", 441 {'width': 176, 'height': 220, 'format': "JPEG"})) 442
443 - def GetTargetsForImageOrigin(self, origin):
444 return self.imagetargets
445 446
447 - def __init__(self):
448 parentprofile.__init__(self)
449 450 _supportedsyncs=( 451 ('phonebook', 'read', None), # all phonebook reading 452 ('calendar', 'read', None), # all calendar reading 453 ('wallpaper', 'read', None), # all wallpaper reading 454 ('ringtone', 'read', None), # all ringtone reading 455 ('call_history', 'read', None),# all call history list reading 456 ('sms', 'read', None), # all SMS list reading 457 ('memo', 'read', None), # all memo list reading 458 ('phonebook', 'write', 'OVERWRITE'), # only overwriting phonebook 459 ('calendar', 'write', 'OVERWRITE'), # only overwriting calendar 460 ('wallpaper', 'write', 'MERGE'), # merge and overwrite wallpaper 461 ('wallpaper', 'write', 'OVERWRITE'), 462 ('ringtone', 'write', 'MERGE'), # merge and overwrite ringtone 463 ('ringtone', 'write', 'OVERWRITE'), 464 ('sms', 'write', 'OVERWRITE'), # all SMS list writing 465 ('memo', 'write', 'OVERWRITE'), # all memo list writing 466 ) 467 468 field_color_data={ 469 'phonebook': { 470 'name': { 471 'first': 1, 'middle': 1, 'last': 1, 'full': 1, 472 'nickname': 0, 'details': 1 }, 473 'number': { 474 'type': 5, 'speeddial': 5, 'number': 5, 'details': 5 }, 475 'email': 2, 476 'address': { 477 'type': 0, 'company': 0, 'street': 0, 'street2': 0, 478 'city': 0, 'state': 0, 'postalcode': 0, 'country': 0, 479 'details': 0 }, 480 'url': 0, 481 'memo': 1, 482 'category': 1, 483 'wallpaper': 1, 484 'ringtone': 2, 485 'storage': 0, 486 }, 487 'calendar': { 488 'description': True, 'location': True, 'allday': True, 489 'start': True, 'end': True, 'priority': False, 490 'alarm': True, 'vibrate': True, 491 'repeat': True, 492 'memo': False, 493 'category': False, 494 'wallpaper': False, 495 'ringtone': True, 496 }, 497 'memo': { 498 'subject': True, 499 'date': True, 500 'secret': False, 501 'category': False, 502 'memo': True, 503 }, 504 'todo': { 505 'summary': False, 506 'status': False, 507 'due_date': False, 508 'percent_complete': False, 509 'completion_date': False, 510 'private': False, 511 'priority': False, 512 'category': False, 513 'memo': False, 514 }, 515 }
516