PyXR

c:\projects\bitpim\src \ phones \ com_samsungsphn200.py



0001 ### BITPIM
0002 ###
0003 ### Copyright (C) 2005 Stephen Wood <saw@bitpim.org>
0004 ###
0005 ### This program is free software; you can redistribute it and/or modify
0006 ### it under the terms of the BitPim license as detailed in the LICENSE file.
0007 ###
0008 ### $Id: com_samsungsphn200.py 2533 2005-09-23 02:49:11Z sawecw $
0009 
0010 """Communicate with a Samsung SPH-N200"""
0011 
0012 import sha
0013 import re
0014 import struct
0015 
0016 import common
0017 import commport
0018 import time
0019 import p_samsungsphn200
0020 import p_brew
0021 import com_brew
0022 import com_phone
0023 import com_samsung_packet
0024 import prototypes
0025 
0026 numbertypetab=('home','office','cell','pager','fax','none')
0027 
0028 class Phone(com_samsung_packet.Phone):
0029     "Talk to a Samsung SPH-N200 phone"
0030 
0031     desc="SPH-N200"
0032 
0033     protocolclass=p_samsungsphn200
0034     serialsname='sphn200'
0035     __groups_range=xrange(5)
0036 
0037     imagelocations=()
0038         # offset, index file, files location, type, maximumentries
0039     
0040     __ams_index_file="ams/AmsRegistry"
0041 
0042     def __init__(self, logtarget, commport):
0043         com_samsung_packet.Phone.__init__(self, logtarget, commport)
0044         self.numbertypetab=numbertypetab
0045         self.mode=self.MODENONE
0046 
0047     def getfundamentals(self, results):
0048         """Gets information fundamental to interopating with the phone and UI."""
0049 
0050         # use a hash of ESN and other stuff (being paranoid)
0051         self.log("Retrieving fundamental phone information")
0052         self.log("Phone serial number")
0053         print "Calling setmode MODEMODEM"
0054         self.setmode(self.MODEMODEM)
0055         print "Getting serial number"
0056         results['uniqueserial']=sha.new(self.get_esn()).hexdigest()
0057 
0058         self.log("Fundamentals retrieved")
0059         return results
0060 
0061     def _setmodemodem(self):
0062         self.log("_setmodemodem")
0063         
0064         # Just try waking phone up first
0065         try:
0066             self.comm.sendatcommand("Z")
0067             self.comm.sendatcommand('E0V1')
0068             return True
0069         except:
0070             pass
0071 
0072         # Should be in modem mode.  Wake up the interface
0073         for baud in (0, 19200, 38400, 115200):
0074             self.log("Baud="+`baud`)
0075             if baud:
0076                 if not self.comm.setbaudrate(baud):
0077                     continue
0078 
0079             try:
0080                 self.comm.sendatcommand("Z")
0081                 self.comm.sendatcommand('E0V1')
0082                 return True
0083             except:
0084                 pass
0085 
0086         return False
0087 
0088     def getphonebook(self, result):
0089         """Read the phonebook data."""
0090         pbook={}
0091         self.setmode(self.MODEPHONEBOOK)
0092 
0093         count=0
0094         req=self.protocolclass.phonebookslotrequest()
0095         for slot in range(2,self.protocolclass.NUMPHONEBOOKENTRIES+1):
0096             req.slot=slot
0097             res=self.sendpbcommand(req, self.protocolclass.phonebookslotresponse, fixup=self.pblinerepair)
0098             if len(res) > 0:
0099                 lastname=res[0].entry.name
0100                 self.log(`slot`+": "+lastname)
0101                 entry=self.extractphonebookentry(res[0].entry, result)
0102                 pbook[count]=entry
0103                 count+=1
0104             self.progress(slot, self.protocolclass.NUMPHONEBOOKENTRIES, lastname)
0105         result['phonebook']=pbook
0106 
0107         return pbook
0108         
0109     def extractphonebookentry(self, entry, fundamentals):
0110         res={}
0111 
0112         res['serials']=[ {'sourcetype': self.serialsname,
0113                           'slot': entry.slot,
0114                           'sourceuniqueid': fundamentals['uniqueserial']} ]
0115         # only one name
0116         res['names']=[ {'full': entry.name} ]
0117 
0118         res['numbers']=[]
0119         secret=0
0120 
0121         for i in range(len(entry.numbers)):
0122             type = self.numbertypetab[entry.numbers[i].numbertype - 1]
0123             numhash = {'number': entry.numbers[i].number, 'type': type }
0124             res['numbers'].append(numhash)
0125             
0126         # Field after each number is secret flag.  Setting secret on
0127         # phone sets secret flag for every defined phone number
0128         res['flags']=[ {'secret': secret} ]
0129 
0130         return res
0131 
0132     def savephonebook(self, data):
0133         "Saves out the phonebook"
0134 
0135         self.setmode(self.MODEPHONEBOOK)
0136         pb=data['phonebook']
0137         keys=pb.keys()
0138         keys.sort()
0139 
0140         keys=keys[:self.protocolclass.NUMPHONEBOOKENTRIES+1]
0141 
0142         #
0143         # Read the existing phonebook so that we cache birthdays
0144         # Erase all entries, being carefull to modify entries with
0145         # with URL's first
0146         #
0147         uslots={}
0148         names={}
0149 
0150         req=self.protocolclass.phonebooksloterase()
0151         self.log('Erasing '+self.desc+' phonebook')
0152         progressmax=self.protocolclass.NUMPHONEBOOKENTRIES+len(keys)
0153         for slot in range(2,self.protocolclass.NUMPHONEBOOKENTRIES+1):
0154             req.slot = slot
0155             self.progress(slot,progressmax,"Erasing  "+`slot`)
0156             res=self.sendpbcommand(req, self.protocolclass.phonebookslotupdateresponse)
0157 
0158 
0159         for i in range(len(keys)):
0160             slot=keys[i]
0161             req=self.protocolclass.phonebookslotupdaterequest()
0162             req.entry=self.makeentry(pb[slot],data)
0163             self.log('Writing entry '+`slot`+" - "+req.entry.name)
0164             self.progress(i+self.protocolclass.NUMPHONEBOOKENTRIES,progressmax,"Writing "+req.entry.name)
0165             self.sendpbcommand(req, self.protocolclass.phonebookslotupdateresponse)
0166         self.progress(progressmax+1,progressmax+1, "Phone book write completed")
0167         return data
0168         
0169     def makeentry(self, entry, data):
0170         e=self.protocolclass.pbentry()
0171 
0172         for k in entry:
0173             # special treatment for lists
0174             if k=='numbertypes' or k=='secrets':
0175                 continue
0176             if k=='ringtone':
0177             #    e.ringtone=self._findmediaindex(data['ringtone-index'], entry['ringtone'], entry['name'], 'ringtone')
0178                 continue
0179             elif k=='wallpaper':
0180             #    e.wallpaper=self._findmediaindex(data['wallpaper-index'], entry['wallpaper'], entry['name'], 'wallpaper')
0181                 continue
0182             elif k=='numbers':
0183                 #l=getattr(e,k)
0184                 nnum=len(entry[k])
0185                 for i in range(nnum):
0186                     enpn=self.protocolclass.phonenumber()
0187                     if i+1 == nnum:
0188                         enpn.last_number=True
0189                     enpn.numbertype=entry['numbertypes'][i]+1
0190                     enpn.number=entry[k][i]
0191                     e.numbers.append(enpn)
0192                 continue
0193             # everything else we just set
0194             setattr(e, k, entry[k])
0195         return e
0196 
0197 
0198     getwallpapers=None
0199     getringtones=None
0200 
0201 class Profile(com_samsung_packet.Profile):
0202     protocolclass=Phone.protocolclass
0203     serialsname=Phone.serialsname
0204     phone_manufacturer='SAMSUNG'
0205     phone_model='SPH-N200'
0206     deviceclasses=("serial",)
0207 
0208     def __init__(self):
0209         com_samsung_packet.Profile.__init__(self)
0210         self.numbertypetab=numbertypetab
0211 
0212     _supportedsyncs=(
0213         ('phonebook', 'read', None),  # all phonebook reading
0214         ('phonebook', 'write', 'OVERWRITE'),  # only overwriting phonebook
0215         )
0216 
0217     def convertphonebooktophone(self, helper, data):
0218         """Converts the data to what will be used by the phone
0219 
0220         @param data: contains the dict returned by getfundamentals
0221                      as well as where the results go"""
0222 
0223         results={}
0224 
0225         # find which entries are already known to this phone
0226         pb=data['phonebook']
0227         # decorate list with (slot, pbkey) tuples
0228         slots=[ (helper.getserial(pb[pbentry].get("serials", []), self.serialsname, data['uniqueserial'], "slot", None), pbentry)
0229                 for pbentry in pb]
0230         slots.sort() # numeric order
0231         # make two lists - one contains known slots, one doesn't
0232         newones=[(pbentry,slot) for slot,pbentry in slots if slot is None]
0233         existing=[(pbentry,slot) for slot,pbentry in slots if slot is not None]
0234         
0235         uslotsused={}
0236 
0237         tempslot=0 # Temporarily just pick slots and speed dial in order
0238         for pbentry,slot in existing+newones:
0239 
0240             if len(results)==self.protocolclass.NUMPHONEBOOKENTRIES:
0241                 break
0242 
0243             try:
0244 
0245                 e={} # entry out
0246 
0247                 entry=data['phonebook'][pbentry]
0248 
0249                 secret=helper.getflag(entry.get('flags', []), 'secret', False)
0250                 if secret:
0251                     secret=1
0252                 else:
0253                     secret=0
0254             
0255                 # name
0256                 e['name']=helper.getfullname(entry.get('names', []),1,1,12)[0]
0257 
0258                 cat=helper.makeone(helper.getcategory(entry.get('cagetgories',[]),0,1,12), None)
0259 
0260                 # phone numbers
0261                 # there must be at least one phone number
0262                 minnumbers=1
0263                 numbers=helper.getnumbers(entry.get('numbers', []),minnumbers,self.protocolclass.NUMPHONENUMBERS)
0264                 e['numbertypes']=[]
0265                 e['numbers']=[]
0266                 e['secrets']=[]
0267                 unusednumbers=[] # Hold duplicate types here
0268                 typesused={}
0269                 defaulttypenum=0
0270                 for num in numbers:
0271                     typename=num['type']
0272                     if typesused.has_key(typename):
0273                         unusednumbers.append(num)
0274                         continue
0275                     typesused[typename]=1
0276                     for typenum,tnsearch in enumerate(self.numbertypetab):
0277                         if typename==tnsearch:
0278                             if defaulttypenum==0:
0279                                 defaulttypenum=typenum
0280                             number=self.phonize(num['number'])
0281                             if len(number)>self.protocolclass.MAXNUMBERLEN:
0282                                 # :: TODO:: number is too long and we have to either truncate it or ignore it?
0283                                 number=number[:self.protocolclass.MAXNUMBERLEN]
0284                             e['numbers'].append(number)
0285                             if(num.has_key('speeddial')):
0286                                 # Only one number per name can be a speed dial
0287                                 # Should make speed dial be the first that
0288                                 # we come accross
0289                                 e['speeddial']=typenum
0290                                 tryuslot = num['speeddial']
0291                             e['numbertypes'].append(typenum)
0292                             e['secrets'].append(secret)
0293 
0294                             break
0295 
0296                 # Should print to log when a requested speed dial slot is
0297                 # not available
0298                 if e.has_key('speeddial'):
0299                     if tryuslot>=1 and tryuslot<=self.protocolclass.NUMPHONEBOOKENTRIES and not uslotsused.has_key(tryuslot):
0300                         uslotsused[tryuslot]=1
0301                         e['uslot']=tryuslot
0302                 else:
0303                     e['speeddial']=defaulttypenum
0304 
0305                 # find the right slot
0306                 if slot is None or slot<2 or slot>self.protocolclass.NUMPHONEBOOKENTRIES or slot in results:
0307                     for i in range(2,100000):
0308                         if i not in results:
0309                             slot=i
0310                             break
0311 
0312                 e['slot']=slot
0313 
0314                 results[slot]=e
0315             except helper.ConversionFailed:
0316                 continue
0317 
0318         # Fill in uslot for entries that don't have it.
0319         
0320         tryuslot=1
0321         for slot in results.keys():
0322 
0323             e=results[slot]
0324             if not e.has_key('uslot'):
0325                 while tryuslot<self.protocolclass.NUMPHONEBOOKENTRIES and uslotsused.has_key(tryuslot):
0326                     tryuslot += 1
0327                 uslotsused[tryuslot]=1
0328                 e['uslot'] = tryuslot
0329                 results[slot] = e
0330 
0331         data['phonebook']=results
0332         return data
0333 
0334     def phonize(self,str):
0335         """Convert the phone number into something the phone understands
0336         All digits, P, T, * and # are kept, everything else is removed"""
0337 
0338         return re.sub("[^0-9PT#*]", "", str)[:self.protocolclass.MAXNUMBERLEN]
0339 
0340 

Generated by PyXR 0.9.4