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

Source Code for Module phones.com_samsungscha310

  1  ### BITPIM 
  2  ### 
  3  ### Copyright (C) 2004 Joe Pham <djpham@netzero.com> 
  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_samsungscha310.py 4365 2007-08-17 21:11:59Z djpham $ 
  9   
 10  """Communicate with a Samsung SCH-A310""" 
 11   
 12  # lib modules 
 13  import sha 
 14   
 15  # my modules 
 16  import common 
 17  import commport 
 18  import com_brew 
 19  import com_phone 
 20  import com_samsung 
 21   
 22   
23 -class Phone(com_samsung.Phone):
24 25 "Talk to the Samsung SCH-A310 Cell Phone" 26 27 desc="SCH-A310" 28 serialsname='scha310' 29 30 __groups_range=xrange(5) 31 __phone_entries_range=xrange(1,501) 32 __pb_max_entries=23 33 __pb_max_speeddials=500 34 __pb_entry=0 35 __pb_mem_loc=1 36 __pb_group=2 37 __pb_ringtone=3 38 __pb_name=4 39 __pb_speed_dial=5 40 __pb_secret=6 41 __pb_home_num=7 42 __pb_office_num=9 43 __pb_mobile_num=11 44 __pb_pager_num=13 45 __pb_fax_num=15 46 __pb_no_label_num=17 47 __pb_blanks=(19, 20) 48 __pb_email=21 49 __pb_date_time_stamp=22 50 __pb_numbers= ({'home': __pb_home_num}, 51 {'office': __pb_office_num}, 52 {'cell': __pb_mobile_num}, 53 {'pager': __pb_pager_num}, 54 {'fax': __pb_fax_num}, 55 {'none': __pb_no_label_num}) 56 __pb_max_name_len=12 57 __pb_max_number_len=32 58 __pb_max_emails=1 59 builtinringtones=( 'Inactive', 60 'Bell 1', 'Bell 2', 'Bell 3', 'Bell 4', 'Bell 5', 61 'Melody 1', 'Melody 2', 'Melody 3', 'Melody 4', 'Melody 5', 62 'Melody 6', 'Melody 7', 'Melody 8', 'Melody 9', 'Melody 10', 63 'Melody 11', 'Melody 12', 'Melody 13', 'Melody 14', 'Melody 15', 64 'Melody 16') 65 66 __cal_end_datetime_value=None 67
68 - def __init__(self, logtarget, commport):
69 "Calls all the constructors and sets initial modes" 70 com_samsung.Phone.__init__(self, logtarget, commport) 71 self.mode=self.MODENONE
72
73 - def getfundamentals(self, results):
74 """Gets information fundamental to interopating with the phone and UI. 75 Currently this is: 76 77 - 'uniqueserial' a unique serial number representing the phone 78 - 'groups' the phonebook groups 79 - 'wallpaper-index' map index numbers to names 80 - 'ringtone-index' map index numbers to ringtone names 81 82 This method is called before we read the phonebook data or before we 83 write phonebook data. 84 """ 85 86 if not self.is_online(): 87 self.log("Failed to talk to phone") 88 return results 89 90 self.setmode(self.MODEPHONEBOOK) 91 92 # use a hash of ESN and other stuff (being paranoid) 93 self.log("Retrieving fundamental phone information") 94 self.log("Reading phone serial number") 95 results['uniqueserial']=sha.new(self.get_esn()).hexdigest() 96 97 # now read groups 98 self.log("Reading group information") 99 g=self.get_groups(self.__groups_range) 100 groups={} 101 102 for i in range(len(g)): 103 if len(g[i]): 104 groups[i]={ 'name': g[i] } 105 results['groups']=groups 106 107 # get the ringtones 108 self.log('Reading ringtone index') 109 results['ringtone-index']=self.get_ringtone_index() 110 self.setmode(self.MODEMODEM) 111 self.log("Fundamentals retrieved") 112 return results
113
114 - def get_ringtone_index(self):
115 try: 116 s=self.comm.sendatcommand('#PUGSN?') 117 if len(s)==0: 118 return {} 119 except commport.ATError: 120 return {} 121 122 r={} 123 for k in s[1:]: 124 s3=k.split(',') 125 r[int(s3[0])]={ 'name': s3[2], 'origin': 'builtin' } 126 return r
127
128 - def _get_phonebook(self, result, show_progress=True):
129 """Reads the phonebook data. The L{getfundamentals} information will 130 already be in result.""" 131 self.setmode(self.MODEPHONEBOOK) 132 c=len(self.__phone_entries_range) 133 k=0 134 pb_book={} 135 for j in self.__phone_entries_range: 136 pb_entry=self.get_phone_entry(j); 137 if len(pb_entry)==self.__pb_max_entries: 138 pb_book[k]=self._extract_phone_entry(pb_entry, result) 139 if show_progress: 140 self.progress(j, c, 'Reading '+pb_entry[self.__pb_name]) 141 k+=1 142 else: 143 if show_progress: 144 self.progress(j, c, 'Blank entry: %d' % j) 145 self.setmode(self.MODEMODEM) 146 return pb_book
147
148 - def getphonebook(self,result):
149 """Reads the phonebook data. The L{getfundamentals} information will 150 already be in result.""" 151 if not self.is_online(): 152 self.log("Failed to talk to phone") 153 return {} 154 pb_book=self._get_phonebook(result) 155 result['phonebook']=pb_book 156 return pb_book
157
158 - def _extract_phone_entry(self, entry, fundamentals):
159 160 res={} 161 162 # serials 163 res['serials']=[ {'sourcetype': self.serialsname, 164 'sourceuniqueid': fundamentals['uniqueserial'], 165 'serial1': entry[self.__pb_entry], 166 'serial2': entry[self.__pb_mem_loc] }] 167 168 # only one name 169 res['names']=[ {'full': entry[self.__pb_name].strip('"') } ] 170 171 # only one category 172 g=fundamentals['groups'] 173 i=int(entry[self.__pb_group]) 174 res['categories']=[ {'category': g[i]['name'] } ] 175 176 # emails 177 s=entry[self.__pb_email].strip('"') 178 if len(s): 179 res['emails']=[ { 'email': s } ] 180 181 # urls 182 # private 183 res['flags']=[ { 'secret': entry[self.__pb_secret]=='1' } ] 184 185 # memos 186 # wallpapers 187 # ringtones 188 r=fundamentals['ringtone-index'] 189 try: 190 ringtone_name=r[int(entry[self.__pb_ringtone])]['name'] 191 except: 192 ringtone_name=entry[self.__pb_ringtone] 193 res['ringtones']=[ { 'ringtone': ringtone_name, 194 'use': 'call' } ] 195 196 # numbers 197 speed_dial=int(entry[self.__pb_speed_dial]) 198 res['numbers']=[] 199 for k in range(len(self.__pb_numbers)): 200 n=self.__pb_numbers[k] 201 for key in n: 202 if len(entry[n[key]]): 203 if speed_dial==k: 204 res['numbers'].append({ 'number': entry[n[key]], 205 'type': key, 206 'speeddial': int(entry[self.__pb_mem_loc])}) 207 else: 208 res['numbers'].append({ 'number': entry[n[key]], 209 'type': key }) 210 return res
211
212 - def savephonebook(self, data):
213 "Saves out the phonebook" 214 if not self.is_online(): 215 self.log("Failed to talk to phone") 216 return data 217 218 pb_book=data['phonebook'] 219 pb_groups=data['groups'] 220 self.log('Validating phonebook entries.') 221 del_entries=[] 222 for k in pb_book: 223 if not self.__validate_entry(pb_book[k], pb_groups): 224 self.log('Invalid entry, entry will be not be sent.') 225 del_entries.append(k) 226 for k in del_entries: 227 self.log('Deleting entry '+pb_book[k]['names'][0]['full']) 228 del pb_book[k] 229 self._has_duplicate_speeddial(pb_book) 230 self.log('All entries validated') 231 232 pb_locs=[False]*(len(self.__phone_entries_range)+1) 233 pb_mem=[False]*len(pb_locs) 234 235 # get existing phonebook from the phone 236 self.log("Getting current phonebook from the phone") 237 current_pb=self._get_phonebook(data, True) 238 239 # check and adjust for speeddial changes 240 self.log("Processing speeddial data") 241 for k in pb_book: 242 self._update_speeddial(pb_book[k]) 243 244 # check for deleted entries and delete them 245 self.setmode(self.MODEPHONEBOOK) 246 self.log("Processing deleted entries") 247 for k1 in current_pb: 248 s1=current_pb[k1]['serials'][0]['serial1'] 249 found=False 250 for k2 in pb_book: 251 if self._same_serial1(s1, pb_book[k2]): 252 found=True 253 break 254 if found: 255 pb_locs[int(current_pb[k1]['serials'][0]['serial1'])]=True 256 pb_mem[int(current_pb[k1]['serials'][0]['serial2'])]=True 257 else: 258 self.log("Deleted item: "+current_pb[k1]['names'][0]['full']) 259 # delete the entries from data and the phone 260 self.progress(0, 10, "Deleting "+current_pb[k1]['names'][0]['full']) 261 self._del_phone_entry(current_pb[k1]) 262 mem_idx, loc_idx = self.__pb_max_speeddials, 1 263 264 # check for new entries & update serials 265 self.log("Processing new & updated entries") 266 serials_update=[] 267 progresscur, progressmax=1,len(pb_book) 268 ringtone_index=data['ringtone-index'] 269 for k in pb_book: 270 if progresscur>len(self.__phone_entries_range): 271 self.log('Max phone entries exceeded: '+str(progresscur)) 272 break 273 e=pb_book[k] 274 if not self._has_serial1(e): 275 while pb_locs[loc_idx]: 276 loc_idx += 1 277 pb_locs[loc_idx]=True 278 sd=self._get_speeddial(e) 279 if sd: 280 mem_index=sd 281 pb_mem[sd]=True 282 else: 283 while pb_mem[mem_idx]: 284 mem_idx -= 1 285 pb_mem[mem_idx]=True 286 mem_index=mem_idx 287 self._set_speeddial(e, mem_idx) 288 s1={ 'sourcetype': self.serialsname, 289 'sourceuniqueid': data['uniqueserial'], 290 'serial1': `loc_idx`, 291 'serial2': `mem_index` } 292 293 e['serials'].append(s1) 294 self.log("New entries: Name: "+e['names'][0]['full']+", s1: "+`loc_idx`+", s2: "+`mem_index`) 295 serials_update.append((self._bitpim_serials(e), s1)) 296 self.progress(progresscur, progressmax, "Updating "+e['names'][0]['full']) 297 if not self._write_phone_entry(e, pb_groups, ringtone_index): 298 self.log("Failed to save entry: "+e['names'][0]['full']) 299 progresscur += 1 300 301 # update existing and new entries 302 data["serialupdates"]=serials_update 303 self.log("Done") 304 self.setmode(self.MODEMODEM) 305 306 return data
307 308 309 # validate a phonebook entry, return True if good, False otherwise
310 - def __validate_entry(self, pb_entry, pb_groups):
311 try: 312 # validate name & alias 313 name=pb_entry['names'][0]['full'].replace('"', '') 314 if len(name)>self.__pb_max_name_len: 315 name=name[:self.__pb_max_name_len] 316 if pb_entry['names'][0]['full']!=name: 317 pb_entry['names'][0]['full']=name 318 # validate numbers 319 has_number_or_email=False 320 if pb_entry.has_key('numbers'): 321 for n in pb_entry['numbers']: 322 num=self.phonize(n['number']) 323 if len(num)>self.__pb_max_number_len: 324 num=num[:self.__pb_max_number_len] 325 if num != n['number']: 326 self.log('Updating number from '+n['number']+' to '+num) 327 n['number']=num 328 try: 329 self._get_number_type(n['type']) 330 except: 331 self.log(n['number']+': setting type to home.') 332 n['type']='home' 333 has_number_or_email=True 334 # validate emails 335 if pb_entry.has_key('emails'): 336 if len(pb_entry['emails'])>self.__pb_max_emails: 337 self.log(name+': Each entry can only have %s emails. The rest will be ignored.'%str(self.__pb_max_emails)) 338 email=pb_entry['emails'][0]['email'] 339 email.replace('"', '') 340 if len(email)>self.__pb_max_number_len: 341 email=email[:self.__pb_max_number_len] 342 if email!=pb_entry['emails'][0]['email']: 343 pb_entry['emails'][0]['email']=email 344 has_number_or_email=True 345 if not has_number_or_email: 346 self.log(name+': Entry has no numbers or emails') 347 # return False so this entry can be deleted from the dict 348 return False 349 # validate groups 350 found=False 351 if pb_entry.has_key('categories') and len(pb_entry['categories']): 352 pb_cat=pb_entry['categories'][0]['category'] 353 for k in pb_groups: 354 if pb_groups[k]['name']==pb_cat: 355 found=True 356 break 357 if not found: 358 self.log(name+': category set to '+pb_groups[0]['name']) 359 pb_entry['categories']=[{'category': pb_groups[0]['name']}] 360 # validate ringtones 361 found=False 362 if pb_entry.has_key('ringtones') and len(pb_entry['ringtones']): 363 pb_rt=pb_entry['ringtones'][0]['ringtone'] 364 # can only set to builtin-ringtone 365 for k in self.builtinringtones: 366 if k==pb_rt: 367 found=True 368 break 369 if not found: 370 self.log(name+': ringtone set to '+self.builtinringtones[0]) 371 pb_entry['ringtones']=[{'ringtone': self.builtinringtones[0], 372 'use': 'call' }] 373 # everything's cool 374 return True 375 except: 376 raise
377
378 - def _has_duplicate_speeddial(self, pb_book):
379 b=[False]*(self.__pb_max_speeddials+1) 380 for k in pb_book: 381 try: 382 for k1, kk in enumerate(pb_book[k]['numbers']): 383 sd=kk['speeddial'] 384 if sd and b[sd]: 385 # speed dial is in used, remove this one 386 del pb_book[k]['numbers'][k1]['speeddial'] 387 self.log('speeddial %d exists, deleted'%sd) 388 else: 389 b[sd]=True 390 except: 391 pass 392 return False
393
394 - def _update_speeddial(self, pb_entry):
395 try: 396 s=self._my_serials(pb_entry) 397 s1=int(s['serial2']) 398 sd=self._get_speeddial(pb_entry) 399 if not sd: 400 # speed dial not set, set it to current mem slot 401 self._set_speeddial(pb_entry, s1) 402 elif sd!=s1: 403 # speed dial set to a different slot, mark it 404 self._del_my_serials(pb_entry) 405 except: 406 pass
407
408 - def _get_speeddial(self, pb_entry):
409 n=pb_entry.get('numbers', []) 410 for k in n: 411 try: 412 if k['speeddial']: 413 return k['speeddial'] 414 except: 415 pass 416 return 0
417
418 - def _set_speeddial(self, pb_entry, sd):
419 if not pb_entry.has_key('numbers'): 420 # no numbers key, just return 421 return 422 for k in pb_entry['numbers']: 423 if k.has_key('speeddial'): 424 k['speeddial']=sd 425 return 426 pb_entry['numbers'][0]['speeddial']=sd
427
428 - def _del_phone_entry(self, pb_entry):
429 try: 430 return self.save_phone_entry(self._my_serials(pb_entry)['serial1']) 431 except: 432 return False
433
434 - def _same_serial1(self, s1, pb_entry):
435 for k in pb_entry['serials']: 436 if k['sourcetype']==self.serialsname and k.has_key('serial1'): 437 return k['serial1']==s1 438 return False
439
440 - def _has_serial1(self, pb_entry):
441 for k in pb_entry['serials']: 442 if k['sourcetype']==self.serialsname and k.has_key('serial1'): 443 return True 444 return False
445
446 - def _bitpim_serials(self, pb_entry):
447 for k in pb_entry['serials']: 448 if k['sourcetype']=="bitpim": 449 return k 450 return {}
451
452 - def _del_my_serials(self, pb_entry):
453 for k in range(len(pb_entry['serials'])): 454 if pb_entry['serials'][k]['sourcetype']==self.serialsname: 455 del pb_entry['serials'][k] 456 return
457
458 - def _my_serials(self, pb_entry):
459 for k in pb_entry['serials']: 460 if k['sourcetype']==self.serialsname: 461 return k 462 return {}
463
464 - def _get_number_type(self, type):
465 n=self.__pb_numbers 466 for k in range(len(n)): 467 if n[k].has_key(type): 468 return k, n[k][type] 469 raise common.IntegrityCheckFailed(self.desc, "Invalid Number Type")
470
471 - def _write_phone_entry(self, pb_entry, groups, ringtone_index):
472 # setting up a list to send to the phone, all fields preset to '0' 473 e=['0']*self.__pb_max_entries 474 # setting the entry # and memory location # 475 serials=self._my_serials(pb_entry) 476 e[self.__pb_entry]=serials['serial1'] 477 e[self.__pb_mem_loc]=serials['serial2'] 478 # groups/categories 479 grp=0 480 try: 481 grp_name=pb_entry['categories'][0]['category'] 482 for k in range(len(groups)): 483 if groups[k]['name']==grp_name: 484 grp=k 485 break 486 except: 487 # invalid group or no group specified, default to group 0 488 grp, pb_entry['categories']=0, [{'category': groups[0]['name']}] 489 e[self.__pb_group]=`grp` 490 491 # ringtones 492 e[self.__pb_ringtone]=None 493 try: 494 rt=pb_entry['ringtones'][0]['ringtone'] 495 for k, n in enumerate(self.builtinringtones): 496 if n==rt: 497 e[self.__pb_ringtone]=`k` 498 break 499 except: 500 pass 501 if e[self.__pb_ringtone] is None: 502 e[self.__pb_ringtone]='0' 503 pb_entry['ringtones']=[ { 'ringtone': self.builtinringtones[0], 504 'use': 'call' } ] 505 506 # name 507 e[self.__pb_name]='"'+pb_entry['names'][0]['full']+'"' 508 509 # private/secret 510 secret='0' 511 512 try: 513 if pb_entry['flags'][0]['secret']: 514 secret='1' 515 except: 516 pass 517 e[self.__pb_secret]=secret 518 519 # numbers & speed dial 520 # preset to empty 521 for k in range(len(self.__pb_numbers)): 522 for kk in self.__pb_numbers[k]: 523 e[self.__pb_numbers[k][kk]]='' 524 e[self.__pb_numbers[k][kk]+1]='' 525 speed_dial='0' 526 n=pb_entry.get('numbers', []) 527 for k in range(len(n)): 528 try: 529 nk=n[k] 530 kkk, kk=self._get_number_type(nk['type']) 531 except: 532 # invalid type, default to 'home' 533 nk['type']='home' 534 kkk, kk=0, self.__pb_home_num 535 e[kk],e[kk+1]=self.phonize(nk['number']), secret 536 try: 537 if nk['speeddial']: 538 speed_dial=`kkk` 539 except: 540 pass 541 542 e[self.__pb_speed_dial]=speed_dial 543 # email 544 email='' 545 try: 546 email=pb_entry['emails'][0]['email'] 547 except: 548 pass 549 e[self.__pb_email]='"'+email+'"' 550 for k in self.__pb_blanks: 551 e[k]='' 552 e[self.__pb_date_time_stamp]=self.get_time_stamp() 553 554 # final check to determine if this entry has changed. 555 # if it has not then do nothing and just return 556 557 ee=self.get_phone_entry(int(e[self.__pb_entry])) 558 if len(ee): 559 # valid phone entry, do comparison 560 # DSV took " out, need put them back in 561 ee[self.__pb_name]='"'+ee[self.__pb_name]+'"' 562 ee[self.__pb_email]='"'+ee[self.__pb_email]+'"' 563 k=self.__pb_max_entries-2 564 if e[0:k]==ee[0:k]: 565 return True 566 567 return self.save_phone_entry('0,'+','.join(e))
568 569 getphoneinfo=com_samsung.Phone._getphoneinfo 570 571 getringtones=None 572 573 getwallpapers=None 574 575 getmedia=None
576
577 -class Profile(com_samsung.Profile):
578 579 serialsname='scha310' 580 # use for auto-detection 581 phone_manufacturer='SAMSUNG ELECTRONICS' 582 phone_model='SCH-A310/148' 583
584 - def __init__(self):
586 587 _supportedsyncs=( 588 ('phonebook', 'read', None), # all phonebook reading 589 ('phonebook', 'write', 'OVERWRITE'), # only overwriting phonebook 590 ('calendar', 'read', None), # all calendar reading 591 ('calendar', 'write', 'OVERWRITE'), # only overwriting calendar 592 ) 593
594 - def convertphonebooktophone(self, helper, data):
595 596 return data;
597