0001 ### BITPIM 0002 ### 0003 ### Copyright (C) 2004 Joe Pham <djpham@netzero.com> 0004 ### Copyright (C) 2004-2006 Stephen Wood <saw@bitpim.org> 0005 ### 0006 ### This program is free software; you can redistribute it and/or modify 0007 ### it under the terms of the BitPim license as detailed in the LICENSE file. 0008 ### 0009 ### $Id: com_samsung_packet.py 4470 2007-11-28 04:27:52Z djpham $ 0010 0011 """Communicate with a Samsung SCH-Axx phone using AT commands""" 0012 0013 # standard modules 0014 import time 0015 import re 0016 import datetime 0017 0018 # BitPim modules 0019 import bpcalendar 0020 import p_brew 0021 import com_brew 0022 import com_phone 0023 import prototypes 0024 import common 0025 import commport 0026 import todo 0027 import memo 0028 0029 class Phone(com_phone.Phone, com_brew.BrewProtocol): 0030 "Talk to a Samsung phone using AT commands" 0031 0032 desc="Samsung SPH-Axx phone" 0033 0034 MODEPHONEBOOK="modephonebook" 0035 0036 __read_timeout=0.1 0037 # Calendar class vars 0038 # if your phone does not support and end-datetime, set this to a default 0039 # value such as 19800106T000000 0040 # if it does support end-datetime, set this to None 0041 __cal_end_datetime_value=None 0042 __cal_alarm_values={0: 10, 1: 30, 2: 60, 3: -1, 4: 0 } 0043 __cal_max_name_len=32 0044 _cal_max_events_per_day=9 0045 0046 builtinringtones=() 0047 0048 builtinimages=() 0049 0050 def __init__(self, logtarget, commport): 0051 "Call all the contructors and sets initial modes" 0052 com_phone.Phone.__init__(self, logtarget, commport) 0053 com_brew.BrewProtocol.__init__(self) 0054 self.mode=self.MODENONE 0055 0056 def _setmodephonebooktobrew(self): 0057 self.log("_setmodephonebooktobrew") 0058 self.setmode(self.MODEMODEM) 0059 self.setmode(self.MODEBREW) 0060 return True 0061 0062 def _setmodemodemtobrew(self): 0063 self.log("_setmodemodemtobrew") 0064 self.log('Switching from modem to BREW') 0065 try: 0066 self.comm.sendatcommand('$QCDMG') 0067 return True 0068 except commport.ATError: 0069 return False 0070 0071 def _setmodebrewtomodem(self): 0072 self.log("_setmodebrewtomodem") 0073 self.log('Switching from BREW to modem') 0074 try: 0075 self.modemmoderequest() 0076 self.mode=self.MODEMODEM 0077 return True 0078 except: 0079 pass 0080 # give it a 2nd try 0081 try: 0082 self.modemmoderequest() 0083 self.mode=self.MODEMODEM 0084 return True 0085 except: 0086 return False 0087 0088 def _setmodemodemtophonebook(self): 0089 self.log("_setmodemodemtophonebook") 0090 self.log('Switching from modem to phonebook') 0091 response=self.comm.sendatcommand("#PMODE=1") 0092 return True 0093 0094 def _setmodemodem(self): 0095 self.log("_setmodemodem") 0096 req=p_brew.memoryconfigrequest() 0097 respc=p_brew.memoryconfigresponse 0098 0099 # Just try waking phone up first 0100 try: 0101 self.comm.sendatcommand("Z") 0102 self.comm.sendatcommand('E0V1') 0103 return True 0104 except: 0105 pass 0106 0107 # Now check to see if in diagnostic mode 0108 for baud in 0, 38400,115200: 0109 if baud: 0110 if not self.comm.setbaudrate(baud): 0111 continue 0112 try: 0113 self.sendbrewcommand(req, respc, callsetmode=False) 0114 self.log('In BREW mode, trying to switch to Modem mode') 0115 # Infinite loop 0116 if self._setmodebrewtomodem(): 0117 break 0118 return False 0119 except com_brew.modeignoreerrortypes: 0120 pass 0121 0122 # Should be in modem mode. Wake up the interface 0123 for baud in (0, 115200, 19200, 230400): 0124 self.log("Baud="+`baud`) 0125 if baud: 0126 if not self.comm.setbaudrate(baud): 0127 continue 0128 0129 try: 0130 self.comm.sendatcommand("Z") 0131 self.comm.sendatcommand('E0V1') 0132 return True 0133 except: 0134 pass 0135 0136 return False 0137 0138 def _setmodephonebook(self): 0139 self.log("_setmodephonebook") 0140 self.setmode(self.MODEMODEM) 0141 self.setmode(self.MODEPHONEBOOK) 0142 return True 0143 0144 def _setmodephonebooktomodem(self): 0145 self.log("_setmodephonebooktomodem") 0146 self.log('Switching from phonebook to modem') 0147 response=self.comm.sendatcommand("#PMODE=0") 0148 return True 0149 0150 def sendpbcommand(self, request, responseclass, ignoreerror=False, fixup=None): 0151 """Similar to the sendpbcommand in com_sanyo and com_lg, except that 0152 a list of responses is returned, one per line of information returned 0153 from the phone""" 0154 0155 buffer=prototypes.buffer() 0156 0157 request.writetobuffer(buffer, logtitle="Samsung phonebook request") 0158 data=buffer.getvalue() 0159 0160 try: 0161 response_lines=self.comm.sendatcommand(data, ignoreerror=ignoreerror) 0162 except commport.ATError: 0163 self.comm.success=False 0164 self.mode=self.MODENONE 0165 self.raisecommsdnaexception("manipulating the phonebook") 0166 0167 self.comm.success=True 0168 0169 reslist=[] 0170 for line in response_lines: 0171 if fixup: 0172 line=fixup(line) 0173 res=responseclass() 0174 buffer=prototypes.buffer(line) 0175 res.readfrombuffer(buffer, logtitle="Samsung phonebook response") 0176 reslist.append(res) 0177 0178 return reslist 0179 0180 def get_esn(self): 0181 req=self.protocolclass.esnrequest() 0182 res=self.sendpbcommand(req, self.protocolclass.esnresponse) 0183 try: 0184 return res[0].esn 0185 except: 0186 pass 0187 return '' 0188 def get_model(self): 0189 req=self.protocolclass.modelreq() 0190 res=self.sendpbcommand(req, self.protocolclass.modelresp) 0191 try: 0192 return res[0].model 0193 except: 0194 return '' 0195 def get_manufacturer(self): 0196 req=self.protocolclass.manufacturerreq() 0197 res=self.sendpbcommand(req, self.protocolclass.manufacturerresp) 0198 try: 0199 return res[0].manufacturer 0200 except: 0201 return '' 0202 def get_battery_level(self): 0203 req=self.protocolclass.batterylevelreq() 0204 res=self.sendpbcommand(req, self.protocolclass.batterylevelresp) 0205 try: 0206 return res[0].levelstr 0207 except: 0208 return '' 0209 def read_groups(self): 0210 0211 g={} 0212 # Don't crash if phone doesn't accept #PMODE=1 (Canadian phones) 0213 try: 0214 self.setmode(self.MODEPHONEBOOK) 0215 except: 0216 return g 0217 req=self.protocolclass.groupnamerequest() 0218 for i in range(self.protocolclass.NUMGROUPS+1): 0219 req.gid=i 0220 # Don't crash if phone doesn't support groups 0221 try: 0222 res=self.sendpbcommand(req, self.protocolclass.groupnameresponse) 0223 except: 0224 return g 0225 g[i]={'name': res[0].entry.groupname} 0226 return g 0227 0228 def savegroups(self, data): 0229 """Write the groups, sending only those groups that have had 0230 a name change. (So that ringers don't get messed up)""" 0231 groups=data['groups'] 0232 0233 groups_onphone=self.read_groups() # Get groups on phone 0234 0235 # If groups read doesn't work, don't try to write groups 0236 if not groups_onphone: 0237 return 0238 0239 keys=groups.keys() 0240 keys.sort() 0241 0242 for k in keys: 0243 if groups[k]['name']!=groups_onphone[k]['name']: 0244 if groups[k]['name']!="Unassigned": 0245 req=self.protocolclass.groupnamesetrequest() 0246 req.gid=k 0247 req.groupname=groups[k]['name'] 0248 # Response will have ERROR, even though it works 0249 self.sendpbcommand(req, self.protocolclass.unparsedresponse, ignoreerror=True) 0250 0251 def pblinerepair(self, line): 0252 "Repair a line from a phone with broken firmware" 0253 return line 0254 0255 def getphonebook(self, result): 0256 """Read the phonebook data.""" 0257 pbook={} 0258 self.setmode(self.MODEPHONEBOOK) 0259 0260 count=0 0261 req=self.protocolclass.phonebookslotrequest() 0262 lastname="" 0263 for slot in range(1,self.protocolclass.NUMPHONEBOOKENTRIES+1): 0264 req.slot=slot 0265 res=self.sendpbcommand(req, self.protocolclass.phonebookslotresponse, fixup=self.pblinerepair) 0266 if len(res) > 0: 0267 lastname=res[0].entry.name 0268 self.log(`slot`+": "+lastname) 0269 entry=self.extractphonebookentry(res[0].entry, result) 0270 pbook[count]=entry 0271 count+=1 0272 else: 0273 lastname="" 0274 self.progress(slot, self.protocolclass.NUMPHONEBOOKENTRIES, 0275 'Reading entry %(slot)d: %(name)s'%{ 'slot': slot, 0276 'name': lastname }) 0277 0278 result['phonebook']=pbook 0279 cats=[] 0280 for i in result['groups']: 0281 if result['groups'][i]['name']!='Unassigned': 0282 cats.append(result['groups'][i]['name']) 0283 result['categories']=cats 0284 print "returning keys",result.keys() 0285 0286 return pbook 0287 0288 def _extractphonebook_numbers(self, entry, fundamentals, res): 0289 """Extract and build phone numbers""" 0290 res['numbers']=[] 0291 secret=0 0292 0293 speeddialtype=entry.speeddial 0294 numberindex=0 0295 for type in self.numbertypetab: 0296 if len(entry.numbers[numberindex].number): 0297 numhash={'number': entry.numbers[numberindex].number, 'type': type } 0298 if entry.numbers[numberindex].secret==1: 0299 secret=1 0300 if speeddialtype==numberindex: 0301 numhash['speeddial']=entry.uslot 0302 res['numbers'].append(numhash) 0303 0304 numberindex+=1 0305 0306 # Field after each number is secret flag. Setting secret on 0307 # phone sets secret flag for every defined phone number 0308 res['flags']=[ {'secret': secret} ] 0309 def _extractphonebook_ringtone(self, entry, fundamentals, res): 0310 """Extract ringtone info""" 0311 if entry.ringtone != self.protocolclass.DEFAULT_RINGTONE: 0312 tone=self.serialsname+"Index_"+`entry.ringtone` 0313 res['ringtones']=[{'ringtone': tone, 'use': 'call'}] 0314 def _extractphonebook_wallpaper(self, entry, fundamentals, res): 0315 """Extract wallpaper info""" 0316 try: 0317 if entry.wallpaper != self.protocolclass.DEFAULT_WALLPAPER: 0318 tone=self.serialsname+"Index_"+`entry.wallpaper` 0319 res['wallpapers']=[{'wallpaper': tone, 'use': 'call'}] 0320 except: 0321 pass 0322 0323 def extractphonebookentry(self, entry, fundamentals): 0324 res={} 0325 0326 res['serials']=[ {'sourcetype': self.serialsname, 0327 'slot': entry.slot, 0328 'sourceuniqueid': fundamentals['uniqueserial']} ] 0329 # only one name 0330 res['names']=[ {'full': entry.name} ] 0331 # only one category 0332 cat=fundamentals['groups'].get(entry.group, {'name': "Unassigned"})['name'] 0333 if cat!="Unassigned": 0334 res['categories']=[ {'category': cat} ] 0335 # only one email 0336 if len(entry.email): 0337 res['emails']=[ {'email': entry.email} ] 0338 # only one url 0339 if len(entry.url): 0340 res['urls']=[ {'url': entry.url} ] 0341 # separate the following processing into methods so subclass can 0342 # customize them 0343 self._extractphonebook_numbers(entry, fundamentals, res) 0344 self._extractphonebook_ringtone(entry, fundamentals, res) 0345 self._extractphonebook_wallpaper(entry, fundamentals, res) 0346 0347 # We don't have a place to put these 0348 # print entry.name, entry.birthday 0349 # print entry.name, entry.timestamp 0350 0351 return res 0352 0353 def savephonebook(self, data): 0354 "Saves out the phonebook" 0355 0356 pb=data['phonebook'] 0357 keys=pb.keys() 0358 keys.sort() 0359 keys=keys[:self.protocolclass.NUMPHONEBOOKENTRIES] 0360 0361 # 0362 # Read the existing phonebook so that we cache birthdays 0363 # Erase all entries, being carefull to modify entries with 0364 # with URL's first 0365 # 0366 uslots={} 0367 names={} 0368 birthdays={} 0369 req=self.protocolclass.phonebookslotrequest() 0370 0371 self.log('Erasing '+self.desc+' phonebook') 0372 progressmax=self.protocolclass.NUMPHONEBOOKENTRIES+len(keys) 0373 for slot in range(1,self.protocolclass.NUMPHONEBOOKENTRIES+1): 0374 req.slot=slot 0375 self.progress(slot,progressmax,"Erasing "+`slot`) 0376 try: 0377 res=self.sendpbcommand(req,self.protocolclass.phonebookslotresponse, fixup=self.pblinerepair) 0378 if len(res) > 0: 0379 names[slot]=res[0].entry.name 0380 birthdays[slot]=res[0].entry.birthday 0381 if len(res[0].entry.url)>0: 0382 reqhack=self.protocolclass.phonebookslotupdaterequest() 0383 reqhack.entry=res[0].entry 0384 reqhack.entry.url="" 0385 reqhack.entry.ringtone=self.protocolclass.DEFAULT_RINGTONE 0386 reqhack.entry.wallpaper=self.protocolclass.DEFAULT_WALLPAPER 0387 reqhack.entry.timestamp=[1900,1,1,0,0,0] 0388 self.sendpbcommand(reqhack, self.protocolclass.phonebookslotupdateresponse) 0389 else: 0390 names[slot]="" 0391 except: 0392 names[slot]="" 0393 self.log("Slot "+`slot`+" read failed") 0394 reqerase=self.protocolclass.phonebooksloterase() 0395 reqerase.slot=slot 0396 self.sendpbcommand(reqerase, self.protocolclass.phonebookslotupdateresponse) 0397 0398 self.savegroups(data) 0399 0400 for i in range(len(keys)): 0401 slot=keys[i] 0402 req=self.protocolclass.phonebookslotupdaterequest() 0403 req.entry=self.makeentry(pb[slot],data) 0404 if names[slot]==req.entry.name: 0405 req.entry.birthday=birthdays[slot] 0406 self.log('Writing entry '+`slot`+" - "+req.entry.name) 0407 self.progress(i+self.protocolclass.NUMPHONEBOOKENTRIES,progressmax,"Writing "+req.entry.name) 0408 self.sendpbcommand(req, self.protocolclass.phonebookslotupdateresponse) 0409 self.progress(progressmax+1,progressmax+1, "Phone book write completed") 0410 return data 0411 0412 def makeentry(self, entry, data): 0413 e=self.protocolclass.pbentry() 0414 0415 for k in entry: 0416 # special treatment for lists 0417 if k=='numbertypes' or k=='secrets': 0418 continue 0419 if k=='ringtone': 0420 # e.ringtone=self._findmediaindex(data['ringtone-index'], entry['ringtone'], entry['name'], 'ringtone') 0421 continue 0422 elif k=='wallpaper': 0423 # e.wallpaper=self._findmediaindex(data['wallpaper-index'], entry['wallpaper'], entry['name'], 'wallpaper') 0424 continue 0425 elif k=='numbers': 0426 #l=getattr(e,k) 0427 for numberindex in range(self.protocolclass.NUMPHONENUMBERS): 0428 enpn=self.protocolclass.phonenumber() 0429 # l.append(enpn) 0430 e.numbers.append(enpn) 0431 for i in range(len(entry[k])): 0432 numberindex=entry['numbertypes'][i] 0433 e.numbers[numberindex].number=entry[k][i] 0434 e.numbers[numberindex].secret=entry['secrets'][i] 0435 continue 0436 # everything else we just set 0437 setattr(e, k, entry[k]) 0438 e.ringtone=self.protocolclass.DEFAULT_RINGTONE 0439 e.wallpaper=self.protocolclass.DEFAULT_WALLPAPER 0440 return e 0441 0442 def getcalendar(self, result): 0443 entries = {} 0444 self.log("Getting calendar entries") 0445 self.setmode(self.MODEPHONEBOOK) 0446 req=self.protocolclass.eventrequest() 0447 cal_cnt=0 0448 for slot in range(self.protocolclass.NUMCALENDAREVENTS): 0449 req.slot=slot 0450 res=self.sendpbcommand(req,self.protocolclass.eventresponse) 0451 if len(res) > 0: 0452 self.progress(slot+1, self.protocolclass.NUMCALENDAREVENTS, 0453 res[0].eventname) 0454 0455 # build a calendar entry 0456 entry=bpcalendar.CalendarEntry() 0457 0458 # start time date 0459 entry.start=res[0].start[0:5] 0460 0461 if res[0].end: 0462 # valid end time 0463 entry.end=res[0].end[0:5] 0464 else: 0465 entry.end=entry.start 0466 0467 # description[location] 0468 entry.desc_loc=res[0].eventname 0469 0470 try: 0471 alarm=self.__cal_alarm_values[res[0].alarm] 0472 except: 0473 alarm=None 0474 entry.alarm=alarm 0475 0476 # update calendar dict 0477 entries[entry.id]=entry 0478 cal_cnt += 1 0479 0480 result['calendar']=entries 0481 self.setmode(self.MODEMODEM) 0482 return result 0483 0484 def _set_unused_calendar_fields(self, entry): 0485 entry['repeat']=None 0486 entry['changeserial']=1 0487 entry['snoozedelay']=0 0488 entry['daybitmap']=0 0489 entry['ringtone']=0 0490 0491 def process_calendar(self, dict): 0492 """ Optimize and expand calendar data suitable for phone download 0493 """ 0494 # first go thru the dict to organize events by date 0495 # and also determine the latest event date 0496 r={} 0497 rp=[] 0498 today=datetime.date.today() 0499 last_date=today 0500 if __debug__: 0501 print 'original calendar:' 0502 for k,e in dict.items(): 0503 if __debug__: 0504 print e.description,':',e.start 0505 sd=datetime.date(*e.start[:3]) 0506 ed=datetime.date(*e.end[:3]) 0507 if ed>last_date: 0508 last_date=ed 0509 if e.repeat is None: 0510 if sd>=today: 0511 r.setdefault(e.start[:3], []).append(Samsung_Calendar(e)) 0512 else: 0513 if ed>=today: 0514 rp.append(e) 0515 # go through and expand on the repeated events 0516 delta_1=datetime.timedelta(1) 0517 for n in rp: 0518 current_date=today 0519 end_date=datetime.date(*n.end[:3]) 0520 cnt=0 0521 while current_date<=end_date: 0522 if n.is_active(current_date.year, current_date.month, 0523 current_date.day): 0524 cd_l=(current_date.year, current_date.month, 0525 current_date.day) 0526 r.setdefault(cd_l, []).append(\ 0527 Samsung_Calendar(n, cd_l)) 0528 cnt+=1 0529 if cnt>self.protocolclass.NUMCALENDAREVENTS: 0530 # enough for this one, breaking out 0531 break 0532 current_date+=delta_1 0533 # and put them all into a list 0534 res=[] 0535 keys=r.keys() 0536 # sort by date 0537 keys.sort() 0538 for k in keys: 0539 # sort by time within this date 0540 r[k].sort() 0541 # clip by max events/day 0542 if len(r[k])>self._cal_max_events_per_day: 0543 res+=r[k][:self._cal_max_events_per_day] 0544 else: 0545 res+=r[k] 0546 # clip by max events 0547 if len(res)>self.protocolclass.NUMCALENDAREVENTS: 0548 res=res[:self.protocolclass.NUMCALENDAREVENTS] 0549 return res 0550 0551 def savecalendar(self, dict, merge): 0552 0553 self.log("Sending calendar entries") 0554 0555 cal=self.process_calendar(dict['calendar']) 0556 # testing 0557 if __debug__: 0558 print 'processed calendar: ', len(cal), ' items' 0559 for c in cal: 0560 print c.description,':', c.start 0561 0562 self.setmode(self.MODEPHONEBOOK) 0563 self.log("Saving calendar entries") 0564 cal_cnt=0 0565 req=self.protocolclass.eventupdaterequest() 0566 l = self.protocolclass.NUMCALENDAREVENTS 0567 for c in cal: 0568 # Save this entry to phone 0569 # self.log('Item %d' %k) 0570 0571 # pos 0572 req.slot=cal_cnt 0573 0574 # start date time 0575 #print "Start ",c.start 0576 req.start=list(c.start)+[0] 0577 0578 # end date time 0579 if self.__cal_end_datetime_value is None: 0580 # valid end-datetime 0581 req.end=list(c.end)+[0] 0582 #print "End ",c.end 0583 else: 0584 # no end-datetime, set to start-datetime 0585 req.end=req.start 0586 0587 # time stamp 0588 req.timestamp=list(time.localtime(time.time())[0:6]) 0589 0590 #print "Alarm ",c.alarm 0591 req.alarm=c.alarm 0592 0593 # Name, check for bad char & proper length 0594 #name=c.description.replace('"', '') 0595 name=c.desc_loc 0596 if len(name)>self.__cal_max_name_len: 0597 name=name[:self.__cal_max_name_len] 0598 req.eventname=name 0599 0600 # and save it 0601 self.progress(cal_cnt+1, l, "Updating "+name) 0602 self.sendpbcommand(req,self.protocolclass.eventupdateresponse) 0603 cal_cnt += 1 0604 0605 # delete the rest of the calendar slots 0606 self.log('Deleting unused entries') 0607 for k in range(cal_cnt, l): 0608 self.progress(k, l, "Deleting entry %d" % k) 0609 reqerase=self.protocolclass.eventsloterase() 0610 reqerase.slot=k 0611 self.sendpbcommand(reqerase, self.protocolclass.eventupdateresponse) 0612 self.setmode(self.MODEMODEM) 0613 0614 return dict 0615 0616 def gettodo(self, result): 0617 todos = {} 0618 self.log("Getting todo entries") 0619 self.setmode(self.MODEPHONEBOOK) 0620 req=self.protocolclass.todorequest() 0621 for slot in range(self.protocolclass.NUMTODOENTRIES): 0622 req.slot=slot 0623 res=self.sendpbcommand(req,self.protocolclass.todoresponse) 0624 if len(res) > 0: 0625 entry = todo.TodoEntry() 0626 entry.summary=res[0].subject 0627 # Convert back to formatted date string 0628 # Shouldn't todo take dates as a list like 0629 # other modules do? 0630 entry.due_date='%4.4d%2.2d%2.2d'%(res[0].duedate[0],res[0].duedate[1],res[0].duedate[2]) 0631 if res[0].priority: 0632 entry.priority=1 0633 else: 0634 entry.priority=10 0635 0636 self.log("Todo "+`slot`+" "+entry.summary+" "+entry.due_date) 0637 todos[entry.id]=entry 0638 0639 result['todo']=todos 0640 return result 0641 0642 def savetodo(self, dict, merge): 0643 self.setmode(self.MODEPHONEBOOK) 0644 todos=dict.get('todo', {}) 0645 #todos=dict['todo'] 0646 todos_len=len(todos) 0647 l=self.protocolclass.NUMTODOENTRIES 0648 if todos_len > l: 0649 self.log("The number of Todo entries (%d) exceeded the mamximum (%d)" % (cal_len, l)) 0650 self.setmode(self.MODEPHONEBOOK) 0651 self.log("Saving todo entries") 0652 todo_cnt=0 0653 req=self.protocolclass.todoupdaterequest() 0654 for k in todos: 0655 todo=todos[k] 0656 print todo.__doc__ 0657 if todo_cnt >= l: 0658 break 0659 0660 req.slot=todo_cnt 0661 if todo.priority is not None and todo.priority<5: 0662 req.priority=1 0663 else: 0664 req.priority=0 0665 0666 dd=todo.due_date 0667 req.duedate=(int(dd[:4]),int(dd[4:6]),int(dd[6:10]),0,0,0) 0668 req.timestamp=list(time.localtime(time.time())[0:6]) 0669 req.subject=todo.summary 0670 self.sendpbcommand(req,self.protocolclass.todoupdateresponse) 0671 todo_cnt += 1 0672 0673 req=self.protocolclass.todoerase() 0674 for slot in range(todo_cnt, self.protocolclass.NUMTODOENTRIES): 0675 req.slot=slot 0676 self.sendpbcommand(req,self.protocolclass.todoupdateresponse) 0677 0678 def getmemo(self, result): 0679 memos = {} 0680 self.log("Getting memo entries") 0681 self.setmode(self.MODEPHONEBOOK) 0682 req=self.protocolclass.memorequest() 0683 for slot in range(self.protocolclass.NUMMEMOENTRIES): 0684 req.slot=slot 0685 res=self.sendpbcommand(req,self.protocolclass.memoresponse) 0686 if len(res) > 0: 0687 entry=memo.MemoEntry() 0688 entry.text=res[0].text 0689 entry.set_date_isostr='%4.4d%2.2d%2.2dT%2.2d%2.2d%2.2d'%(res[0].timestamp[0],res[0].timestamp[1],res[0].timestamp[2],res[0].timestamp[3],res[0].timestamp[4],res[0].timestamp[5]) 0690 memos[entry.id]=entry 0691 0692 result['memo']=memos 0693 return result 0694 0695 def savememo(self, dict, merge): 0696 self.setmode(self.MODEPHONEBOOK) 0697 memos=dict.get('memo', {}) 0698 memos_len=len(memos) 0699 l=self.protocolclass.NUMMEMOENTRIES 0700 if memos_len > l: 0701 self.log("The number of Memo entries (%d) exceeded the mamximum (%d)" % (cal_len, l)) 0702 self.setmode(self.MODEPHONEBOOK) 0703 self.log("Saving memo entries") 0704 memo_cnt=0 0705 req=self.protocolclass.memoupdaterequest() 0706 for k in memos: 0707 memo=memos[k] 0708 if memo_cnt >= l: 0709 break 0710 0711 dd=memo.set_date_isostr 0712 req.timestamp=list(time.localtime(time.time())[0:6]) 0713 req.text=memo.text 0714 req.slot=memo_cnt 0715 self.sendpbcommand(req,self.protocolclass.memoupdateresponse) 0716 memo_cnt += 1 0717 0718 req=self.protocolclass.memoerase() 0719 for slot in range(memo_cnt, self.protocolclass.NUMMEMOENTRIES): 0720 req.slot=slot 0721 self.sendpbcommand(req,self.protocolclass.memoupdateresponse) 0722 0723 # return some basic info about this phone 0724 def getbasicinfo(self, phoneinfo): 0725 self.log('Getting Basic Phone Info') 0726 for _key,_ in phoneinfo.standard_keys: 0727 _val=getattr(self, 'get_'+_key, 0728 lambda *_: '')() 0729 if _val: 0730 setattr(phoneinfo, _key, _val) 0731 getphoneinfo=getbasicinfo 0732 getcallhistory=None 0733 0734 class Profile(com_phone.Profile): 0735 0736 BP_Calendar_Version=3 0737 0738 usbids=( ( 0x04e8, 0x6601, 1), # Samsung internal USB interface 0739 ) 0740 0741 # which device classes we are. 0742 deviceclasses=("modem","serial") 0743 WALLPAPER_WIDTH=128 0744 WALLPAPER_HEIGHT=118 0745 OVERSIZE_PERCENTAGE=100 0746 MAX_WALLPAPER_BASENAME_LENGTH=19 0747 WALLPAPER_FILENAME_CHARS="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .`~!@#$%^&()-_=+[{]};\'" 0748 WALLPAPER_CONVERT_FORMAT="png" 0749 0750 MAX_RINGTONE_BASENAME_LENGTH=19 0751 RINGTONE_FILENAME_CHARS="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .`~!@#$%^&()-_=+[{]};\'" 0752 0753 _supportedsyncs=() 0754 0755 def __init__(self): 0756 com_phone.Profile.__init__(self) 0757 0758 def _getgroup(self, name, groups): 0759 for key in groups: 0760 if groups[key]['name']==name: 0761 return key,groups[key] 0762 return None,None 0763 0764 0765 def normalisegroups(self, helper, data): 0766 "Assigns groups based on category data" 0767 0768 pad=[] 0769 keys=data['groups'].keys() 0770 keys.sort() 0771 for k in keys: 0772 if k==self.protocolclass.NUMGROUPS: # ignore key 4 which is 'Unassigned' 0773 name=data['groups'][k]['name'] 0774 pad.append(name) 0775 0776 groups=helper.getmostpopularcategories(self.protocolclass.NUMGROUPS, data['phonebook'], ["Unassigned"], 12, pad) 0777 0778 # alpha sort 0779 groups.sort() 0780 0781 # newgroups 0782 newgroups={} 0783 0784 # Unassigned in 5th group 0785 newgroups[self.protocolclass.NUMGROUPS]={'name': 'Unassigned'} 0786 0787 # populate 0788 for name in groups: 0789 # existing entries keep same key 0790 if name=="Unassigned": continue 0791 key,value=self._getgroup(name, data['groups']) 0792 if key is not None: 0793 newgroups[key]=value 0794 # new entries get whatever numbers are free 0795 for name in groups: 0796 key,value=self._getgroup(name, newgroups) 0797 if key is None: 0798 for key in range(self.protocolclass.NUMGROUPS): 0799 if key not in newgroups: 0800 newgroups[key]={'name': name, 'icon': 1} 0801 break 0802 0803 # yay, done 0804 if data['groups']!=newgroups: 0805 data['groups']=newgroups 0806 0807 def convertphonebooktophone(self, helper, data): 0808 """Converts the data to what will be used by the phone 0809 0810 @param data: contains the dict returned by getfundamentals 0811 as well as where the results go""" 0812 0813 self.normalisegroups(helper, data) 0814 results={} 0815 0816 # find which entries are already known to this phone 0817 pb=data['phonebook'] 0818 # decorate list with (slot, pbkey) tuples 0819 slots=[ (helper.getserial(pb[pbentry].get("serials", []), self.serialsname, data['uniqueserial'], "slot", None), pbentry) 0820 for pbentry in pb] 0821 slots.sort() # numeric order 0822 # make two lists - one contains known slots, one doesn't 0823 newones=[(pbentry,slot) for slot,pbentry in slots if slot is None] 0824 existing=[(pbentry,slot) for slot,pbentry in slots if slot is not None] 0825 0826 uslotsused={} 0827 0828 tempslot=0 # Temporarily just pick slots and speed dial in order 0829 for pbentry,slot in existing+newones: 0830 0831 if len(results)==self.protocolclass.NUMPHONEBOOKENTRIES: 0832 break 0833 0834 try: 0835 0836 e={} # entry out 0837 0838 entry=data['phonebook'][pbentry] 0839 0840 secret=helper.getflag(entry.get('flags', []), 'secret', False) 0841 if secret: 0842 secret=1 0843 else: 0844 secret=0 0845 0846 # name 0847 e['name']=helper.getfullname(entry.get('names', []),1,1,20)[0] 0848 0849 cat=helper.makeone(helper.getcategory(entry.get('categories',[]),0,1,12), None) 0850 if cat is None: 0851 e['group']=self.protocolclass.NUMGROUPS # Unassigned group 0852 else: 0853 key,value=self._getgroup(cat, data['groups']) 0854 if key is not None: 0855 e['group']=key 0856 else: 0857 # Sorry no space for this category 0858 e['group']=self.protocolclass.NUMGROUPS # Unassigned 0859 0860 # email addresses 0861 e['email']=helper.makeone(helper.getemails(entry.get('emails', []), 0,1,32), "") 0862 # url 0863 e['url']=helper.makeone(helper.geturls(entry.get('urls', []), 0,1,32), "") 0864 0865 # phone numbers 0866 # there must be at least one phone number 0867 minnumbers=1 0868 numbers=helper.getnumbers(entry.get('numbers', []),minnumbers,self.protocolclass.NUMPHONENUMBERS) 0869 e['numbertypes']=[] 0870 e['numbers']=[] 0871 e['secrets']=[] 0872 unusednumbers=[] # Hold duplicate types here 0873 typesused={} 0874 defaulttypenum=0 0875 for num in numbers: 0876 typename=num['type'] 0877 if typesused.has_key(typename): 0878 unusednumbers.append(num) 0879 continue 0880 typesused[typename]=1 0881 for typenum,tnsearch in enumerate(self.numbertypetab): 0882 if typename==tnsearch: 0883 if defaulttypenum==0: 0884 defaulttypenum=typenum 0885 number=self.phonize(num['number']) 0886 if len(number)>self.protocolclass.MAXNUMBERLEN: 0887 # :: TODO:: number is too long and we have to either truncate it or ignore it? 0888 number=number[:self.protocolclass.MAXNUMBERLEN] 0889 e['numbers'].append(number) 0890 if(num.has_key('speeddial')): 0891 # Only one number per name can be a speed dial 0892 # Should make speed dial be the first that 0893 # we come accross 0894 e['speeddial']=typenum 0895 tryuslot = num['speeddial'] 0896 e['numbertypes'].append(typenum) 0897 e['secrets'].append(secret) 0898 0899 break 0900 0901 # Should print to log when a requested speed dial slot is 0902 # not available 0903 if e.has_key('speeddial'): 0904 if tryuslot>=1 and tryuslot<=self.protocolclass.NUMPHONEBOOKENTRIES and not uslotsused.has_key(tryuslot): 0905 uslotsused[tryuslot]=1 0906 e['uslot']=tryuslot 0907 else: 0908 e['speeddial']=defaulttypenum 0909 0910 e['ringtone']=helper.getringtone(entry.get('ringtones', []), 'call', None) 0911 e['wallpaper']=helper.getwallpaper(entry.get('wallpapers', []), 'call', None) 0912 0913 # find the right slot 0914 if slot is None or slot<1 or slot>self.protocolclass.NUMPHONEBOOKENTRIES or slot in results: 0915 for i in range(1,100000): 0916 if i not in results: 0917 slot=i 0918 break 0919 0920 e['slot']=slot 0921 0922 e['timestamp']=list(time.localtime(time.time())[0:6]) 0923 0924 results[slot]=e 0925 except helper.ConversionFailed: 0926 continue 0927 0928 # Fill in uslot for entries that don't have it. 0929 0930 tryuslot=1 0931 for slot in results.keys(): 0932 0933 e=results[slot] 0934 if not e.has_key('uslot'): 0935 while tryuslot<self.protocolclass.NUMPHONEBOOKENTRIES and uslotsused.has_key(tryuslot): 0936 tryuslot += 1 0937 uslotsused[tryuslot]=1 0938 e['uslot'] = tryuslot 0939 results[slot] = e 0940 0941 data['phonebook']=results 0942 return data 0943 0944 def phonize(self,str): 0945 """Convert the phone number into something the phone understands 0946 All digits, P, T, * and # are kept, everything else is removed""" 0947 0948 return re.sub("[^0-9PT#*]", "", str)[:self.protocolclass.MAXNUMBERLEN] 0949 0950 class Samsung_Calendar: 0951 _cal_alarm_values={ 0952 10: 0, 30: 1, 60: 2, -1: 3, 0: 4 } 0953 0954 def __init__(self, calendar_entry, new_date=None): 0955 self._start=self._end=self._alarm=self._desc=self._desc_loc=None 0956 self._extract_cal_info(calendar_entry, new_date) 0957 0958 def _extract_cal_info(self, cal_entry, new_date): 0959 s=cal_entry.start 0960 if new_date is not None: 0961 s=new_date[:3]+s[3:] 0962 self._start=s 0963 self._end=cal_entry.end 0964 self._desc=cal_entry.description 0965 self._desc_loc=cal_entry.desc_loc 0966 # approximate the alarm value 0967 self._alarm=0 0968 alarm=cal_entry.alarm 0969 _keys=self._cal_alarm_values.keys() 0970 _keys.sort() 0971 _keys.reverse() 0972 for k in _keys: 0973 if alarm>=k: 0974 self._alarm=self._cal_alarm_values[k] 0975 break 0976 0977 def __lt__(self, rhs): 0978 return self.start<rhs.start 0979 def __le__(self, rhs): 0980 return self.start<=rhs.start 0981 def __eq__(self, rhs): 0982 return self.start==rhs.start 0983 def __ne__(self, rhs): 0984 return self.start!=rhs.start 0985 def __gt__(self, rhs): 0986 return self.start>rhs.start 0987 def __ge__(self, rhs): 0988 return self.start>=rhs.start 0989 0990 def _get_start(self): 0991 return self._start 0992 start=property(fget=_get_start) 0993 0994 def _get_end(self): 0995 return self._end 0996 end=property(fget=_get_end) 0997 0998 def _get_desc(self): 0999 return self._desc 1000 description=property(fget=_get_desc) 1001 1002 def _get_desc_loc(self): 1003 return self._desc_loc 1004 desc_loc=property(fget=_get_desc_loc) 1005 1006 def _get_alarm(self): 1007 return self._alarm 1008 alarm=property(fget=_get_alarm) 1009 1010 1011 1012 1013
Generated by PyXR 0.9.4