PyXR

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



0001 ### BITPIM
0002 ###
0003 ### Copyright (C) 2003 Roger Binns <rogerb@rogerbinns.com>
0004 ### Copyright (C) 2003 Scott Craig <scott.craig@shaw.ca>
0005 ### Copyright (C) 2003 Alan Gonzalez <agonzalez@yahoo.com>
0006 ###
0007 ### This program is free software; you can redistribute it and/or modify
0008 ### it under the terms of the BitPim license as detailed in the LICENSE file.
0009 ###
0010 ### $Id: com_lgtm520.py 4543 2008-01-04 23:44:24Z djpham $
0011 
0012 "Talk to the LG TM520/VX10 cell phone"
0013 
0014 # standard modules
0015 import re
0016 import time
0017 import cStringIO
0018 import sha
0019 
0020 # my modules
0021 import common
0022 import p_lgtm520
0023 import com_brew
0024 import com_phone
0025 import com_lg
0026 import prototypes
0027 
0028 typemap = {
0029             'fwd': ( 'home', 'office', 'cell', 'pager', 'data' ),
0030             'rev': { 'home': 0, 'office': 1, 'cell': 2, 'pager': 3, 'data': 4, 'fax': 4 }
0031           }
0032 
0033 class Phone(com_phone.Phone,com_brew.BrewProtocol,com_lg.LGPhonebook):
0034     "Talk to the LG TM520/VX10 cell phone"
0035     desc="LG-TM520/VX10"
0036     protocolclass=p_lgtm520
0037     serialsname='lgtm520'
0038 
0039     ringtonelocations=(
0040         # offset, index file, files location, type, maximumentries
0041         # There really isn't an index file
0042         ( 0, "", "ringer", "ringers", 5),
0043         # phonebook linkage
0044         #( 0, "pim/midiringer.dat", "ringer", "ringers", 199),
0045         # main ringer
0046         #( 0, "pim/ringtitle.dat", "ringer", "ringers", 1),
0047         )
0048 
0049     builtinringtones=( 'Standard1', 'Standard2', 'Standard3', 'Standard4',
0050                        'Standard5', 'Radetzky March', 'Nocturn', 'Carmen',
0051                        'La Traviata', 'Liberty Bell', 'Semper Fidelis',
0052                        'Take Me Out', 'Turkey In The Straw', 'We Wish...',
0053                        'Csikos Post', 'Bumble Bee Twist', 'Badinerie',
0054                        'Silken Ladder', 'Chestnut' )
0055 
0056     # phone uses Jan 1, 1980 as epoch.  Python uses Jan 1, 1970.  This is difference
0057     # plus a fudge factor of 5 days, 20 hours for no reason I can find
0058     _tm520epochtounix=315532800+460800
0059     _brewepochtounix=315532800+460800  # trying to override inherited entry
0060     _calrepeatvalues={ 0: None, 1: None, 2: 'daily' }
0061 
0062     getwallpapers=None
0063     
0064     def __init__(self, logtarget, commport):
0065         com_phone.Phone.__init__(self, logtarget, commport)
0066         com_brew.BrewProtocol.__init__(self)
0067         com_lg.LGPhonebook.__init__(self)
0068         self.log("Attempting to contact phone")
0069         self.mode=self.MODENONE
0070 
0071     def getfundamentals(self, results):
0072         """Gets information fundamental to interopating with the phone and UI."""
0073 
0074         # use a hash of ESN and other stuff (being paranoid)
0075         self.log("Retrieving fundamental phone information")
0076         self.log("Phone serial number")
0077         results['uniqueserial']=sha.new(self.getfilecontents("nvm/$SYS.ESN")).hexdigest()
0078         results['ringtone-index'] = {}
0079         ringcount = 1
0080         for r in self.builtinringtones:
0081             results['ringtone-index'][ringcount] = {'name': r, 'origin': 'builtin'}
0082             ringcount += 1
0083 
0084         try:
0085             ringers=self.getfilesystem('ringer')
0086             for r in ringers.keys():
0087                 results['ringtone-index'][ringcount] = {'name': r[len('ringer/'):], 'origin': 'ringers'}
0088                 ringcount +=1
0089         except com_brew.BrewNoSuchDirectoryException:
0090             self.log("Ringer directory doesn't exist, firmware might not be download capable")
0091         self.log("Fundamentals retrieved")
0092         return results
0093 
0094     def pbinit(self):
0095         self.mode = self.MODEPHONEBOOK
0096         self.sendpbcommand(self.protocolclass.pbstartsyncrequest(), self.protocolclass.pbstartsyncresponse)
0097         
0098         self.mode = self.MODEBREW
0099         res=self.sendpbcommand(self.protocolclass.pbinforequest(), self.protocolclass.pbinforesponse)
0100 
0101         return res.numentries
0102 
0103     def pbend(self):
0104         req=self.protocolclass.pbendsyncrequest()
0105         self.sendpbcommand(req, self.protocolclass.pbendsyncresponse)
0106 
0107     def pregetpb(self, result):
0108         index={}
0109         try:
0110             buf=prototypes.buffer(self.getfilecontents("pim/midiringer.dat"))
0111         except com_brew.BrewNoSuchFileException:
0112             # file may not exist
0113             result['intermediate'] = index
0114             return
0115         g=self.protocolclass.ringindex()
0116         g.readfrombuffer(buf, logtitle="ringer index")
0117         for i in g.items:
0118             if i.name != "default":
0119                 index[i.index+1]=i.name[len('ringer/'):]
0120         result['intermediate'] = index
0121 
0122     def postgetdb(self, result):
0123         #cats=[]
0124         #for i in result['groups']:
0125         #    if result['groups'][i]['name']!='No Group':
0126         # cats.append(result['groups'][i]['name'])
0127         #result['categories'] = cats
0128         del result['intermediate']
0129 
0130     def getphonebook(self,result):
0131         """Reads the phonebook data.  The L{getfundamentals} information will
0132         already be in result."""
0133         pbook={}
0134         # Bug in the phone.  if you repeatedly read the phone book it starts
0135         # returning a random number as the number of entries.  We get around
0136         # this by switching into brew mode which clears that.
0137         #self.mode=self.MODENONE
0138         #self.setmode(self.MODEBREW)
0139 
0140         self.pregetpb(result)
0141         self.log("Reading number of phonebook entries")
0142 
0143         numentries=self.pbinit()
0144         self.log("There are %d entries" % (numentries,))
0145         for i in range(0, numentries):
0146             ### Read current entry
0147             req=self.protocolclass.pbreadentryrequest()
0148             res=self.sendpbcommand(req, self.protocolclass.pbreadentryresponse)
0149             self.log("Read entry "+`i`+" - "+res.entry.name)
0150             entry=self.extractphonebookentry(res.entry, result)
0151             pbook[i]=entry 
0152             self.progress(i, numentries, res.entry.name)
0153             #### Advance to next entry
0154             req=self.protocolclass.pbnextentryrequest()
0155             self.sendpbcommand(req, self.protocolclass.pbnextentryresponse)
0156 
0157         self.progress(numentries, numentries, "Phone book read completed")
0158         result['phonebook']=pbook
0159         self.pbend()
0160         self.postgetdb(result)
0161 
0162         print "returning keys",result.keys()
0163         return pbook
0164 
0165     def extractphonebookentry(self, entry, fundamentals):
0166         """Return a phonebook entry in BitPim format"""
0167         res={}
0168         # serials
0169         res['serials']=[ {'sourcetype': self.serialsname, 'serial1': entry.serial1, 'serial2': entry.serial2,
0170                           'sourceuniqueid': fundamentals['uniqueserial']} ]
0171         # only one name
0172         res['names']=[ {'full': entry.name} ]
0173         # only one email
0174         if len(entry.email) > 0: res['emails']=[ {'email': entry.email} ]
0175         res['flags'] = []
0176         # we only supply secret/voicetag if it is true
0177         if entry.secret: res['flags'].append({'secret': entry.secret })
0178         if entry.voicetag: res['flags'].append({'voicetag': entry.voicetag })
0179 
0180         # ringtones
0181         res['ringtones'] = []
0182         if entry.ringtone > 0:
0183             # individual ringtone
0184             if entry.ringtone > len(self.builtinringtones):
0185                 # custom individual ringtone
0186                 try:
0187                     res['ringtones'].append({'ringtone': fundamentals['intermediate'][entry.entrynumber], 'use': 'call'})
0188                 except:
0189                     self.log('Custom ringtone not properly assigned for '+entry.name)
0190             else:
0191                 # stock individual ringtone
0192                 res['ringtones'].append({'ringtone': fundamentals['ringtone-index'][entry.ringtone]['name'], 'use': 'call'})
0193         # 5 phone numbers
0194         res['numbers']=[]
0195         numbernumber=0
0196         for type in typemap['fwd']:
0197             item = entry.numbers[numbernumber]
0198             if len(item.number) > 0:
0199                 res['numbers'].append({'number': item.number, 'type': type, 'sum': item.chksum })
0200                 if numbernumber == entry.default: res['numbers'][-1]['speeddial'] = entry.entrynumber
0201             numbernumber+=1
0202         return res
0203 
0204     def savegroups(self, data): pass
0205 
0206     def savephonebook(self, data):
0207         self.savegroups(data)
0208         # To write the phone book, we scan through all existing entries
0209         # and record their record number and serials.
0210         # We then delete any entries that aren't in data
0211         # We then write out our records, usng overwrite or append
0212         # commands as necessary
0213         serialupdates=[]
0214         existingpbook={} # keep track of the phonebook that is on the phone
0215         ringindex = {}
0216 
0217         # Ringtones
0218         pbook = data['phonebook']
0219         for i in pbook.keys():
0220             if not 'ringtone' in pbook[i]: continue
0221             if not pbook[i]['ringtone'] is None and not pbook[i]['ringtone'] in self.builtinringtones:
0222                 ringindex[pbook[i]['entrynumber']] = pbook[i]['ringtone'];
0223 
0224         ringidxfile=self.protocolclass.ringindex()
0225         for i in range(1, 200):
0226             ringerentry = self.protocolclass.ringentry()
0227             ringerentry.index = i
0228             ringerentry.name = ''
0229             if i in ringindex: ringerentry.name = 'ringer/'+ringindex[i]
0230             ringidxfile.items.append(ringerentry)
0231         buf=prototypes.buffer()
0232         ringidxfile.writetobuffer(buf, logtitle="Custom ringer index")
0233 
0234         # ::TODO:: this code looks wrong.  Why isn't the if before the loop above?
0235         # and if the user deleted all ringers then shouldn't the file be truncated
0236         # rather than ignored?
0237         if len(ringindex) > 0:
0238             self.writefile("pim/midiringer.dat", buf.getvalue())
0239 
0240         #self.mode=self.MODENONE
0241         #self.setmode(self.MODEBREW) # see note in getphonebook() for why this is necessary
0242         #self.setmode(self.MODEPHONEBOOK)
0243         # similar loop to reading
0244         numexistingentries=self.pbinit()
0245         progressmax=numexistingentries+len(data['phonebook'].keys())
0246         progresscur=0
0247         self.log("There are %d existing entries" % (numexistingentries,))
0248         for i in range(0, numexistingentries):
0249             ### Read current entry
0250             req=self.protocolclass.pbreadentryrequest()
0251             res=self.sendpbcommand(req, self.protocolclass.pbreadentryresponse)
0252             
0253             entry={ 'number':  res.entry.entrynumber, 'serial1':  res.entry.serial1,
0254                     'serial2': res.entry.serial2, 'name': res.entry.name}
0255             assert entry['serial1']==entry['serial2'] # always the same
0256             self.log("Reading entry "+`i`+" - "+entry['name'])            
0257             existingpbook[i]=entry 
0258             self.progress(progresscur, progressmax, "existing "+entry['name'])
0259             #### Advance to next entry
0260             req=self.protocolclass.pbnextentryrequest()
0261             self.sendpbcommand(req, self.protocolclass.pbnextentryresponse)
0262             progresscur+=1
0263         # we have now looped around back to begining
0264 
0265         # Find entries that have been deleted
0266         pbook=data['phonebook']
0267         dellist=[]
0268         for i in range(0, numexistingentries):
0269             ii=existingpbook[i]
0270             serial=ii['serial1']
0271             item=self._findserial(serial, pbook)
0272             if item is None:
0273                 dellist.append(i)
0274 
0275         progressmax+=len(dellist) # more work to do
0276 
0277         # Delete those entries
0278         for i in dellist:
0279             progresscur+=1
0280             numexistingentries-=1  # keep count right
0281             ii=existingpbook[i]
0282             self.log("Deleting entry "+`i`+" - "+ii['name'])
0283             req=self.protocolclass.pbdeleteentryrequest()
0284             req.serial1=ii['serial1']
0285             req.serial2=ii['serial2']
0286             req.entrynumber=ii['number']
0287             self.sendpbcommand(req, self.protocolclass.pbdeleteentryresponse)
0288             self.progress(progresscur, progressmax, "Deleting "+ii['name'])
0289             # also remove them from existingpbook
0290             del existingpbook[i]
0291 
0292         # counter to keep track of record number (otherwise appends don't work)
0293         counter=0
0294         # Now rewrite out existing entries
0295         keys=existingpbook.keys()
0296         existingserials=[]
0297         keys.sort()  # do in same order as existingpbook
0298         for i in keys:
0299             progresscur+=1
0300             ii=pbook[self._findserial(existingpbook[i]['serial1'], pbook)]
0301             self.log("Rewriting entry "+`i`+" - "+ii['name'])
0302             self.progress(progresscur, progressmax, "Rewriting "+ii['name'])
0303             entry=self.makeentry(counter, ii, data)
0304             counter+=1
0305             existingserials.append(existingpbook[i]['serial1'])
0306             req=self.protocolclass.pbupdateentryrequest()
0307             req.entry=entry
0308             res=self.sendpbcommand(req, self.protocolclass.pbupdateentryresponse)
0309             serialupdates.append( ( ii["bitpimserial"],
0310                                     {'sourcetype': self.serialsname, 'serial1': res.serial1, 'serial2': res.serial1,
0311                                      'sourceuniqueid': data['uniqueserial']})
0312                                   )
0313             assert ii['serial1']==res.serial1 # serial should stay the same
0314 
0315         # Finally write out new entries
0316         keys=pbook.keys()
0317         keys.sort()
0318         for i in keys:
0319             ii=pbook[i]
0320             if ii['serial1'] in existingserials:
0321                 continue # already wrote this one out
0322             progresscur+=1
0323             entry=self.makeentry(counter, ii, data)
0324             counter+=1
0325             self.log("Appending entry "+ii['name'])
0326             self.progress(progresscur, progressmax, "Writing "+ii['name'])
0327             req=self.protocolclass.pbappendentryrequest()
0328             req.entry=entry
0329             res=self.sendpbcommand(req, self.protocolclass.pbappendentryresponse)
0330             serialupdates.append( ( ii["bitpimserial"],
0331                                      {'sourcetype': self.serialsname, 'serial1': res.newserial, 'serial2': res.newserial,
0332                                      'sourceuniqueid': data['uniqueserial']})
0333                                   )
0334 
0335         self.pbend()
0336         data["serialupdates"]=serialupdates
0337         if len(ringindex) == 0: return
0338 
0339 
0340     def _findserial(self, serial, dict):
0341         """Searches dict to find entry with matching serial.  If not found,
0342         returns None"""
0343         for i in dict:
0344             if dict[i]['serial1']==serial:
0345                 return i
0346         return None
0347 
0348     def getcalendar(self,result):
0349         res={}
0350         # Now read schedule
0351         buf=prototypes.buffer(self.getfilecontents("sch/sch_00.dat"))
0352         sc=self.protocolclass.schedulefile()
0353         sc.readfrombuffer(buf, logtitle="Calendar")
0354         self.logdata("Calendar", buf.getdata(), sc)
0355         for event in sc.events:
0356             entry={}
0357             if event.state == 0 or event.repeat == 0: continue    # deleted entry
0358             if event.date == 0x11223344: continue  # blanked entry
0359             date = event.date
0360             date += self._tm520epochtounix
0361             entry['start'] = self.decodedate(date)
0362             entry['end'] = self.decodedate(date)
0363             entry['pos']=event.pos
0364             entry['description'] = event.description
0365             if event.pos == 0: entry['description'] = 'Wake Up'
0366             entry['alarm'] = 0
0367             if event.alarm & 0xB0 == 0xB0: entry['alarm'] = 1
0368             entry['ringtone'] = 0
0369             entry['changeserial'] = 0
0370             entry['repeat'] = self._calrepeatvalues[event.repeat]
0371 
0372             # Hack - using snoozedelay to store the DST flag
0373             entry['snoozedelay'] = time.localtime(date)[8]
0374             res[event.pos]=entry
0375 
0376         result['calendar']=res
0377         return result
0378 
0379     def savecalendar(self, dict, merge):
0380         # ::TODO:: obey merge param
0381         # what will be written to the files
0382         eventsf=self.protocolclass.schedulefile()
0383 
0384         # what are we working with
0385         cal=dict['calendar']
0386         newcal={}
0387         keys=cal.keys()
0388         keys.sort()
0389 
0390         # number of entries
0391         numactiveitems=len(keys)
0392         self.log("There are %d calendar entries" % (numactiveitems,))
0393         counter = 1
0394 
0395         # Write out alarm entry - see below for special handling
0396         alarm=self.protocolclass.scheduleevent()
0397         alarm.pos = 0
0398         alarm.date = 0x11223344
0399         alarm.state = 0
0400         alarm.alarm = 0x80
0401         alarm.repeat = 0
0402         alarm.description = " NO ENTRY        NO ENTRY      "
0403 
0404         eventsf.events.append(dummy)
0405         # play with each entry
0406         for k in keys:
0407             # entry is what we will return to user
0408             entry=cal[k]
0409             data=self.protocolclass.scheduleevent()
0410             if counter >= 50:
0411                 self.log("More than 49 entries in calendar, only writing out the first 49")
0412                 break
0413             data.pos=counter
0414             counter+=1
0415             entry['pos']=data.pos
0416             # simple copy of these fields
0417             for field in 'start','description':
0418                 setattr(data,field,entry[field])
0419 
0420             data.state = 2
0421             data.alarm = 0
0422             data.repeat = 1
0423 
0424             dst = -1
0425             if entry['snoozedelay']: dst = entry['snoozedelay']
0426             data.date = self.encodedate(entry['start'],dst)-self._tm520epochtounix
0427 
0428             # Special alarm handling - TM520 is not capable of having an alarmed
0429             # entry, so we will only alarm on the earliest entry
0430             if entry['alarm'] > 0 and ( alarm.date == 0x11223344 or data.date < alarm.date ):
0431                 alarm.date = data.date
0432                 alarm.state = 1
0433                 alarm.alarm = 0xB0
0434                 alarm.repeat = 1
0435                 if entry['repeat'] > 0: alarm.repeat = 2
0436 
0437             # put entry in nice shiny new dict we are building
0438             newcal[data.pos]=entry
0439             eventsf.events.append(data)
0440 
0441         if counter < 50:
0442             for i in range(counter, 50):
0443                 dummy=self.protocolclass.scheduleevent()
0444                 dummy.pos = i
0445                 dummy.date = 0x11223344
0446                 dummy.state = 0
0447                 dummy.alarm = 0x80
0448                 dummy.repeat = 0
0449                 dummy.description = " NO ENTRY        NO ENTRY      "
0450                 eventsf.events.append(dummy)
0451 
0452         # scribble everything out
0453         buf=prototypes.buffer()
0454         eventsf.writetobuffer(buf, logtitle="Writing calendar")
0455         self.writefile("sch/sch_00.dat", buf.getvalue())
0456 
0457         # fix passed in dict
0458         dict['calendar']=newcal
0459 
0460         return dict
0461 
0462     def getringtones(self, result):
0463         media = {}
0464         try:
0465             ringers=self.getfilesystem('ringer')
0466             for r in ringers:
0467                 name = r[len('ringer/'):]
0468                 media[name] = self.getfilecontents(r)
0469         except com_brew.BrewNoSuchDirectoryException: pass
0470         result['ringtone'] = media
0471         return result
0472         
0473     def saveringtones(self, results, merge):
0474         try:
0475             ringers=self.getfilesystem('ringer')
0476             for r in ringers.keys():
0477                 ringers[r[len('ringer/'):]] = ringers[r]
0478                 del ringers[r]
0479         except com_brew.BrewNoSuchDirectoryException:
0480             self.log("Ringer directory doesn't exist, firmware might not be download capable")
0481             return results
0482 
0483         index={}
0484         for r in results['ringtone-index']:
0485             if r['origin'] == 'ringers': index.append(r['name'])
0486 
0487         for r in ringers.keys():
0488             # it is in the original index, are we writing it back out?
0489             if r in index and ringers[r]['size'] == len(results['ringtone'][r]): continue
0490             else:
0491                 if not merge or r in index:
0492                     # go ahead and delete unwanted files
0493                     print "deleting",r
0494                     self.rmfile("ringer/"+r)
0495                     if r in index: self.writefile("ringer/"+r, results['ringtone'][r])
0496 
0497     def decodedate(self,val):
0498         """Unpack 32 bit value into date/time
0499 
0500         @rtype: tuple
0501         @return: (year, month, day, hour, minute)
0502         """
0503         return time.localtime(val)[:5]
0504 
0505     def encodedate(self,val,dst):
0506         tmp = []
0507         for i in val: tmp.append(i)
0508         tmp += [0, 0, 0, dst]
0509         return time.mktime(tmp)
0510 
0511     def _findringtoneindex(self, index, name, pbentryname):
0512         if name is None: return 0
0513         for i in index:
0514             if index[i]['name'] == name:
0515                 return i
0516         self.log("%s: Unable to find ringtone %s in the index. Setting to default." % (pbentryname, name))
0517         return 0
0518 
0519     def _calcnumsum(self, entry, number):
0520         sumtbl = { '0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9,
0521                    'H': 24, 'T': 36, '#': -13, '*': -6 }
0522         entry.number = number
0523         entry.chksum = 0
0524         lastseven = number
0525         if len(lastseven) > 7: lastseven = lastseven[len(lastseven)-7:]
0526         if len(lastseven) > 0:
0527             for i in lastseven:
0528                 entry.chksum += sumtbl[i]
0529         else: entry.chksum = 255
0530 
0531     def makeentry(self, counter, entry, dict):
0532         e=self.protocolclass.pbentry()
0533         e.entrynumber=counter
0534         
0535         for k in entry:
0536             # special treatment for lists
0537             if k == 'numbers':
0538                 l=getattr(e,k)
0539                 for item in entry[k]:
0540                     num=self.protocolclass.numentry()
0541                     self._calcnumsum(num, item)
0542                     l.append(num)
0543             elif k == 'ringtone':
0544                 e.ringtone = self._findringtoneindex(dict['ringtone-index'], entry[k], entry['name'])
0545             else:
0546                 # everything else we just set
0547                 setattr(e,k,entry[k])
0548 
0549         return e
0550 
0551 def phonize(str):
0552     """Convert the phone number into something the phone understands
0553     
0554     All digits, P, H, T, * and # are kept, everything else is removed"""
0555     return re.sub("[^0-9HPT#*]", "", str)
0556 
0557 
0558 class Profile(com_phone.Profile):
0559     serialsname='lgtm520'
0560     WALLPAPER_WIDTH=100
0561     WALLPAPER_HEIGHT=100
0562     MAX_WALLPAPER_BASENAME_LENGTH=19
0563     MAX_RINGTONE_BASENAME_LENGTH=19
0564     WALLPAPER_FILENAME_CHARS="abcdefghijklmnopqrstuvwxyz0123456789 ."
0565     RINGTONE_FILENAME_CHARS="abcdefghijklmnopqrstuvwxyz0123456789 ."
0566     WALLPAPER_CONVERT_FORMAT="bmp"
0567     
0568     usbids = ( )
0569     deviceclasses = ("serial", )
0570     _supportedsyncs=(
0571         ('phonebook', 'read', None),  # all phonebook reading
0572         ('calendar', 'read', None),   # all calendar reading
0573         ('ringtone', 'read', None),   # all ringtone reading
0574         ('phonebook', 'write', 'OVERWRITE'),  # only overwriting phonebook
0575         ('calendar', 'write', 'OVERWRITE'),   # only overwriting calendar
0576         ('ringtone', 'write', 'MERGE'),
0577         ('ringtone', 'write', 'OVERWRITE'),
0578         )
0579 
0580     def convertphonebooktophone(self, helper, data):
0581         "Converts the data to what will be used by the phone"
0582 
0583         results = {}
0584         speeddial = {}
0585         entrynumber = 1
0586 
0587         for pbentry in data['phonebook']:
0588             e = {}        # entry out
0589             entry = data['phonebook'][pbentry]        # entry in
0590 
0591             try:
0592                 try:
0593                     e['name'] = helper.getfullname(entry.get('names', []),1,1,16)[0]
0594                 except IndexError: raise helper.ConversionFailed("No name assigned to entry")
0595                 try:
0596                     e['email']= helper.getemails(entry.get('emails', []),0,1,48)[0]
0597                 except IndexError: e['email'] = ""
0598                 e['ringtone'] = helper.getringtone(entry.get('ringtones', []), 'call', None)
0599                 e['secret'] = helper.getflag(entry.get('flags',[]), 'secret', False)
0600                 e['voicetag'] = helper.getflag(entry.get('flags',[]), 'voicetag', False)
0601                 e['default'] = 0
0602 
0603                 numbers = entry.get('numbers', [])
0604                 if len(numbers) < 1: raise helper.ConversionFailed("Too few numbers. Need at least 1 number")
0605                 e['numbers']=[ '', '', '', '', '' ]
0606                 available = 5
0607                 deferred = []
0608                 for num in numbers:
0609                     number=phonize(num['number'])
0610                     if len(number) == 0: continue        # no actual digits in number
0611                     if len(number) > 32: number = number[:32]        # truncate long number
0612                     if available == 0: break        # all slots filled
0613                     if not 'type' in num:
0614                         deferred.append(num)
0615                         continue
0616                     elif not num['type'] in typemap['rev']:
0617                         deferred.append(num)
0618                         continue
0619                     else:
0620                         typeidx = typemap['rev'][num['type']]
0621                         if len(e['numbers'][typeidx]) == 0:
0622                             e['numbers'][typeidx] = number
0623                             if 'speeddial' in num and not 'entrynumber' in e:
0624                                 if not num['speeddial'] in speeddial:
0625                                     e['entrynumber'] = num['speeddial']
0626                                     e['default'] = typeidx
0627                             available -= 1
0628                 if available > 0 and len(deferred) > 0:
0629                     for num in deferred:
0630                         if available == 0: break
0631                         number=phonize(num['number'])
0632                         if len(number) > 32: number = number[:32]        # truncate long number
0633                         for slot in range(0, 5):
0634                             if len(e['numbers'][slot]) > 0: continue
0635                             e['numbers'][slot] = number
0636                             if 'speeddial' in num and not 'entrynumber' in e:
0637                                 if not num['speeddial'] in speeddial:
0638                                     e['entrynumber'] = num['speeddial']
0639                                     e['default'] = slot
0640                             available -= 1
0641                 if available == 5:
0642                     raise helper.ConversionFailed("The phone numbers didn't have any digits for this entry")
0643                 if not 'entrynumber' in e:
0644                     while entrynumber in speedial:
0645                         entrynumber += 1
0646                     if entrynumber > 199:
0647                         self.log("Too many entries in phonebook, only 199 entries supported")
0648                         break
0649                     e['entrynumber'] = entrynumber
0650                 speeddial[e['entrynumber']] = pbentry
0651 
0652                 serial1 = helper.getserial(entry.get('serials', []), self.serialsname, data['uniqueserial'], 'serial1', 0)
0653                 serial2 = helper.getserial(entry.get('serials', []), self.serialsname, data['uniqueserial'], 'serial2', serial1)
0654 
0655                 e['serial1'] = serial1
0656                 e['serial2'] = serial2
0657                 for ss in entry["serials"]:
0658                     if ss["sourcetype"]=="bitpim":
0659                         e['bitpimserial']=ss
0660                 assert e['bitpimserial']
0661 
0662                 results[pbentry] = e
0663 
0664             except helper.ConversionFailed: continue
0665 
0666         data['phonebook'] = results
0667         return data
0668 

Generated by PyXR 0.9.4