PyXR

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



0001 ### BITPIM
0002 ###
0003 ### Copyright (C) 2008 Joe Pham <djpham@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_lgvx9100.py 4693 2008-08-15 22:30:51Z djpham $
0009 
0010 """
0011 Communicate with the LG VX9100 (enV2) cell phone.  This is based on the enV model
0012 """
0013 
0014 # BitPim modules
0015 import common
0016 import com_brew
0017 import com_lg
0018 import com_lgvx8550
0019 import p_lgvx9100
0020 import prototypes
0021 import helpids
0022 import sms
0023 
0024 DEBUG1=False
0025 DEBUG2=False
0026 #-------------------------------------------------------------------------------
0027 parentphone=com_lgvx8550.Phone
0028 class Phone(parentphone):
0029     "Talk to the LG VX9100 cell phone"
0030 
0031     desc="LG-VX9100"
0032     helpid=helpids.ID_PHONE_LGVX9100
0033     protocolclass=p_lgvx9100
0034     serialsname='lgvx9100'
0035     my_model='VX9100'
0036 
0037     # rintones and wallpaper info, copy from VX9900, may need to change to match
0038     # what the phone actually has
0039     external_storage_root='mmc1/'
0040     builtinringtones= ('Low Beep Once', 'Low Beeps', 'Loud Beep Once', 'Loud Beeps', 'Door Bell', 'VZW Default Tone') + \
0041                       tuple(['Ringtone '+`n` for n in range(1,17)]) + \
0042                       ('No Ring',)
0043 
0044     ringtonelocations= (
0045         #  type          index file            default dir        external dir    max  type Index
0046         ( 'ringers',    'dload/myringtone.dat','brew/mod/10889/ringtones','mmc1/ringers', 100, protocolclass.INDEX_RT_TYPE, 100),
0047         ( 'sounds',     'dload/mysound.dat',   'brew/mod/18067',   '',             100, protocolclass.INDEX_SOUND_TYPE, None),
0048         ( 'sounds(sd)', 'dload/sd_sound.dat',  'mmc1/my_sounds',  '',             100, protocolclass.INDEX_SDSOUND_TYPE, None),
0049 ##        ( 'music',      'dload/efs_music.dat', 'my_music',        '',             100, 0x104, None),
0050 ##        ( 'music(sd)',  'dload/sd_music.dat',  'mmc1/my_music',   '',             100, 0x14, None),
0051         )
0052 
0053     wallpaperlocations= (
0054         #  type          index file            default dir     external dir  max  type Index
0055         ( 'images',     'dload/image.dat',    'brew/mod/10888', '',          100, protocolclass.INDEX_IMAGE_TYPE, 100),
0056         ( 'images(sd)', 'dload/sd_image.dat', 'mmc1/my_pix',   '',           100, protocolclass.INDEX_SDIMAGE_TYPE, None),
0057         ( 'video',      'dload/video.dat',    'brew/mod/10890', '',          100, protocolclass.INDEX_VIDEO_TYPE, None),
0058         ( 'video(sd)',  'dload/sd_video.dat', 'mmc1/my_flix',  '',           100, protocolclass.INDEX_SDVIDEO_TYPE, None),
0059         )
0060 
0061     def __init__(self, logtarget, commport):
0062         parentphone.__init__(self, logtarget, commport)
0063 
0064     def setDMversion(self):
0065         self._DMv6=True
0066         self._DMv5=False
0067 
0068     # Fundamentals:
0069     #  - get_esn             - same as LG VX-8300
0070     #  - getgroups           - same as LG VX-8100
0071     #  - getwallpaperindices - LGUncountedIndexedMedia
0072     #  - getrintoneindices   - LGUncountedIndexedMedia
0073     #  - DM Version          - T99VZV01: N/A, T99VZV02: 5
0074 
0075     # phonebook stuff-----------------------------------------------------------
0076     # This is essentially the same with the VX-8550 with a few tweaks.
0077     # These tweaks are probably applicable to the VX-8550 as well, but since
0078     # I can't test them on an actual VX-8550, I'll leave it alone.
0079 
0080     # groups
0081     def getgroups(self, results):
0082         "Read groups"
0083         # Reads groups that use explicit IDs
0084         self.log("Reading group information")
0085         g=self.readobject(self.protocolclass.pb_group_filename,
0086                           self.protocolclass.pbgroups,
0087                           'Reading groups data')
0088         groups={}
0089         for _group in g.groups:
0090             if _group.name:
0091                 groups[_group.groupid]= { 'name': _group.name,
0092                                      'user_added': _group.user_added }
0093         results['groups'] = groups
0094         return groups
0095 
0096     def savegroups(self, data):
0097         groups=data.get('groups', {})
0098         keys=groups.keys()
0099         keys.sort()
0100         keys.reverse()
0101         g=self.protocolclass.pbgroups()
0102         # write the No Group entry first
0103         g.groups.append(self.protocolclass.pbgroup(name='No Group'))
0104         # now write the rest in reverse ID order
0105         for k in keys:
0106             if not k:
0107                 # already wrote this one out
0108                 continue
0109             g.groups.append(self.protocolclass.pbgroup(name=groups[k]['name'],
0110                                                        groupid=k,
0111                                                        user_added=groups[k].get('user_added', 1)))
0112         self.writeobject(self.protocolclass.pb_group_filename, g,
0113                          logtitle='Writing phonebook groups',
0114                          uselocalfs=DEBUG1)
0115 
0116     def _get_speeddials(self):
0117         """Return the speed dials dict"""
0118         speeds={}
0119         try:
0120             if self.protocolclass.NUMSPEEDDIALS:
0121                 self.log("Reading speed dials")
0122                 sd=self.readobject(self.protocolclass.speed_file_name,
0123                                    self.protocolclass.speeddials, 'Reading speed dials')
0124                 for _idx,_entry in enumerate(sd.speeddials):
0125                     if _entry.valid():
0126                         speeds.setdefault(_entry.entry, {}).update({ _entry.number: _idx })
0127         except com_brew.BrewNoSuchFileException:
0128             pass
0129         return speeds
0130 
0131     def _build_media_dict(self, fundamentals, media_data, index_name):
0132         """Build & return a dict with keys being the media filenames and
0133         values being the name of the index item (index['name'])
0134         """
0135         _res={}
0136         _media_index=fundamentals.get(index_name, {})
0137         for _item in media_data.items:
0138             _pathname=_item.pathname
0139             if _pathname and not _res.has_key(_pathname):
0140                 # not already in dict, look up the name if any
0141                 _res[_pathname]=None
0142                 for _entry in _media_index.values():
0143                     if _entry.get('filename', None)==_pathname:
0144                         _res[_pathname]=_entry['name']
0145                         break
0146         return _res
0147 
0148     def _build_ice_dict(self):
0149         # Return an ICE dict for building phone entries
0150         _res={}
0151         _ice=self.readobject(self.protocolclass.pb_ice_file_name,
0152                              self.protocolclass.iceentryfile,
0153                              logtitle='Reading ICE entries')
0154         for _item in _ice.items:
0155             if _item.valid():
0156                 _res[_item.pb_index]=_item.entry_number
0157         return _res
0158 
0159     def getphonebook (self, result):
0160         """Reads the phonebook data.  The L{getfundamentals} information will
0161         already be in result."""
0162         # Read speed dials first -- same file format as the VX-8100
0163         _speeds=self._get_speeddials()
0164 
0165         # Read the emergency contacts list
0166         self.log("Reading ICE entries")
0167         _ices=self._build_ice_dict()
0168 
0169         self.log("Reading phonebook entries")
0170         pb_entries=self.readobject(self.protocolclass.pb_file_name,
0171                                    self.protocolclass.pbfile,
0172                                    logtitle='Reading phonebook entries')
0173 
0174         self.log("Reading phone numbers")
0175         pb_numbers=self.readobject(self.protocolclass.pn_file_name,
0176                                    self.protocolclass.pnfile,
0177                                    logtitle='Reading phonebook numbers')
0178 
0179         self.log("Reading Ringtone IDs")
0180         ring_pathf=self._get_path_index(self.protocolclass.RTPathIndexFile)
0181         _rt_ids=self._build_media_dict(result, ring_pathf, 'ringtone-index')
0182 
0183         self.log("Reading Picture IDs")
0184         picid_pathf=self._get_path_index(self.protocolclass.WPPathIndexFile)
0185         _wp_ids=self._build_media_dict(result, picid_pathf, 'wallpaper-index')
0186 
0187         pbook={}
0188         for _cnt in range(self.protocolclass.NUMPHONEBOOKENTRIES):
0189             pb_entry=pb_entries.items[_cnt]
0190             if not pb_entry.valid():
0191                 continue
0192             try:
0193                 self.log("Parse entry "+`_cnt`+" - " + pb_entry.name)
0194                 pbook[_cnt]=self.extractphonebookentry(pb_entry, pb_numbers,
0195                                                        _speeds, _ices, result,
0196                                                        _rt_ids.get(ring_pathf.items[_cnt].pathname, None),
0197                                                        _wp_ids.get(picid_pathf.items[_cnt].pathname, None))
0198 
0199                 self.progress(_cnt, self.protocolclass.NUMPHONEBOOKENTRIES, pb_entry.name)
0200             except common.PhoneBookBusyException:
0201                 raise
0202             except Exception, e:
0203                 # Something's wrong with this entry, log it and skip
0204                 self.log('Failed to parse entry %d'%_cnt)
0205                 self.log('Exception %s raised'%`e`)
0206                 if __debug__:
0207                     raise
0208             
0209         self.progress(self.protocolclass.NUMPHONEBOOKENTRIES,
0210                       self.protocolclass.NUMPHONEBOOKENTRIES,
0211                       "Phone book read completed")
0212 
0213         result['phonebook']=pbook
0214         cats=[]
0215         for i in result['groups']:
0216             if result['groups'][i]['name']!='No Group':
0217                 cats.append(result['groups'][i]['name'])
0218         result['categories']=cats
0219         return pbook
0220 
0221     def extractphonebookentry(self, entry, numbers, speeds, ices, fundamentals,
0222                               rt_name, wp_name):
0223         """Return a phonebook entry in BitPim format.  This is called from getphonebook."""
0224         res={}
0225         # serials
0226         res['serials']=[ {'sourcetype': self.serialsname,
0227                           'sourceuniqueid': fundamentals['uniqueserial'],
0228                           'serial1': entry.entry_number1,
0229                           'serial2': entry.entry_number1 } ] 
0230 
0231         # only one name
0232         res['names']=[ {'full': entry.name} ]
0233 
0234         # only one category
0235         cat=fundamentals['groups'].get(entry.group, {'name': "No Group"})['name']
0236         if cat!="No Group":
0237             res['categories']=[ {'category': cat} ]
0238 
0239         # emails
0240         res['emails']=[]
0241         for i in entry.emails:
0242             if len(i.email):
0243                 res['emails'].append( {'email': i.email} )
0244         if not len(res['emails']): del res['emails'] # it was empty
0245 
0246         # wallpapers
0247         if entry.wallpaper!=self.protocolclass.NOWALLPAPER:
0248             try:
0249                 if entry.wallpaper == 0x64:
0250                     paper = wp_name
0251                 else:
0252                     paper = fundamentals['wallpaper-index'][entry.wallpaper]['name']
0253                 res['wallpapers']=[ {'wallpaper': paper, 'use': 'call'} ]                
0254             except:
0255                 print "can't find wallpaper for index",entry.wallpaper
0256             
0257         # ringtones
0258         if entry.ringtone != self.protocolclass.NORINGTONE:
0259             try:
0260                 if entry.ringtone == 0x64:
0261                     tone = rt_name
0262                 else:
0263                     tone=fundamentals['ringtone-index'][entry.ringtone]['name']
0264                 if tone:
0265                     res['ringtones']=[ {'ringtone': tone, 'use': 'call'} ]
0266             except:
0267                 print "can't find ringtone for index",entry.ringtone
0268         # assume we are like the VX-8100 in this regard -- looks correct
0269         res=self._assignpbtypeandspeeddialsbytype(entry, numbers, speeds, res)
0270 
0271         # assign the ICE entry to the associated contact to keep them in sync
0272         res=self._assigniceentry(entry, numbers, ices, res)
0273 
0274         return res
0275                     
0276     def _assignpbtypeandspeeddialsbytype(self, entry, numbers, speeds, res):
0277         # for some phones (e.g. vx8100) the speeddial numberindex is really the numbertype (now why would LG want to change this!)
0278         res['numbers']=[]
0279         for i in range(self.protocolclass.NUMPHONENUMBERS):
0280             if entry.numberindices[i].numberindex>=\
0281                self.protocolclass.NUMPHONENUMBERENTRIES:
0282                 # invalid number
0283                 continue
0284             _pnentry=numbers.items[entry.numberindices[i].numberindex]
0285             num=_pnentry.phone_number
0286             num_type=_pnentry.type
0287             if len(num):
0288                 t=self.protocolclass.numbertypetab[num_type]
0289                 if t[-1]=='2':
0290                     t=t[:-1]
0291                 res['numbers'].append({'number': num, 'type': t})
0292                 # if this is a speeddial number set it
0293                 if speeds.has_key(entry.entry_number0) and \
0294                    speeds[entry.entry_number0].has_key(num_type):
0295                     res['numbers'][i]['speeddial']=speeds[entry.entry_number0][num_type]
0296         return res
0297 
0298     def _assigniceentry(self, entry, numbers, ices, res):
0299         if ices.has_key(entry.entry_number0):
0300             # this contact entry is an ICE entry
0301             res['ice']=[ { 'iceindex': ices[entry.entry_number0] } ]
0302             self.log('Entry %d is ICE %d'%(entry.entry_number0,
0303                                            ices[entry.entry_number0]))
0304         return res
0305 
0306     def _get_next_pb_id(self):
0307         """Return the next available pbentry ID"""
0308         return self.readobject(self.protocolclass.pb_recordid_filename,
0309                                self.protocolclass.RecordIdEntry,
0310                                logtitle='Reading record_id').idnum
0311     def _save_next_pb_id(self, idnum):
0312         """Save the next pbentry ID"""
0313         self.writeobject(self.protocolclass.pb_recordid_filename,
0314                          self.protocolclass.RecordIdEntry(idnum=idnum),
0315                          logtitle='Writing record_id',
0316                          uselocalfs=DEBUG1)
0317     def savephonebook (self, data):
0318         "Saves out the phonebook"
0319         self.savegroups (data)
0320 
0321         ring_pathf=self.protocolclass.PathIndexFile()
0322         picid_pathf=self.protocolclass.PathIndexFile()
0323 
0324         # the pbentry.dat will will be overwritten so there is no need to delete entries
0325         pbook = data.get('phonebook', {})
0326         keys = pbook.keys ()
0327         keys.sort ()
0328 
0329         _rt_index=data.get('ringtone-index', {})
0330         _wp_index=data.get('wallpaper-index', {})
0331 
0332         entry_num0 = 0
0333         entry_num1=self._get_next_pb_id()
0334         pb_entries = self.protocolclass.pbfile()
0335         pn_entries=self.protocolclass.pnfile()
0336         ice_entries = self.protocolclass.iceentryfile()
0337         for i in range(self.protocolclass.NUMEMERGENCYCONTACTS):
0338             ice_entries.items.append (self.protocolclass.iceentry())
0339         speeddials={}
0340         for i in keys:
0341             pb_entries.items.append(self.make_entry (pn_entries, speeddials, ice_entries,
0342                                                      entry_num0, entry_num1,
0343                                                      pbook[i], data,
0344                                                      ring_pathf,_rt_index,
0345                                                      picid_pathf, _wp_index))
0346             entry_num0 += 1
0347             if entry_num0 >= self.protocolclass.NUMPHONEBOOKENTRIES:
0348                 self.log ("Maximum number of phonebook entries reached")
0349                 break
0350             if entry_num1==0xffffffff:
0351                 entry_num1=0
0352             else:
0353                 entry_num1+=1
0354 
0355         # write phonebook entries
0356         self.log ("Writing phonebook entries")
0357         self.writeobject(self.protocolclass.pb_file_name,
0358                          pb_entries,
0359                          logtitle='Writing phonebook entries',
0360                          uselocalfs=DEBUG1)
0361         # write phone numbers
0362         self.log ("Writing phone numbers")
0363         self.writeobject(self.protocolclass.pn_file_name,
0364                          pn_entries, logtitle='Writing phonebook numbers',
0365                          uselocalfs=DEBUG1)
0366         # write ringtone index
0367         self.log('Writing ringtone ID')
0368         self.writeobject(self.protocolclass.RTPathIndexFile,
0369                          ring_pathf, logtitle='Writing ringtone paths',
0370                          uselocalfs=DEBUG1)
0371         # write wallpaer index
0372         self.log('Writing pciture ID')
0373         self.writeobject(self.protocolclass.WPPathIndexFile,
0374                          picid_pathf, logtitle='Writing wallpaper paths',
0375                          uselocalfs=DEBUG1)
0376         # write ICE index
0377         self.log('Writing ICE entries')
0378         self.writeobject(self.protocolclass.pb_ice_file_name,
0379                          ice_entries, logtitle='Writing ICE entries',
0380                          uselocalfs=DEBUG1)
0381 
0382         # update speed dials
0383         req=self.protocolclass.speeddials()
0384         # slot 0 is always unused
0385         req.speeddials.append(self.protocolclass.speeddial())
0386         # if empty, slot 1 is for voicemail
0387         if speeddials.has_key(1):
0388             req.speeddials.append(self.protocolclass.speeddial(entry=speeddials[1]['entry'],
0389                                                                number=speeddials[1]['type']))
0390         else:
0391             req.speeddials.append(self.protocolclass.speeddial(entry=1000,
0392                                                                number=6))
0393         for i in range(2, self.protocolclass.NUMSPEEDDIALS):
0394             sd=self.protocolclass.speeddial()
0395             if speeddials.has_key(i):
0396                 sd.entry=speeddials[i]['entry']
0397                 sd.number=speeddials[i]['type']
0398             req.speeddials.append(sd)
0399         self.log('Writing speed dials')
0400         self.writeobject(self.protocolclass.speed_file_name,
0401                          req, logtitle='Writing speed dials data',
0402                          uselocalfs=DEBUG1)
0403         # update the next pbentries ID
0404         self._save_next_pb_id(entry_num1)
0405         data["rebootphone"]=True
0406 
0407         return data
0408 
0409     def make_pn_entry (self, phone_number, number_type, pn_id, pbpn_id, pe_id):
0410         """ Create a non-blank pnfileentry frome a phone number string """
0411         if len(phone_number) == 0:
0412             raise
0413         
0414         new_entry = self.protocolclass.pnfileentry(entry_tag=self.protocolclass.PB_NUMBER_SOR)
0415         new_entry.pn_id = pn_id
0416         new_entry.pe_id = pe_id
0417         new_entry.phone_number = phone_number
0418         new_entry.type = number_type
0419         new_entry.pn_order = pbpn_id
0420 
0421         return new_entry
0422 
0423     def make_ice_entry (self, ice_id, pb_id):
0424         """ Create a iceentry from a pb_id and ice_id """
0425         new_entry = self.protocolclass.iceentry()
0426         
0427         new_entry.entry_assigned = 1
0428         new_entry.entry_number = ice_id
0429         new_entry.pb_index = pb_id
0430 
0431         return new_entry
0432 
0433     def make_entry (self, pn_entries, speeddials, ice_entries,
0434                     entry_num0, entry_num1,
0435                     pb_entry, data, ring_pathf,
0436                     rt_index, picid_pathf, wp_index):
0437         """ Create a pbfileentry from a bitpim phonebook entry """
0438         new_entry = self.protocolclass.pbfileentry(entry_tag=self.protocolclass.PB_ENTRY_SOR)
0439         # entry IDs
0440         new_entry.entry_number0 = entry_num0
0441         new_entry.entry_number1 = entry_num1
0442 
0443         for key in pb_entry:
0444             if key in ('emails', 'numbertypes'):
0445                 l = getattr (new_entry, key)
0446                 for item in pb_entry[key]:
0447                     l.append(item)
0448             elif key == 'numbers':
0449                 l = getattr (new_entry, 'numberindices')
0450                 for i in range(0, self.protocolclass.NUMPHONENUMBERS):
0451                     new_pn_id = len (pn_entries.items)
0452                     if new_pn_id == self.protocolclass.NUMPHONENUMBERENTRIES:
0453                         # this state should not be possible. should this raise an exception?
0454                         self.log ("Maximum number of phone numbers reached")
0455                         break
0456 
0457                     try:
0458                         pn_entries.items.append(self.make_pn_entry (pb_entry[key][i],pb_entry['numbertypes'][i], new_pn_id, i, entry_num0))
0459                         l.append (new_pn_id)
0460                     except:
0461                         l.append (0xffff)
0462             elif key == 'speeddials':
0463                 for _sd,_num_type in zip(pb_entry['speeddials'], pb_entry['numbertypes']):
0464                     if _sd is not None:
0465                         speeddials[_sd]={ 'entry': entry_num0,
0466                                           'type': _num_type }
0467             elif key == 'ice':
0468                 # In Case of Emergency
0469                 _ice = pb_entry['ice']
0470                 if _ice is not None and len(_ice) > 0:
0471                     _ice_entry = _ice[0]['iceindex']
0472                     ice_entries.items[_ice_entry] = self.make_ice_entry (_ice_entry, entry_num0)
0473             elif key == 'ringtone':
0474                 new_entry.ringtone = self._findmediainindex(data['ringtone-index'], pb_entry['ringtone'], pb_entry['name'], 'ringtone')
0475                 try:
0476                     _filename = rt_index[new_entry.ringtone]['filename']
0477                     ring_pathf.items.append(self.protocolclass.PathIndexEntry(pathname=_filename))
0478                     new_entry.ringtone = 0x64
0479                 except:
0480                     ring_pathf.items.append(self.protocolclass.PathIndexEntry())
0481             elif key == 'wallpaper':
0482                 new_entry.wallpaper = self._findmediainindex(data['wallpaper-index'], pb_entry['wallpaper'], pb_entry['name'], 'wallpaper')
0483                 try:
0484                     _filename = wp_index[new_entry.wallpaper]['filename']
0485                     picid_pathf.items.append(self.protocolclass.PathIndexEntry(pathname=_filename))
0486                     new_entry.wallpaper = 0x64
0487                 except:
0488                     picid_pathf.items.append(self.protocolclass.PathIndexEntry())
0489             elif key in new_entry.getfields():
0490                 setattr (new_entry, key, pb_entry[key])
0491 
0492         return new_entry
0493 
0494 
0495     # Calendar stuff------------------------------------------------------------
0496     def _scheduleextras(self, data, fwversion):
0497         data.serial_number = '000000d1-00000000-00000000-' + fwversion
0498         data.unknown3 = 0x01fc
0499 
0500 
0501     # ringtones and wallpapers stuff--------------------------------------------
0502     def savewallpapers(self, results, merge):
0503         results['rebootphone']=True
0504         return self.savemedia('wallpapers', 'wallpaper-index',
0505                               self.wallpaperlocations, results, merge,
0506                               self.getwallpaperindices, True)
0507             
0508     def saveringtones(self, results, merge):
0509         # Let the phone rebuild the index file, just need to reboot
0510         results['rebootphone']=True
0511         return self.savemedia('ringtone', 'ringtone-index',
0512                               self.ringtonelocations, results, merge,
0513                               self.getringtoneindices, True)
0514 
0515     # SMS Stuff-----------------------------------------------------------------
0516     # Again, this is very similar to the 8800, just make it work with the 9100
0517     def getindex(self, filename):
0518         try:
0519             return self.readobject(filename,
0520                                    self.protocolclass.indexfile,
0521                                    logtitle='Reading index file',
0522                                    uselocalfs=DEBUG2).items
0523         except:
0524             return []
0525 
0526     def _readsms(self):
0527         res={}
0528         # The Voyager and Venus use index files to keep track of SMS messages
0529         for item in self.getindex(self.protocolclass.drafts_index):
0530                 sf=self.readobject(item.filename,
0531                                    self.protocolclass.sms_saved,
0532                                    logtitle='SMS draft item',
0533                                    uselocalfs=DEBUG2)
0534                 # The 9100 only has draft messages (saved outgoing messaged)
0535                 entry=self._getoutboxmessage(sf.outbox)
0536                 entry.folder=entry.Folder_Saved
0537                 res[entry.id]=entry
0538         for item in self.getindex(self.protocolclass.inbox_index):
0539                 sf=self.readobject(item.filename,
0540                                    self.protocolclass.sms_in,
0541                                    logtitle='SMS inbox item',
0542                                    uselocalfs=DEBUG2)
0543                 entry=self._getinboxmessage(sf)
0544                 res[entry.id]=entry
0545         for item in self.getindex(self.protocolclass.outbox_index):
0546                 sf=self.readobject(item.filename,
0547                                    self.protocolclass.sms_out,
0548                                    logtitle='SMS outbox item',
0549                                    uselocalfs=DEBUG2)
0550                 entry=self._getoutboxmessage(sf)
0551                 res[entry.id]=entry
0552         return res 
0553 
0554     def _getinboxmessage(self, sf):
0555         entry=sms.SMSEntry()
0556         entry.folder=entry.Folder_Inbox
0557         entry.datetime="%d%02d%02dT%02d%02d%02d" % (sf.GPStime)
0558         entry._from=sf.sender if sf.sender else sf.sender_name
0559         entry.subject=sf.subject
0560         entry.locked=sf.locked
0561         if sf.priority==0:
0562             entry.priority=sms.SMSEntry.Priority_Normal
0563         else:
0564             entry.priority=sms.SMSEntry.Priority_High
0565         entry.read=sf.read
0566         txt=""
0567         _decode_func=self._get_text_from_sms_msg_with_header if \
0568                       sf.msgs[1].msg_length else \
0569                       self._get_text_from_sms_msg_without_header
0570         for _entry in sf.msgs:
0571             if _entry.msg_length:
0572                 txt+=_decode_func(_entry.msg_data.msg, _entry.msg_length)
0573         entry.text=unicode(txt, errors='ignore')
0574         entry.callback=sf.callback
0575         return entry
0576 
0577 
0578 #-------------------------------------------------------------------------------
0579 parentprofile=com_lgvx8550.Profile
0580 class Profile(parentprofile):
0581     protocolclass=Phone.protocolclass
0582     serialsname=Phone.serialsname
0583 
0584     BP_Calendar_Version=3
0585     phone_manufacturer='LG Electronics Inc'
0586     phone_model='VX9100'
0587 
0588     WALLPAPER_WIDTH=320
0589     WALLPAPER_HEIGHT=240
0590     # outside LCD: 160x64
0591 
0592     imageorigins={}
0593     imageorigins.update(common.getkv(parentprofile.stockimageorigins, "images"))
0594     imageorigins.update(common.getkv(parentprofile.stockimageorigins, "video"))
0595     imageorigins.update(common.getkv(parentprofile.stockimageorigins, "images(sd)"))
0596     imageorigins.update(common.getkv(parentprofile.stockimageorigins, "video(sd)"))
0597     def GetImageOrigins(self):
0598         return self.imageorigins
0599 
0600 
0601 ##    ringtoneorigins=('ringers', 'sounds', 'sounds(sd)',' music', 'music(sd)')
0602 ##    excluded_ringtone_origins=('sounds', 'sounds(sd)', 'music', 'music(sd)')
0603     ringtoneorigins=('ringers', 'sounds', 'sounds(sd)')
0604     excluded_ringtone_origins=('sounds', 'sounds(sd)')
0605 
0606     # our targets are the same for all origins
0607     imagetargets={}
0608     imagetargets.update(common.getkv(parentprofile.stockimagetargets, "wallpaper",
0609                                       {'width': 320, 'height': 215, 'format': "JPEG"}))
0610     imagetargets.update(common.getkv(parentprofile.stockimagetargets, "outsidelcd",
0611                                       {'width': 160, 'height': 64, 'format': "JPEG"}))
0612 
0613     def GetTargetsForImageOrigin(self, origin):
0614         return self.imagetargets
0615 
0616     _supportedsyncs=(
0617         ('phonebook', 'read', None),   # all phonebook reading
0618         ('calendar', 'read', None),    # all calendar reading
0619         ('wallpaper', 'read', None),   # all wallpaper reading
0620         ('ringtone', 'read', None),    # all ringtone reading
0621         ('call_history', 'read', None),# all call history list reading
0622         ('sms', 'read', None),         # all SMS list reading
0623         ('memo', 'read', None),        # all memo list reading
0624         ('phonebook', 'write', 'OVERWRITE'),  # only overwriting phonebook
0625         ('calendar', 'write', 'OVERWRITE'),   # only overwriting calendar
0626         ('wallpaper', 'write', 'MERGE'),      # merge and overwrite wallpaper
0627 ##        ('wallpaper', 'write', 'OVERWRITE'),
0628         ('ringtone', 'write', 'MERGE'),       # merge and overwrite ringtone
0629 ##        ('ringtone', 'write', 'OVERWRITE'),
0630 ####        ('sms', 'write', 'OVERWRITE'),        # all SMS list writing
0631         ('memo', 'write', 'OVERWRITE'),       # all memo list writing
0632 ####        ('playlist', 'read', 'OVERWRITE'),
0633 ####        ('playlist', 'write', 'OVERWRITE'),
0634         )
0635 
0636     def normalisegroups(self, helper, data):
0637         "Assigns groups based on category data"
0638 
0639         pad=[]
0640         keys=data['groups'].keys()
0641         keys.sort()
0642         for k in keys:
0643                 if k: # ignore key 0 which is 'No Group'
0644                     name=data['groups'][k]['name']
0645                     pad.append(name)
0646 
0647         groups=helper.getmostpopularcategories(self.protocolclass.MAX_PHONEBOOK_GROUPS, data['phonebook'], ["No Group"], 32, pad)
0648 
0649         # alpha sort
0650         groups.sort()
0651 
0652         # newgroups
0653         newgroups={}
0654 
0655         # put in No group
0656         newgroups[0]={'name': 'No Group', 'user_added': 0}
0657 
0658         # populate
0659         for name in groups:
0660             # existing entries remain unchanged
0661             if name=="No Group": continue
0662             key,value=self._getgroup(name, data['groups'])
0663             if key is not None and key!=0:
0664                 newgroups[key]=value
0665         # new entries get whatever numbers are free
0666         for name in groups:
0667             key,value=self._getgroup(name, newgroups)
0668             if key is None:
0669                 for key in range(1,100000):
0670                     if key not in newgroups:
0671                         newgroups[key]={'name': name, 'user_added': 1}
0672                         break
0673                        
0674         # yay, done
0675         if data['groups']!=newgroups:
0676             data['groups']=newgroups
0677             data['rebootphone']=True
0678 
0679     def convertphonebooktophone(self, helper, data):
0680         """Converts the data to what will be used by the phone
0681 
0682         @param data: contains the dict returned by getfundamentals
0683                      as well as where the results go"""
0684         results={}
0685 
0686         self.normalisegroups(helper, data)
0687 
0688         for pbentry in data['phonebook']:
0689             if len(results)==self.protocolclass.NUMPHONEBOOKENTRIES:
0690                 break
0691             e={} # entry out
0692             entry=data['phonebook'][pbentry] # entry in
0693             try:
0694                 # serials
0695                 serial1=helper.getserial(entry.get('serials', []), self.serialsname, data['uniqueserial'], 'serial1', 0)
0696                 serial2=helper.getserial(entry.get('serials', []), self.serialsname, data['uniqueserial'], 'serial2', serial1)
0697 
0698                 e['serial1']=serial1
0699                 e['serial2']=serial2
0700                 for ss in entry["serials"]:
0701                     if ss["sourcetype"]=="bitpim":
0702                         e['bitpimserial']=ss
0703                 assert e['bitpimserial']
0704 
0705                 # name
0706                 e['name']=helper.getfullname(entry.get('names', []),1,1,32)[0]
0707 
0708                 # ice
0709                 e['ice']=entry.get('ice', None)
0710 
0711                 # categories/groups
0712                 cat=helper.makeone(helper.getcategory(entry.get('categories', []),0,1,32), None)
0713                 if cat is None:
0714                     e['group']=0
0715                 else:
0716                     key,value=self._getgroup(cat, data['groups'])
0717                     if key is not None:
0718                         e['group']=key
0719                     else:
0720                         # sorry no space for this category
0721                         e['group']=0
0722 
0723                 # email addresses
0724                 emails=helper.getemails(entry.get('emails', []) ,0,self.protocolclass.NUMEMAILS,48)
0725                 e['emails']=helper.filllist(emails, self.protocolclass.NUMEMAILS, "")
0726 
0727                 # phone numbers
0728                 # there must be at least one email address or phonenumber
0729                 minnumbers=1
0730                 if len(emails): minnumbers=0
0731                 numbers=helper.getnumbers(entry.get('numbers', []),minnumbers,self.protocolclass.NUMPHONENUMBERS)
0732                 e['numbertypes']=[]
0733                 e['numbers']=[]
0734                 e['speeddials']=[]
0735                 for numindex in range(len(numbers)):
0736                     num=numbers[numindex]
0737                     # deal with type
0738                     b4=len(e['numbertypes'])
0739                     type=num['type']
0740                     for i,t in enumerate(self.protocolclass.numbertypetab):
0741                         if type==t:
0742                             # some voodoo to ensure the second home becomes home2
0743                             if i in e['numbertypes'] and t[-1]!='2':
0744                                 type+='2'
0745                                 continue
0746                             e['numbertypes'].append(i)
0747                             break
0748                         if t=='none': # conveniently last entry
0749                             e['numbertypes'].append(i)
0750                             break
0751                     if len(e['numbertypes'])==b4:
0752                         # we couldn't find a type for the number
0753                         helper.add_error_message('Number %s (%s/%s) not supported and ignored.'%
0754                                                  (num['number'], e['name'], num['type']))
0755                         continue 
0756                     # deal with number
0757                     number=self.phonize(num['number'])
0758                     if len(number)==0:
0759                         # no actual digits in the number
0760                         continue
0761                     if len(number)>24: # get this number from somewhere sensible
0762                         # ::TODO:: number is too long and we have to either truncate it or ignore it?
0763                         number=number[:24] # truncate for moment
0764                     e['numbers'].append(number)
0765                     # deal with speed dial
0766                     sd=num.get("speeddial", None)
0767                     if sd is not None and \
0768                        sd>=self.protocolclass.FIRSTSPEEDDIAL and \
0769                        sd<=self.protocolclass.LASTSPEEDDIAL:
0770                         e['speeddials'].append(sd)
0771                     else:
0772                         e['speeddials'].append(None)
0773 
0774                 if len(e['numbers'])<minnumbers:
0775                     # we couldn't find any numbers
0776                     # for this entry, so skip it, entries with no numbers cause error
0777                     helper.add_error_message("Name: %s. No suitable numbers or emails found" % e['name'])
0778                     continue 
0779                 e['numbertypes']=helper.filllist(e['numbertypes'], self.protocolclass.NUMPHONENUMBERS, 0)
0780                 e['numbers']=helper.filllist(e['numbers'], self.protocolclass.NUMPHONENUMBERS, "")
0781                 e['speeddials']=helper.filllist(e['speeddials'], self.protocolclass.NUMPHONENUMBERS, None)
0782 
0783                 # ringtones, wallpaper
0784                 e['ringtone']=helper.getringtone(entry.get('ringtones', []), 'call', None)
0785                 e['wallpaper']=helper.getwallpaper(entry.get('wallpapers', []), 'call', None)
0786 
0787                 results[pbentry]=e
0788                 
0789             except helper.ConversionFailed:
0790                 continue
0791 
0792         data['phonebook']=results
0793         return data
0794     # applicable fields for this model
0795     field_color_data={
0796         'phonebook': {
0797             'name': {
0798                 'first': 1, 'middle': 1, 'last': 1, 'full': 1,
0799                 'nickname': 0, 'details': 1 },
0800             'number': {
0801                 'type': 5, 'speeddial': 5, 'number': 5, 'details': 5 },
0802             'email': 2,
0803             'address': {
0804                 'type': 0, 'company': 0, 'street': 0, 'street2': 0,
0805                 'city': 0, 'state': 0, 'postalcode': 0, 'country': 0,
0806                 'details': 0 },
0807             'url': 0,
0808             'memo': 0,
0809             'category': 1,
0810             'wallpaper': 1,
0811             'ringtone': 2,
0812             'storage': 0,
0813             'secret': 0,
0814             'ICE': 1,
0815             },
0816         'calendar': {
0817             'description': True, 'location': False, 'allday': False,
0818             'start': True, 'end': True, 'priority': False,
0819             'alarm': True, 'vibrate': True,
0820             'repeat': True,
0821             'memo': False,
0822             'category': False,
0823             'wallpaper': False,
0824             'ringtone': True,
0825             },
0826         'memo': {
0827             'subject': True,
0828             'date': True,
0829             'secret': False,
0830             'category': False,
0831             'memo': True,
0832             },
0833         'todo': {
0834             'summary': False,
0835             'status': False,
0836             'due_date': False,
0837             'percent_complete': False,
0838             'completion_date': False,
0839             'private': False,
0840             'priority': False,
0841             'category': False,
0842             'memo': False,
0843             },
0844         }
0845 

Generated by PyXR 0.9.4