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

Source Code for Module phones.com_samsung

   1  ### BITPIM 
   2  ### 
   3  ### Copyright (C) 2004 Joe Pham <djpham@netzero.com> 
   4  ### Copyright (C) 2004 Stephen Wood <saw@bitpim.org> 
   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_samsung.py 4365 2007-08-17 21:11:59Z djpham $ 
  10   
  11  """Communicate with a Samsung SCH-Axx phone using AT commands""" 
  12  # standard modules 
  13  import copy 
  14  import datetime 
  15  import re 
  16  import time 
  17   
  18  # site-packages 
  19  from thirdparty import DSV 
  20   
  21  # BitPim modules 
  22  import bpcalendar 
  23  import com_brew 
  24  import com_phone 
  25  import common 
  26  import commport 
  27  import memo 
  28  import p_brew 
  29  import phoneinfo 
  30  import sms 
  31  import todo 
32 33 -class Phone(com_phone.Phone,com_brew.BrewProtocol):
34 "Talk to a Samsung phone using AT commands" 35 36 desc="Samsung SCH-Axx phone" 37 38 MODEPHONEBOOK="modephonebook" 39 40 _AT_str="AT" 41 _OK_str="\r\nOK\r\n" 42 _Error_str="\r\nERROR\r\n" 43 _read_timeout=0.1 44 # Calendar class vars 45 _cal_entries_range=xrange(20) 46 _cal_max_events=20 47 _cal_max_events_per_day=9 48 _cal_num_of_read_fields=7 49 _cal_num_of_write_fields=6 50 _cal_entry=0 51 _cal_start_datetime=1 52 _cal_end_datetime=2 53 # if your phone does not support and end-datetime, set this to a default value 54 # if it does support end-datetime, set this to None 55 _cal_end_datetime_value='19800106T000000' 56 _cal_datetime_stamp=3 57 _cal_alarm_type=4 58 _cal_read_name=6 59 _cal_write_name=5 60 _cal_alarm_values={ 61 '0': -1, '1': 0, '2': 10, '3': 30, '4': 60 } 62 _cal_max_name_len=32 63 _switch_mode_cmd='\x44\x58\xf4\x7e' 64
65 - def __init__(self, logtarget, commport):
66 "Call all the contructors and sets initial modes" 67 com_phone.Phone.__init__(self, logtarget, commport) 68 com_brew.BrewProtocol.__init__(self) 69 self.mode=self.MODENONE
70
71 - def _setmodephonebooktobrew(self):
72 self.setmode(self.MODEMODEM) 73 self.setmode(self.MODEBREW) 74 return True
75
76 - def _setmodemodemtobrew(self):
77 self.log('Switching from modem to BREW') 78 try: 79 self.comm.sendatcommand('$QCDMG') 80 return True 81 except: 82 pass 83 # give it another try 84 self.log('Retry switching from modem to BREW') 85 try: 86 self.comm.sendatcommand('$QCDMG') 87 return True 88 except commport.ATError: 89 return False 90 except: 91 if __debug__: 92 self.log('Got an excepetion') 93 return False
94
95 - def _setmodebrew(self):
96 # switch from None to BREW 97 self.log('Switching from None to BREW') 98 # do it the long, but sure, way: 1st try to switch to modem 99 if not self._setmodemodem(): 100 # can't switch to modem, give up 101 return False 102 # then switch from modem to BREW 103 return self._setmodemodemtobrew()
104
105 - def _setmodebrewtomodem(self):
106 self.log('Switching from BREW to modem') 107 try: 108 self.comm.write(self._switch_mode_cmd, False) 109 self.comm.readsome(numchars=5, log=False) 110 return True 111 except: 112 pass 113 # give it a 2nd try 114 try: 115 self.comm.write(self._switch_mode_cmd, False) 116 self.comm.readsome(numchars=5, log=False) 117 return True 118 except: 119 return False
120
121 - def _setmodemodemtophonebook(self):
122 self.log('Switching from modem to phonebook') 123 response=self.comm.sendatcommand("#PMODE=1") 124 return True
125
126 - def _setmodemodem(self):
127 self.log('Switching to modem') 128 try: 129 self.comm.sendatcommand('E0V1') 130 return True 131 except: 132 pass 133 # could be in BREW mode, try switch over 134 self.log('trying to switch from BREW mode') 135 if not self._setmodebrewtomodem(): 136 return False 137 try: 138 self.comm.sendatcommand('E0V1') 139 return True 140 except: 141 return False
142
143 - def _setmodephonebook(self):
144 self.setmode(self.MODEMODEM) 145 self.setmode(self.MODEPHONEBOOK) 146 return True
147
148 - def _setmodephonebooktomodem(self):
149 self.log('Switching from phonebook to modem') 150 response=self.comm.sendatcommand("#PMODE=0") 151 return True
152
153 - def _get_at_response(self):
154 s=self.comm.read(1, False) 155 if not len(s): 156 return '' 157 158 # got at least one char, try to read the rest with short timeout 159 160 i=self.comm.ser.getTimeout() 161 self.comm.ser.setTimeout(self._read_timeout) 162 while True: 163 s1=self.comm.read(1, False) 164 if len(s1): 165 s += s1 166 else: 167 break 168 169 self.comm.ser.setTimeout(i) 170 return s
171
172 - def is_online(self):
173 self.setmode(self.MODEPHONEBOOK) 174 try: 175 self.comm.sendatcommand("E0V1") 176 return True 177 except commport.ATError: 178 return False
179
180 - def get_esn(self):
181 try: 182 s=self.comm.sendatcommand("+gsn") 183 if len(s): 184 return ' '.join(s[0].split(": ")[1:]) 185 except commport.ATError: 186 pass 187 return ''
188
189 - def _send_and_get(self, at_command):
190 try: 191 s=self.comm.sendatcommand(str(at_command)) 192 if len(s): 193 return self.splitandunescape(s[0]) 194 except commport.ATError: 195 pass 196 return None
197
198 - def get_model(self):
199 return ','.join(self._send_and_get('+GMM'))
200 - def get_manufacturer(self):
201 return ','.join(self._send_and_get('+GMI'))
202 - def get_phone_number(self):
203 return self._send_and_get('+MIN?')[0]
204 - def get_firmware_version(self):
205 return ','.join(self._send_and_get('+GMR'))
206 - def get_battery_level(self):
207 s=self._send_and_get('+CBC?') 208 if s is not None and len(s)==2: 209 return s[1]+'%'
210 - def get_signal_quality(self):
211 s=self._send_and_get('+CSQ?') 212 if s is not None and len(s)==2: 213 return str(100*int(s[0])/31)+'%'
214 - def get_analog_digital(self):
215 d={ '0': 'Analog', '1': 'Digital' } 216 s=self._send_and_get('+CAD?') 217 return d.get(s[0], '<Unknown>')
218
219 - def get_groups(self, groups_range):
220 221 g=[] 222 for i in groups_range: 223 try: 224 s=self.comm.sendatcommand("#PBGRR=%d" % i) 225 if len(s): 226 g.append(s[0].split(': ')[1].split(',')[1].strip('"')) 227 else: 228 g.append('') 229 except commport.ATError: 230 g.append('') 231 return g
232
233 - def get_phone_entry(self, entry_index, alias_column=-1, num_columns=-1):
234 try: 235 s=self.comm.sendatcommand("#PBOKR=%d" % entry_index) 236 if len(s): 237 line=s[0] 238 if alias_column >= 0 and alias_column < num_columns: 239 line=self.defrell(line, alias_column, num_columns) 240 return self.splitandunescape(line) 241 except commport.ATError: 242 pass 243 return []
244
245 - def del_phone_entry(self, entry_index):
246 try: 247 s=self.comm.sendatcommand("#PBOKW=%d" % entry_index) 248 return True 249 except commport.ATError: 250 return False
251
252 - def save_phone_entry(self, entry_str):
253 try: 254 s=self.comm.sendatcommand("#PBOKW="+entry_str) 255 return True 256 except commport.ATError: 257 return False
258
259 - def get_time_stamp(self):
260 261 now = time.localtime(time.time()) 262 return "%04d%02d%02dT%02d%02d%02d" % now[0:6]
263
264 - def phonize(self, str):
265 """Convert the phone number into something the phone understands 266 All digits, P, T, * and # are kept, everything else is removed""" 267 268 return re.sub("[^0-9PT#*]", "", str)
269
270 - def get_calendar_entry(self, entry_index):
271 try: 272 s=self.comm.sendatcommand('#PISHR=%d' % entry_index) 273 if len(s): 274 return self.splitandunescape(s[0]) 275 except commport.ATError: 276 pass 277 return []
278
279 - def save_calendar_entry(self, entry_str):
280 try: 281 self.comm.sendatcommand('#PISHW='+entry_str) 282 return True 283 except: 284 return False
285
286 - def get_memo_entry(self, entry_index):
287 try: 288 s=self.comm.sendatcommand('#PIMMR=%d'%entry_index) 289 if len(s): 290 return self.splitandunescape(s[0]) 291 except commport.ATError: 292 pass 293 return []
294
295 - def save_memo_entry(self, entry_str):
296 try: 297 self.comm.sendatcommand('#PIMMW='+entry_str) 298 return True 299 except: 300 return False
301
302 - def get_todo_entry(self, entry_index):
303 try: 304 s=self.comm.sendatcommand('#PITDR=%d' % entry_index) 305 if len(s): 306 return self.splitandunescape(s[0]) 307 except commport.ATError: 308 pass 309 return []
310
311 - def save_todo_entry(self, entry_str):
312 try: 313 self.comm.sendatcommand("#PITDW="+entry_str) 314 return True 315 except: 316 return False
317
318 - def get_sms_inbox(self, entry_index):
319 try: 320 s=self.comm.sendatcommand('#psrmr=%d'%entry_index) 321 if len(s): 322 return self.splitandunescape(s[0]) 323 except commport.ATError: 324 pass 325 return []
326 - def get_sms_saved(self, entry_index):
327 try: 328 s=self.comm.sendatcommand('#psfmr=%d'%entry_index) 329 if len(s): 330 return self.splitandunescape(s[0]) 331 except commport.ATError: 332 pass 333 return []
334 - def get_sms_sent(self, entry_index):
335 try: 336 s=self.comm.sendatcommand('#pssmr=%d'%entry_index) 337 if len(s): 338 return self.splitandunescape(s[0]) 339 except commport.ATError: 340 pass 341 return []
342 - def get_canned_msg(self, entry_index):
343 try: 344 s=self.comm.sendatcommand('#psstr=%d'%entry_index) 345 if len(s): 346 return self.splitandunescape(s[0]) 347 except commport.ATError: 348 pass 349 return []
350 - def save_canned_msg(self, entry_str):
351 try: 352 self.comm.sendatcommand('#psstw='+entry_str) 353 return True 354 except: 355 return False
356
357 - def extract_timedate(self, td):
358 # extract samsung timedate 'YYYYMMDDTHHMMSS' to (y, m, d, h, m) 359 return (int(td[:4]), int(td[4:6]), int(td[6:8]), int(td[9:11]), int(td[11:13]))
360
361 - def encode_timedate(self, td):
362 # reverse if extract_timedate 363 return "%04d%02d%02dT%02d%02d00" % tuple(td)
364
365 - def splitandunescape(self, line):
366 """Split fields and unescape double quote and right brace""" 367 # Should unescaping be done on fields that are not surrounded by 368 # double quotes? DSV strips these quotes, so we have to do it to 369 # all fields. 370 col=line.find(": ") 371 print line[col+2:] 372 e=DSV.importDSV([line[col+2:]])[0] 373 i=0 374 while i<len(e): 375 item=e[i] 376 item=item.replace("}\002",'"') 377 item=item.replace("}]","}") 378 e[i]=item 379 i+=1 380 381 return e
382
383 - def samsungescape(self, s):
384 """Escape double quotes and }'s in a string""" 385 #s=s.replace("}","}]") 386 #s=s.replace('"','}\002') 387 return s
388
389 - def defrell(self, s, acol, ncol):
390 """Fixes up phonebook responses with the alias field. The alias field 391 does not have quotes around it, but can still contain commas""" 392 # Example with A670 self.defrell(s, 17, 26) 393 if acol<0 or acol>=ncol: # Invalid alias column, do nothing 394 return s 395 e=s.split(",") 396 i=0 397 398 while i<len(e): 399 # Recombine when ,'s in quotes 400 if len(e[i]) and e[i][0]=='"' and e[i][-1]!='"': 401 while i+1<len(e) and (len(e[i+1])==0 or e[i+1][-1]!='"'): 402 e[i] += ","+e[i+1] 403 del e[i+1] 404 else: 405 if i+1<len(e): 406 e[i] += ","+e[i+1] 407 del e[i+1] 408 i+=1 409 410 if len(e)<=ncol: # Return original string if no excess commas 411 return s 412 413 for k in range(len(e)-ncol): 414 e[acol]+=","+e[acol+1] 415 del e[acol+1] 416 417 e[acol]='"'+e[acol]+'"' # quote the string 418 419 res=e[0] 420 for item in e[1:]: # Rejoin the columns 421 res+=","+item 422 423 return res
424 425
426 - def csvsplit(self, line):
427 """Parse a Samsung comma separated list.""" 428 e=line.split(",") 429 i=0 430 print len(e) 431 result=[] 432 while i<len(e): 433 # Recombine when ;'s in quotes 434 if len(e[i]) and e[i][0]=='"' and e[i][-1]!='"': 435 while i+1<len(e) and (len(e[i+1])==0 or e[i+1][-1]!='"'): 436 e[i] = e[i]+","+e[i+1] 437 del e[i+1] 438 else: 439 if i+1<len(e): 440 e[i] = e[i]+","+e[i+1] 441 del e[i+1] 442 443 444 # Identify type of each item 445 # Strip quotes on strings 446 # Un escape escaped characters 447 item=e[i] 448 if len(item)==0: 449 t=0 450 elif item[0]=='"' or item[-1]=='"': 451 mo=re.match('^"?(.*?)"?$',item) 452 item=mo.group(1) 453 item=item.replace("}\002",'"') 454 item=item.replace("}]","}") 455 t='string' 456 elif re.match('^\d+T\d+$',item): 457 t='timestamp' 458 elif re.match('^[\dPT]+$',item): 459 # Number or phone number 460 t='number' 461 elif re.match('^\(\d+-\d+\)',item): 462 t='range' 463 elif re.match('^\d\d?/\d\d?/\d\d(\d\d)?$',item): 464 t='date' 465 else: 466 t='other' 467 468 if t: 469 result.append({'type':t, 'value':item}) 470 else: 471 result.append(0) 472 473 i+=1 474 475 return result
476
477 - def getcalendar(self, result):
478 self.log("Getting calendar entries") 479 self.setmode(self.MODEPHONEBOOK) 480 res={} 481 l=len(self._cal_entries_range) 482 cal_cnt=0 483 for k in self._cal_entries_range: 484 r=self.get_calendar_entry(k) 485 if not len(r): 486 # blank, no entry 487 self.progress(k+1, l, "Getting blank entry: %d"%k) 488 continue 489 self.progress(k+1, l, "Getting "+r[self._cal_read_name]) 490 491 # build a calendar entry 492 entry=bpcalendar.CalendarEntry() 493 494 # start time date 495 entry.start=self.extract_timedate(r[self._cal_start_datetime]) 496 497 498 if self._cal_end_datetime_value is None: 499 # valid end time 500 entry.end=self.extract_timedate(r[self._cal_end_datetime]) 501 else: 502 # no end time, end time=start time 503 entry.end=entry.start 504 505 # description 506 entry.description=r[self._cal_read_name] 507 508 # alarm 509 try: 510 alarm=self._cal_alarm_values[r[self._cal_alarm_type]] 511 except: 512 alarm=None 513 entry.alarm=alarm 514 515 # update calendar dict 516 res[entry.id]=entry 517 cal_cnt += 1 518 result['calendar']=res 519 self.setmode(self.MODEMODEM) 520 return result
521
522 - def process_calendar(self, dict):
523 """ Optimize and expand calendar data suitable for phone download 524 """ 525 # first go thru the dict to organize events by date 526 # and also determine the latest event date 527 r={} 528 rp=[] 529 today=datetime.date.today() 530 last_date=today 531 if __debug__: 532 print 'original calendar:' 533 for k,e in dict.items(): 534 if __debug__: 535 print e.description,':',e.start 536 sd=datetime.date(*e.start[:3]) 537 ed=datetime.date(*e.end[:3]) 538 if ed>last_date: 539 last_date=ed 540 if e.repeat is None: 541 if sd>=today: 542 r.setdefault(e.start[:3], []).append(Samsung_Calendar(e)) 543 else: 544 if ed>=today: 545 rp.append(e) 546 # go through and expand on the repeated events 547 delta_1=datetime.timedelta(1) 548 for n in rp: 549 current_date=today 550 end_date=datetime.date(*n.end[:3]) 551 cnt=0 552 while current_date<=end_date: 553 if n.is_active(current_date.year, current_date.month, 554 current_date.day): 555 cd_l=(current_date.year, current_date.month, 556 current_date.day) 557 r.setdefault(cd_l, []).append(\ 558 Samsung_Calendar(n, cd_l)) 559 cnt+=1 560 if cnt>self._cal_max_events: 561 # enough for this one, breaking out 562 break 563 current_date+=delta_1 564 # and put them all into a list 565 res=[] 566 keys=r.keys() 567 # sort by date 568 keys.sort() 569 for k in keys: 570 # sort by time within this date 571 r[k].sort() 572 # clip by max events/day 573 if len(r[k])>self._cal_max_events_per_day: 574 res+=r[k][:self._cal_max_events_per_day] 575 else: 576 res+=r[k] 577 # clip by max events 578 if len(res)>self._cal_max_events: 579 res=res[:self._cal_max_events] 580 return res
581
582 - def savecalendar(self, dict, merge):
583 584 self.log("Sending calendar entries") 585 586 cal=self.process_calendar(dict['calendar']) 587 588 # testing 589 if __debug__: 590 print 'processed calendar: ', len(cal), ' items' 591 for c in cal: 592 print c.description,':', c.start 593 # testing 594 self.setmode(self.MODEPHONEBOOK) 595 self.log("Saving calendar entries") 596 cal_cnt=0 597 l=self._cal_max_events 598 for c in cal: 599 # Save this entry to phone 600 e=['']*self._cal_num_of_write_fields 601 602 # pos 603 e[self._cal_entry]=`cal_cnt` 604 605 # start date time 606 e[self._cal_start_datetime]=self.encode_timedate(c.start) 607 608 # end date time 609 if self._cal_end_datetime_value is None: 610 # valid end-datetime 611 e[self._cal_end_datetime]=self.encode_timedate(c.end) 612 else: 613 # no end-datetime, set to start-datetime 614 e[self._cal_end_datetime]=self._cal_end_datetime_value 615 616 # time stamp 617 e[self._cal_datetime_stamp]=self.get_time_stamp() 618 619 # Alarm type 620 e[self._cal_alarm_type]=c.alarm 621 622 # Name, check for bad char & proper length 623 name=c.description.replace('"', '') 624 if len(name)>self._cal_max_name_len: 625 name=name[:self._cal_max_name_len] 626 e[self._cal_write_name]='"'+name+'"' 627 628 # and save it 629 self.progress(cal_cnt+1, l, "Updating "+name) 630 if not self.save_calendar_entry(",".join(e)): 631 self.log("Failed to save item: "+name) 632 else: 633 cal_cnt += 1 634 635 # delete the rest of the 636 self.log('Deleting unused entries') 637 for k in range(cal_cnt, l): 638 self.progress(k, l, "Deleting entry %d" % k) 639 self.save_calendar_entry(`k`) 640 641 self.setmode(self.MODEMODEM) 642 643 return dict
644 # common methods for individual phones if they can use them w/o changes
645 - def _getmemo(self, result):
646 self.setmode(self.MODEPHONEBOOK) 647 m=MemoList(self) 648 m.read() 649 m_dict=m.get() 650 result['memo']=m_dict 651 self.setmode(self.MODEMODEM) 652 return m_dict
653
654 - def _savememo(self, result, merge):
655 self.setmode(self.MODEPHONEBOOK) 656 m=MemoList(self) 657 r=result.get('memo', {}) 658 m.set(r) 659 m.write() 660 self.setmode(self.MODEMODEM) 661 return r
662
663 - def _gettodo(self, result):
664 self.log("Getting todo entries") 665 self.setmode(self.MODEPHONEBOOK) 666 td_l=TodoList(self) 667 td_l.read() 668 result['todo']=td_l.get() 669 self.setmode(self.MODEMODEM) 670 return result
671
672 - def _savetodo(self, result, merge):
673 self.log("Saving todo entries") 674 self.setmode(self.MODEPHONEBOOK) 675 td_l=TodoList(self, result.get('todo', {})) 676 td_l.validate() 677 td_l.write() 678 self.setmode(self.MODEMODEM) 679 return result
680
681 - def _getsms(self, result):
682 self.log("Getting SMS entries") 683 self.setmode(self.MODEPHONEBOOK) 684 sms_l=SMSList(self) 685 sms_l.read() 686 result['sms']=sms_l.get() 687 sms_canned=CannedMsgList(self) 688 sms_canned.read() 689 result['canned_msg']=sms_canned.get() 690 self.setmode(self.MODEMODEM) 691 return result
692 - def _savesms(self, result, merge):
693 self.log("Saving SMS Canned Messages") 694 self.setmode(self.MODEPHONEBOOK) 695 canned_msg=CannedMsgList(self, result.get('canned_msg', {})) 696 canned_msg.write() 697 self.setmode(self.MODEMODEM) 698 return result
699 - def _getphoneinfo(self, phone_info):
700 self.log('Getting Phone Info') 701 self.setmode(self.MODEPHONEBOOK) 702 for e in phoneinfo.PhoneInfo.standard_keys: 703 f=getattr(self, 'get_'+e[0]) 704 setattr(phone_info, e[0], f()) 705 phone_info.append('Analog/Digital:', self.get_analog_digital()) 706 self.setmode(self.MODEMODEM)
707
708 - def _send_at_and_get(self, cmd):
709 try: 710 resp=self.comm.sendatcommand(cmd) 711 return ': '.join(resp[0].split(': ')[1:]) 712 except: 713 return None
714
715 - def is_mode_modem(self):
716 try: 717 resp=self.comm.sendatcommand('E0V1') 718 return True 719 except: 720 return False
721
722 - def get_detect_data(self, r):
723 # get detection data 724 r['manufacturer']=self._send_at_and_get('+GMI') 725 r['model']=self._send_at_and_get('+GMM') 726 r['firmware_version']=self._send_at_and_get('+GMR') 727 r['esn']=self._send_at_and_get('+GSN')
728 729 @classmethod
730 - def detectphone(_, coms, likely_ports, res, _module, _log):
731 if not len(likely_ports): 732 return None 733 for port in likely_ports: 734 if not res.has_key(port): 735 res[port]={ 'mode_modem': None, 'mode_brew': None, 736 'manufacturer': None, 'model': None, 737 'firmware_version': None, 'esn': None, 738 'firmwareresponse': None } 739 try: 740 if res[port]['mode_modem']==False or \ 741 res[port]['model']: 742 continue 743 p=Phone(_log, commport.CommConnection(_log, port, timeout=1)) 744 if p.is_mode_modem(): 745 res[port]['mode_modem']=True 746 p.get_detect_data(res[port]) 747 else: 748 res[port]['mode_modem']=False 749 except: 750 # this port is not available 751 if __debug__: 752 raise
753
754 #------------------------------------------------------------------------------ 755 -class Profile(com_phone.Profile):
756 757 BP_Calendar_Version=3 758 759 serialsname='samsung' 760 761 usbids=( ( 0x04e8, 0x6601, 1), # Samsung internal USB interface 762 ) 763 764 # which device classes we are. 765 deviceclasses=("modem", "serial") 766 767 _supportedsyncs=() 768
769 - def __init__(self):
771
772 #------------------------------------------------------------------------------ 773 -class Samsung_Calendar:
774 _cal_alarm_values={ 775 '0': -1, '1': 0, '2': 10, '3': 30, '4': 60 } 776
777 - def __init__(self, calendar_entry, new_date=None):
778 self._start=self._end=self._alarm=self._desc=None 779 self._extract_cal_info(calendar_entry, new_date)
780
781 - def _extract_cal_info(self, cal_entry, new_date):
782 s=cal_entry.start 783 if new_date is not None: 784 s=new_date[:3]+s[3:] 785 self._start=s 786 self._end=cal_entry.end 787 self._desc=cal_entry.description 788 # approximate the alarm value 789 self._alarm='0' 790 alarm=cal_entry.alarm 791 _keys=self._cal_alarm_values.keys() 792 _keys.sort() 793 _keys.reverse() 794 for k in _keys: 795 if alarm>=self._cal_alarm_values[k]: 796 self._alarm=k 797 break
798
799 - def __lt__(self, rhs):
800 return self.start<rhs.start
801 - def __le__(self, rhs):
802 return self.start<=rhs.start
803 - def __eq__(self, rhs):
804 return self.start==rhs.start
805 - def __ne__(self, rhs):
806 return self.start!=rhs.start
807 - def __gt__(self, rhs):
808 return self.start>rhs.start
809 - def __ge__(self, rhs):
810 return self.start>=rhs.start
811
812 - def _get_start(self):
813 return self._start
814 start=property(fget=_get_start) 815
816 - def _get_end(self):
817 return self._end
818 end=property(fget=_get_end) 819
820 - def _get_desc(self):
821 return self._desc
822 description=property(fget=_get_desc) 823
824 - def _get_alarm(self):
825 return self._alarm
826 alarm=property(fget=_get_alarm)
827
828 #------------------------------------------------------------------------------- 829 -class MemoList(object):
830 # class constants 831 _max_num_entries=10 832 _range_entries=xrange(_max_num_entries) 833 _max_text_len=60 834 _max_subject_len=12 835 _max_num_of_fields=4 836 _text_index=3 837 _date_index=1 838 _max_write_fields=3 839 _write_entry_index=0 840 _write_date_index=1 841 _write_text_index=2 842 _continuation_char='-' 843
844 - def __init__(self, phone):
845 self._phone=phone 846 self._data={}
847
848 - def get(self):
849 return copy.deepcopy(self._data, {})
850
851 - def read(self):
852 self._data={} 853 text='' 854 for i in self._range_entries: 855 try: 856 self._phone.progress(i, self._max_num_entries, 857 'Reading Memo Entry: '+str(i)) 858 s=self._phone.get_memo_entry(i) 859 if len(s)!=self._max_num_of_fields: 860 continue 861 t=s[self._text_index] 862 if len(t)==self._max_text_len and \ 863 t[-1]==self._continuation_char: 864 # contination to the next record 865 text+=t[:len(t)-1] 866 continue 867 # new record 868 text+=t 869 m=memo.MemoEntry() 870 m.text=text 871 m.set_date_isostr(s[self._date_index]) 872 self._data[m.id]=m 873 text='' 874 except: 875 if __debug__: raise
876
877 - def write(self):
878 keys=self._data.keys() 879 keys.sort() 880 count=0 881 for k in keys: 882 if count>=self._max_num_entries: 883 self._phone.log('Max number of memos sent') 884 break 885 n=self._data[k] 886 text=n.text 887 subj=n.subject 888 l=min(self._max_subject_len, len(text)) 889 if subj[:l]!=text[:l]: 890 text=subj+':'+text 891 text.replace('"', '') 892 while len(text) and count<self._max_num_entries: 893 if len(text)>self._max_text_len: 894 sub_text=text[:self._max_text_len-1]+self._continuation_char 895 text=text[self._max_text_len-1:] 896 else: 897 sub_text=text 898 text='' 899 entry_str=['']*self._max_write_fields 900 entry_str[self._write_entry_index]=`count` 901 entry_str[self._write_date_index]=self._phone.get_time_stamp() 902 entry_str[self._write_text_index]='"'+sub_text+'"' 903 self._phone.progress(count, self._max_num_entries, 904 'Writing Memo Entry: '+str(count)) 905 if self._phone.save_memo_entry(','.join(entry_str)): 906 self._phone.log('Sent memo %s to the phone'%subj) 907 count+=1 908 else: 909 self._phone.log("Failed to send memo"+subj) 910 # clear out the rest of the slots 911 for k in xrange(count, self._max_num_entries): 912 self._phone.progress(k, self._max_num_entries, 913 'Deleing Memo Entry: '+str(k)) 914 self._phone.save_memo_entry(`k`)
915
916 - def set(self, data):
917 self._data={} 918 self._data.update(data)
919
920 #------------------------------------------------------------------------------- 921 -class TodoList(object):
922 _td_max_read_fields=6 923 _td_max_write_fields=5 924 _td_max_entries=20 925 _td_entry=0 926 _td_priority=1 927 _td_due_datetime=2 928 _td_datetime_stamp=3 929 _td_status=4 930 _td_subject=5 931 _td_write_subject=4 932 _td_max_len_name=32 933
934 - def __init__(self, phone, data={}):
935 self._phone=phone 936 self._data=data
937
938 - def get(self):
939 return copy.deepcopy(self._data, {})
940
941 - def _extract_fields(self, s):
942 entry=todo.TodoEntry() 943 i=int(s[self._td_priority]) 944 if i: 945 entry.priority=1 946 else: 947 entry.priority=10 948 entry.due_date=s[self._td_due_datetime][:8] 949 entry.summary=s[self._td_subject] 950 return entry
951
952 - def read(self):
953 self._data={} 954 cnt=0 955 for i in xrange(self._td_max_entries): 956 s=self._phone.get_todo_entry(i) 957 if not len(s): 958 self._phone.progress(i+1, self._td_max_entries, 959 'Getting blank entry: '+str(i)) 960 continue 961 self._phone.progress(i+1, self._td_max_entries, s[self._td_subject]) 962 e=self._extract_fields(s) 963 self._data[e.id]=e
964
965 - def _encode_fields(self, i, entry):
966 e=['']*self._td_max_write_fields 967 e[self._td_entry]=`i` 968 if entry.priority is not None and entry.priority<5: 969 e[self._td_priority]='1' 970 else: 971 e[self._td_priority]='0' 972 s=entry.due_date 973 if s is None or not len(s): 974 s=self._phone.get_time_stamp() 975 else: 976 s+='T000000' 977 e[self._td_due_datetime]=s 978 e[self._td_datetime_stamp]=self._phone.get_time_stamp() 979 e[self._td_write_subject]='"'+entry.summary+'"' 980 return ','.join(e)
981
982 - def _write_entry(self, i, entry):
983 return self._phone.save_todo_entry(self._encode_fields(i, entry))
984
985 - def validate(self):
986 for k,n in self._data.items(): 987 name=n.summary.replace('"', '') 988 if len(name)>self._td_max_len_name: 989 name=name[:self._td_max_len_name] 990 n.summary=name
991
992 - def write(self):
993 keys=self._data.keys() 994 keys.sort() 995 cnt=0 996 for k in keys: 997 n=self._data[k] 998 if cnt>self._td_max_entries: 999 break 1000 if self._write_entry(cnt, n): 1001 cnt += 1 1002 else: 1003 self._phone.log('Failed to save todo entry '+str(k)) 1004 self._phone.progress(cnt, self._td_max_entries, 'Saving entry: '+n.summary) 1005 for i in xrange(cnt, self._td_max_entries): 1006 self._phone.progress(i, self._td_max_entries, 'Deleting entry: '+str(i)) 1007 self._phone.save_todo_entry(`i`)
1008
1009 #------------------------------------------------------------------------------- 1010 -class SMS_Generic_List(object):
1011 - def __init__(self, phone):
1012 self._phone=phone 1013 self._data={}
1014 - def get(self):
1015 return self._data.copy()
1016 - def read(self):
1017 raise NotImplementedError
1018
1019 #------------------------------------------------------------------------------- 1020 -class SMS_Inbox_List(SMS_Generic_List):
1021 _max_entries=100 1022 _valid_range=xrange(_max_entries) 1023 _datetime_index=3 1024 _body_index=4 1025 _callback_index=5 1026 _field_num=6
1027 - def __init__(self, phone):
1028 super(SMS_Inbox_List, self).__init__(phone)
1029 - def read(self):
1030 for i in self._valid_range: 1031 self._phone.progress(i, self._max_entries, 1032 'Reading SMS Inbox Entry '+str(i)) 1033 s=self._phone.get_sms_inbox(i) 1034 if len(s)==self._field_num: 1035 e=sms.SMSEntry() 1036 e.folder=e.Folder_Inbox 1037 e.datetime=s[self._datetime_index] 1038 e._from, e.subject, txt=self._extract_body(s[self._body_index]) 1039 e.text=unicode(txt, errors='ignore') 1040 e.callback=s[self._callback_index] 1041 self._data[e.id]=e
1042
1043 - def _extract_body(self, s):
1044 try: 1045 # extract different components from the main text body 1046 _from=None 1047 l=s.split(' ') 1048 ss=l[0] 1049 if ss.find('@') != -1: 1050 # this the 'from' email address 1051 _from=ss 1052 l=l[1:] 1053 ss=l[0] 1054 _subj=[] 1055 if ss[0]=='(': 1056 while l: 1057 _subj.append(ss) 1058 l=l[1:] 1059 if ss[-1]==')': 1060 break 1061 if l: 1062 ss=l[0] 1063 if l: 1064 return (_from, ' '.join(_subj), ' '.join(l)) 1065 else: 1066 return (_from, '', ' '.join(_subj)) 1067 except: 1068 # something happend, just return the original text 1069 return (None, '', s)
1070
1071 #------------------------------------------------------------------------------- 1072 -class SMS_Saved_List(SMS_Generic_List):
1073 _max_entries=20 1074 _valid_range=xrange(_max_entries) 1075 _field_num=5 1076 _datetime_index=1 1077 _from_index=2 1078 _body_index=4
1079 - def __init__(self, phone):
1080 super(SMS_Saved_List, self).__init__(phone)
1081 - def read(self):
1082 for i in self._valid_range: 1083 self._phone.progress(i, self._max_entries, 1084 'Reading SMS Saved Entry '+str(i)) 1085 s=self._phone.get_sms_saved(i) 1086 if len(s)==self._field_num: 1087 e=sms.SMSEntry() 1088 e.folder=e.Folder_Saved 1089 e.datetime=s[self._datetime_index] 1090 e._from=s[self._from_index] 1091 e.subject, txt=self._extract_body(s[self._body_index]) 1092 e.text=unicode(txt, errors='ignore') 1093 self._data[e.id]=e
1094 - def _extract_body(self, s):
1095 # extract different components from the main text body 1096 try: 1097 l=s.split(' ') 1098 ss=l[0] 1099 _subj=[] 1100 if ss[0]=='(': 1101 while l: 1102 _subj.append(ss) 1103 l=l[1:] 1104 if ss[-1]==')': 1105 break 1106 if l: 1107 ss=l[0] 1108 if l: 1109 return (' '.join(_subj), ' '.join(l)) 1110 else: 1111 return ('', ' '.join(_subj)) 1112 except: 1113 return ('', s)
1114
1115 #------------------------------------------------------------------------------- 1116 -class SMS_Sent_List(SMS_Generic_List):
1117 _max_entries=100 1118 _valid_range=xrange(_max_entries) 1119 _field_num=5 1120 _datetime_index=1 1121 _to_index=2 1122 _from_index=3 1123 _text_index=4
1124 - def __init__(self, phone):
1125 super(SMS_Sent_List, self).__init__(phone)
1126 - def read(self):
1127 for i in self._valid_range: 1128 self._phone.progress(i, self._max_entries, 1129 'Reading SMS Sent Entry '+str(i)) 1130 s=self._phone.get_sms_sent(i) 1131 if len(s)==self._field_num: 1132 e=sms.SMSEntry() 1133 e.folder=e.Folder_Sent 1134 e.datetime=s[self._datetime_index] 1135 e._to=s[self._to_index] 1136 e._from=s[self._from_index] 1137 e.text=unicode(s[self._text_index], errors='ignore') 1138 self._data[e.id]=e
1139
1140 #------------------------------------------------------------------------------- 1141 -class SMSList(object):
1142 - def __init__(self, phone):
1143 self._phone=phone 1144 self._inbox=SMS_Inbox_List(phone) 1145 self._saved=SMS_Saved_List(phone) 1146 self._sent=SMS_Sent_List(phone) 1147 self._data={}
1148 - def get(self):
1149 return self._data.copy()
1150 - def read(self):
1151 self._inbox.read() 1152 self._data.update(self._inbox.get()) 1153 self._saved.read() 1154 self._data.update(self._saved.get()) 1155 self._sent.read() 1156 self._data.update(self._sent.get())
1157
1158 #------------------------------------------------------------------------------- 1159 -class CannedMsgList(SMS_Generic_List):
1160 _max_entries=20 1161 _valid_range=xrange(_max_entries) 1162 _field_num=4 1163 _text_index=3 1164 _data_key='canned_msg' 1165 _max_write_fields=3 1166 _count_index=0 1167 _timestamp_index=1 1168 _write_text_index=2
1169 - def __init__(self, phone, data={}):
1170 super(CannedMsgList, self).__init__(phone) 1171 self._data=data
1172 - def read(self):
1173 msg_list=[] 1174 for i in self._valid_range: 1175 self._phone.progress(i, self._max_entries, 1176 'Reading SMS Canned Msg '+str(i)) 1177 s=self._phone.get_canned_msg(i) 1178 if len(s)==self._field_num: 1179 msg_list.append({'text': s[self._text_index], 1180 'type': sms.CannedMsgEntry.user_type }) 1181 self._data=msg_list
1182 - def get(self):
1183 return copy.deepcopy(self._data, _nil=[])
1184 - def validate(self):
1185 pass
1186 - def write(self):
1187 msg_lst=[x['text'] for x in self._data if x['type']==sms.CannedMsgEntry.user_type] 1188 k=None 1189 for k,n in enumerate(msg_lst): 1190 if k>=self._max_entries: 1191 # enough of that 1192 break 1193 n=n.replace('"', '') 1194 self._phone.progress(k, self._max_entries, 1195 'Writing SMS Canned Msg '+str(k)) 1196 s=`k`+','+self._phone.get_time_stamp()+',"'+n+'"' 1197 if not self._phone.save_canned_msg(s): 1198 self._phone.log('Failed to write SMS Canned Msg entry: '+str(k)) 1199 if k is None: 1200 k=0 1201 else: 1202 k+=1 1203 for i in xrange(k, self._max_entries): 1204 self._phone.progress(i, self._max_entries, 1205 'Deleting SMS Canned Msg entry: '+str(i)) 1206 self._phone.save_canned_msg(`i`)
1207 1208 #------------------------------------------------------------------------------- 1209