PyXR

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



0001 ### BITPIM
0002 ###
0003 ### Copyright (C) 2004 Joe Pham <djpham@netzero.com>
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_samsungscha650.py 4365 2007-08-17 21:11:59Z djpham $
0009 
0010 
0011 """Communicate with a Samsung SCH-A650"""
0012 
0013 # lib modules
0014 import copy
0015 import re
0016 import sha
0017 
0018 # my modules
0019 
0020 import common
0021 import commport
0022 import com_brew
0023 import com_samsung
0024 import com_phone
0025 import conversions
0026 import fileinfo
0027 import memo
0028 import nameparser
0029 import p_samsungscha650
0030 import prototypes
0031 
0032 import call_history
0033 
0034 #-------------------------------------------------------------------------------
0035 class Phone(com_samsung.Phone):
0036 
0037     "Talk to the Samsung SCH-A650 Cell Phone"
0038 
0039     desc="SCH-A650"
0040     serialsname='scha650'
0041     protocolclass=p_samsungscha650
0042     parent_phone=com_samsung.Phone
0043 
0044     __groups_range=xrange(5)
0045     __phone_entries_range=xrange(1,501)
0046     __pb_max_entries=25
0047     __pb_max_speeddials=500
0048     __pb_entry=0
0049     __pb_mem_loc=1
0050     __pb_group=2
0051     __pb_ringtone=3
0052     __pb_name=4
0053     __pb_speed_dial=5
0054     __pb_home_num=7
0055     __pb_office_num=9
0056     __pb_mobile_num=11
0057     __pb_pager_num=13
0058     __pb_fax_num=15
0059     __pb_alias=17
0060     __pb_email=21
0061     __pb_four=22
0062     __pb_blanks=(19, 20)
0063     __pb_date_time_stamp=24
0064     __pb_numbers= ({'home': __pb_home_num},
0065                     {'office': __pb_office_num},
0066                     {'cell': __pb_mobile_num},
0067                     {'pager': __pb_pager_num},
0068                     {'fax': __pb_fax_num})
0069     __pb_max_name_len=22
0070     __pb_max_number_len=32
0071     __pb_max_emails=1
0072 
0073     # 'type name', 'type index name', 'origin', 'dir path', 'max file name length', 'max file name count'    
0074     __ringtone_info=('ringtone', 'ringtone-index', 'ringtone', 'user/sound/ringer', 17, 20)
0075     __wallpaper_info=('wallpapers', 'wallpaper-index', 'images', 'nvm/brew/shared', 17, 10)
0076         
0077     def __init__(self, logtarget, commport):
0078 
0079         "Calls all the constructors and sets initial modes"
0080         com_samsung.Phone.__init__(self, logtarget, commport)
0081         self.mode=self.MODENONE
0082 
0083     def getfundamentals(self, results):
0084 
0085         """Gets information fundamental to interopating with the phone and UI.
0086 
0087         Currently this is:
0088 
0089           - 'uniqueserial'     a unique serial number representing the phone
0090           - 'groups'           the phonebook groups
0091           - 'wallpaper-index'  map index numbers to names
0092           - 'ringtone-index'   map index numbers to ringtone names
0093 
0094         This method is called before we read the phonebook data or before we
0095         write phonebook data.
0096         """
0097         
0098         self.setmode(self.MODEPHONEBOOK)
0099 
0100         # use a hash of ESN and other stuff (being paranoid)
0101 
0102         self.log("Retrieving fundamental phone information")
0103         self.log("Reading phone serial number")
0104         results['uniqueserial']=sha.new(self.get_esn()).hexdigest()
0105 
0106         # now read groups
0107 
0108         self.log("Reading group information")
0109         g=self.get_groups(self.__groups_range)
0110         groups={}
0111         for i, g_i in enumerate(g):
0112             if len(g_i):
0113                 groups[i]={ 'name': g_i }
0114         results['groups']=groups
0115 
0116         # getting rintone-index
0117         self.setmode(self.MODEBREW)
0118         rt_index=RingtoneIndex(self)
0119         results['ringtone-index']=rt_index.get()
0120         
0121         # getting wallpaper-index
0122         img_index=ImageIndex(self)
0123         results['wallpaper-index']=img_index.get()
0124         
0125         self.setmode(self.MODEMODEM)
0126         self.log("Fundamentals retrieved")
0127 
0128         return results
0129 
0130     def getphonebook(self,result):
0131         """Reads the phonebook data.  The L{getfundamentals} information will
0132         already be in result."""
0133         self.setmode(self.MODEBREW)
0134         pb=PhoneBook(self)
0135         pb.read()
0136         pb_book=pb.get_dict(result)
0137         result['phonebook']=pb_book
0138         self.setmode(self.MODEMODEM)
0139         return pb_book
0140 
0141     def savephonebook(self, data):
0142         "Saves out the phonebook"
0143 
0144         pb_book=data['phonebook']
0145         pb_groups=data['groups']
0146         ringtone_index=data.get('ringtone-index', {})
0147         self.log('Validating phonebook entries.')
0148         del_entries=[]
0149         for k in pb_book:
0150             if not self.__validate_entry(pb_book[k], pb_groups, ringtone_index):
0151                 self.log('Invalid entry, entry will be not be sent.')
0152                 del_entries.append(k)
0153         for k in del_entries:
0154             self.log('Deleting entry '+\
0155                      nameparser.getfullname(pb_book[k]['names'][0]))
0156             del pb_book[k]
0157         self._has_duplicate_speeddial(pb_book)
0158         self.log('All entries validated')
0159 
0160         pb_locs=[False]*(len(self.__phone_entries_range)+1)
0161         pb_mem=[False]*len(pb_locs)
0162 
0163         # get existing phonebook from the phone
0164         self.log("Getting current phonebook from the phone")
0165         self.setmode(self.MODEBREW)
0166         phone_book=PhoneBook(self)
0167         phone_book.read()
0168         current_pb=phone_book.get_dict(data)
0169         self.setmode(self.MODEMODEM)
0170     
0171         # check and adjust for speeddial changes
0172         self.log("Processing speeddial data")
0173         for k in pb_book:
0174             self._update_speeddial(pb_book[k])
0175 
0176         # check for deleted entries and delete them
0177         self.setmode(self.MODEPHONEBOOK)
0178         self.log("Processing deleted entries")
0179 
0180         for k1 in current_pb:
0181             s1=current_pb[k1]['serials'][0]['serial1']
0182             found=False
0183             for k2 in pb_book:
0184                 if self._same_serial1(s1, pb_book[k2]):
0185                     found=True
0186                     break
0187             if found:
0188                 pb_locs[int(current_pb[k1]['serials'][0]['serial1'])]=True
0189                 pb_mem[int(current_pb[k1]['serials'][0]['serial2'])]=True
0190             else:
0191                 self.log("Deleted item: "+\
0192                          nameparser.getfullname(current_pb[k1]['names'][0]))
0193                 # delete the entries from data and the phone
0194                 self.progress(0, 10, "Deleting "+\
0195                               nameparser.getfullname(\
0196                                   current_pb[k1]['names'][0]))
0197                 self._del_phone_entry(current_pb[k1])
0198         mem_idx, loc_idx = self.__pb_max_speeddials, 1
0199         
0200         # check for new entries & update serials
0201         self.log("Processing new & updated entries")
0202         serials_update=[]
0203         progresscur, progressmax=1,len(pb_book)
0204         for k in pb_book:
0205             if progresscur>len(self.__phone_entries_range):
0206                 self.log('Max phone entries exceeded: '+str(progresscur))
0207                 break
0208             e=pb_book[k]
0209             if not self._has_serial1(e):
0210                 while pb_locs[loc_idx]:
0211                     loc_idx += 1
0212                 pb_locs[loc_idx]=True
0213                 sd=self._get_speeddial(e)
0214                 if sd:
0215                     mem_index=sd
0216                     pb_mem[sd]=True
0217                 else:
0218                     while pb_mem[mem_idx]:
0219                         mem_idx -= 1
0220                     pb_mem[mem_idx]=True
0221                     mem_index=mem_idx
0222                     self._set_speeddial(e, mem_idx)
0223                 s1={ 'sourcetype': self.serialsname,
0224                           'sourceuniqueid': data['uniqueserial'],
0225                           'serial1': `loc_idx`,
0226                           'serial2': `mem_index` }
0227                 e['serials'].append(s1)
0228                 self.log("New entries: Name: "+\
0229                          nameparser.getfullname(e['names'][0])+\
0230                          ", s1: "+`loc_idx`+", s2: "+`mem_index`)
0231                 serials_update.append((self._bitpim_serials(e), s1))
0232             self.progress(progresscur, progressmax, "Updating "+\
0233                           nameparser.getfullname(e['names'][0]))
0234             if not self._write_phone_entry(e, pb_groups, ringtone_index,
0235                                            phone_book):
0236                 self.log("Failed to save entry: "+\
0237                          nameparser.getfullname(e['names'][0]))
0238             progresscur += 1
0239 
0240         data["serialupdates"]=serials_update
0241         self.log("Done")
0242         self.setmode(self.MODEMODEM)
0243         return data
0244 
0245     # validate a phonebook entry, return True if good, False otherwise
0246     def __validate_entry(self, pb_entry, pb_groups, ringtone_index):
0247         try:
0248             # validate name & alias
0249             name=nameparser.getfullname(pb_entry['names'][0]).replace('"', '')
0250             if len(name)>self.__pb_max_name_len:
0251                 name=name[:self.__pb_max_name_len]
0252             pb_entry['names'][0].setdefault('full', name)
0253             if pb_entry['names'][0].has_key('nickname'):
0254                 name=re.sub('[,"]', '', pb_entry['names'][0]['nickname'])
0255                 if len(name)>self.__pb_max_name_len:
0256                     name=name[:self.__pb_max_name_len]
0257                 if pb_entry['names'][0]['nickname']!=name:
0258                     pb_entry['names'][0]['nickname']=name
0259             # validate numbers
0260             has_number_or_email=False
0261             if pb_entry.has_key('numbers'):
0262                 for n in pb_entry['numbers']:
0263                     num=self.phonize(n['number'])
0264                     if len(num)>self.__pb_max_number_len:
0265                         num=num[:self.__pb_max_number_len]
0266                     if num != n['number']:
0267                         self.log('Updating number from '+n['number']+' to '+num)
0268                         n['number']=num
0269                     try:
0270                         self._get_number_type(n['type'])
0271                     except:
0272                         self.log(n['number']+': setting type to home.')
0273                         n['type']='home'
0274                     has_number_or_email=True
0275             # validate emails
0276             if pb_entry.has_key('emails'):
0277                 if len(pb_entry['emails'])>self.__pb_max_emails:
0278                     self.log(name+': Each entry can only have %s emails.  The rest will be ignored.'%str(self.__pb_max_emails))
0279                 email=pb_entry['emails'][0]['email'].replace('"', '')
0280                 if len(email)>self.__pb_max_number_len:
0281                     email=email[:self.__pb_max_number_len]
0282                 if email!=pb_entry['emails'][0]['email']:
0283                     pb_entry['emails'][0]['email']=email
0284                 has_number_or_email=True
0285             if not has_number_or_email:
0286                 self.log(name+': Entry has no numbers or emails')
0287                 # return False so this entry can be deleted from the dict
0288                 return False
0289             # validate groups
0290             found=False
0291             if pb_entry.has_key('categories') and len(pb_entry['categories']):
0292                 pb_cat=pb_entry['categories'][0]['category']
0293                 for k in pb_groups:
0294                     if pb_groups[k]['name']==pb_cat:
0295                         found=True
0296                         break
0297             if not found:
0298                 self.log(name+': category set to '+pb_groups[0]['name'])
0299                 pb_entry['categories']=[{'category': pb_groups[0]['name']}]
0300             # validate ringtones
0301             found=False
0302             if pb_entry.has_key('ringtones') and len(pb_entry['ringtones']):
0303                 pb_rt=pb_entry['ringtones'][0]['ringtone']
0304                 # can only set to builtin-ringtone
0305                 for k, rt in ringtone_index.items():
0306                     if pb_rt==rt['name']:
0307                         found=True
0308                         break
0309             if not found:
0310                 rt=ringtone_index[0]['name']
0311                 self.log(name+': ringtone set to '+rt)
0312                 pb_entry['ringtones']=[{'ringtone': rt,
0313                                         'use': 'call' }]
0314             # everything's cool
0315             return True
0316         except:
0317             raise
0318         
0319     def _has_duplicate_speeddial(self, pb_book):
0320         b=[False]*(self.__pb_max_speeddials+1)
0321         for k in pb_book:
0322             try:
0323                 for  k1, kk in enumerate(pb_book[k]['numbers']):
0324                     sd=kk['speeddial']
0325                     if sd and b[sd]:
0326                         # speed dial is in used, remove this one
0327                         del pb_book[k]['numbers'][k1]['speeddial']
0328                         self.log('speeddial %d exists, deleted'%sd)
0329                     else:
0330                         b[sd]=True
0331             except:
0332                 pass
0333         return False
0334 
0335     def _update_speeddial(self, pb_entry):
0336         try:
0337             s=self._my_serials(pb_entry)
0338             s1=int(s['serial2'])
0339             sd=self._get_speeddial(pb_entry)
0340             if not sd:
0341                 # speed dial not set, set it to current mem slot
0342                 self._set_speeddial(pb_entry, s1)
0343             elif sd!=s1:
0344                 # speed dial set to a different slot, mark it
0345                 self._del_my_serials(pb_entry)
0346         except:
0347             pass
0348 
0349     def _get_speeddial(self, pb_entry):
0350         n=pb_entry.get('numbers', [])
0351         for k in n:
0352             try:
0353                if k['speeddial']:
0354                    return k['speeddial']
0355             except:
0356                 pass
0357         return 0
0358 
0359     def _set_speeddial(self, pb_entry, sd):
0360         if not pb_entry.has_key('numbers'):
0361             # no numbers key, just return
0362             return
0363         for k in pb_entry['numbers']:
0364             if k.has_key('speeddial'):
0365                 k['speeddial']=sd
0366                 return
0367         pb_entry['numbers'][0]['speeddial']=sd
0368 
0369     def _del_phone_entry(self, pb_entry):
0370         try:
0371             return self.save_phone_entry(self._my_serials(pb_entry)['serial1'])
0372         except:
0373             return False
0374 
0375     def _same_serial1(self, s1, pb_entry):
0376         for k in pb_entry['serials']:
0377             if k['sourcetype']==self.serialsname and k.has_key('serial1'):
0378                 return k['serial1']==s1
0379         return False
0380 
0381     def _has_serial1(self, pb_entry):
0382         for k in pb_entry['serials']:
0383             if k['sourcetype']==self.serialsname and k.has_key('serial1'):
0384                 return True
0385         return False
0386 
0387     def _bitpim_serials(self, pb_entry):
0388         for k in pb_entry['serials']:
0389             if k['sourcetype']=="bitpim":
0390                 return k
0391         return {}
0392 
0393     def _del_my_serials(self, pb_entry):
0394         for k in range(len(pb_entry['serials'])):
0395             if pb_entry['serials'][k]['sourcetype']==self.serialsname:
0396                 del pb_entry['serials'][k]
0397                 return
0398 
0399     def _my_serials(self, pb_entry):
0400         for k in pb_entry['serials']:
0401             if k['sourcetype']==self.serialsname:
0402                 return k
0403         return {}
0404 
0405     def _get_number_type(self, type):
0406         n=self.__pb_numbers
0407         for k in range(len(n)):
0408             if n[k].has_key(type):
0409                 return k, n[k][type]
0410         raise common.IntegrityCheckFailed(self.desc, "Invalid Number Type")
0411 
0412 
0413     def _write_phone_entry(self, pb_entry, groups, ringtone_index, phone_book):
0414 
0415         # setting up a list to send to the phone, all fields preset to '0'
0416         e=['0']*self.__pb_max_entries
0417 
0418         # setting the entry # and memory location #
0419         serials=self._my_serials(pb_entry)
0420         e[self.__pb_entry]=serials['serial1']
0421         e[self.__pb_mem_loc]=serials['serial2']
0422 
0423         # groups/categories
0424         grp=0
0425         try:
0426             grp_name=pb_entry['categories'][0]['category']
0427             for k in range(len(groups)):
0428                 if groups[k]['name']==grp_name:
0429                     grp=k
0430                     break
0431 
0432         except:
0433             # invalid group or no group specified, default to group 0
0434             grp, pb_entry['categories']=0, [{'category': groups[0]['name']}]
0435         e[self.__pb_group]=`grp`
0436 
0437         # ringtones
0438         e[self.__pb_ringtone]='0'   # default to Inactive
0439         try:
0440             rt=pb_entry['ringtones'][0]['ringtone']
0441             for k, n in ringtone_index.items():
0442                 if rt==n['name']:
0443                     e[self.__pb_ringtone]=`k`
0444                     break
0445         except:
0446             pass
0447 
0448         # name & alias
0449         e[self.__pb_name]='"'+nameparser.getfullname(pb_entry['names'][0])+'"'
0450         nick_name=''
0451         try:
0452             nick_name=pb_entry['names'][0]['nickname']
0453         except:
0454             pass
0455 
0456         e[self.__pb_alias]=nick_name
0457         if len(nick_name):
0458             e[self.__pb_alias+1]='0'
0459         else:
0460             e[self.__pb_alias+1]=''
0461 
0462         # numbers & speed dial
0463 
0464         # preset to empty
0465 
0466         for k in range(len(self.__pb_numbers)):
0467             for kk in self.__pb_numbers[k]:
0468                 e[self.__pb_numbers[k][kk]]=''
0469                 e[self.__pb_numbers[k][kk]+1]=''
0470         speed_dial='0'
0471         n=pb_entry.get('numbers', [])
0472         for k in range(len(n)):
0473             try:
0474                 nk=n[k]
0475                 kkk, kk=self._get_number_type(nk['type'])
0476             except:
0477                 # invalid type, default to 'home'
0478                 nk['type']='home'
0479                 kkk, kk=0, self.__pb_home_num
0480             e[kk],e[kk+1]=self.phonize(nk['number']),'0'
0481             try:
0482                 if nk['speeddial']:
0483                     speed_dial=`kkk`
0484             except:
0485                 pass
0486         e[self.__pb_speed_dial]=speed_dial
0487 
0488         # email
0489         email=''
0490         try:
0491             email=pb_entry['emails'][0]['email']
0492         except:
0493             pass
0494 
0495         e[self.__pb_email]='"'+email+'"'
0496         e[self.__pb_four]='4'
0497         for k in self.__pb_blanks:
0498             e[k]=''
0499 
0500         e[self.__pb_date_time_stamp]=self.get_time_stamp()
0501 
0502         # final check to determine if this entry has changed.
0503         # if it has not then do nothing and just return
0504         ee=self.get_phone_entry(int(e[self.__pb_entry]),
0505                                 self.__pb_alias, self.__pb_max_entries)
0506         if len(ee)==self.__pb_max_entries:
0507             # DSV took the " out, need to put them back in for comparison
0508             ee[self.__pb_name]='"'+ee[self.__pb_name]+'"'
0509             ee[self.__pb_email]='"'+ee[self.__pb_email]+'"'
0510             # set the correct ringtone index
0511             ee[self.__pb_ringtone]=str(phone_book.get_ringtone(\
0512                 int(e[self.__pb_mem_loc])))
0513             k=self.__pb_max_entries-2
0514             if e[0:k]==ee[0:k]:
0515                 return True
0516         return self.save_phone_entry('0,'+','.join(e))
0517 
0518     def getringtones(self, result):
0519         self.setmode(self.MODEBREW)
0520         m=FileEntries(self, self.__ringtone_info)
0521         rt_info=RingtoneIndex(self).get_download_info()
0522         r=m.get_media(result, rt_info)
0523         self.setmode(self.MODEMODEM)
0524         return r
0525 
0526     def saveringtones(self, result, merge):
0527         self.setmode(self.MODEBREW)
0528         m=FileEntries(self, self.__ringtone_info)
0529         result['rebootphone']=1 # So we end up back in AT mode
0530         r=m.save_media(result, RingtoneIndex(self).get_download_info())
0531         self.setmode(self.MODEMODEM)
0532         return r
0533 
0534     def getwallpapers(self, result):
0535         self.setmode(self.MODEBREW)
0536         m=FileEntries(self, self.__wallpaper_info)
0537         img_info=ImageIndex(self).get_download_info()
0538         r=m.get_media(result, img_info)
0539         self.setmode(self.MODEMODEM)
0540         return r
0541 
0542     def savewallpapers(self, result, merge):
0543         self.setmode(self.MODEBREW)
0544         m=FileEntries(self, self.__wallpaper_info)
0545         r=m.save_media(result, ImageIndex(self).get_download_info())
0546         result['rebootphone']=1
0547         self.setmode(self.MODEMODEM)
0548         return r
0549 
0550     getmemo=parent_phone._getmemo
0551     savememo=parent_phone._savememo
0552 
0553     gettodo=parent_phone._gettodo
0554     savetodo=parent_phone._savetodo
0555 
0556     getsms=parent_phone._getsms
0557     savesms=parent_phone._savesms
0558 
0559     getphoneinfo=parent_phone._getphoneinfo
0560 
0561     getmedia=None
0562 
0563 #-------------------------------------------------------------------------------
0564 class Profile(com_samsung.Profile):
0565 
0566     serialsname='scha650'
0567 
0568     WALLPAPER_WIDTH=128
0569     WALLPAPER_HEIGHT=160
0570     MAX_WALLPAPER_BASENAME_LENGTH=17
0571     WALLPAPER_FILENAME_CHARS="abcdefghijklmnopqrstuvwxyz0123456789_*[]=<>;|?:% ."
0572     WALLPAPER_CONVERT_FORMAT="png"
0573    
0574     MAX_RINGTONE_BASENAME_LENGTH=17
0575     RINGTONE_FILENAME_CHARS="abcdefghijklmnopqrstuvwxyz0123456789_*[]=<>;|?:% ."
0576     RINGTONE_LIMITS= {
0577         'MAXSIZE': 30000
0578     }
0579     # use for auto-detection
0580     phone_manufacturer='SAMSUNG ELECTRONICS'
0581     phone_model='SCH-A650/163'
0582     
0583     def __init__(self):
0584         com_samsung.Profile.__init__(self)
0585 
0586     _supportedsyncs=(
0587         ('phonebook', 'read', None),  # all phonebook reading
0588         ('phonebook', 'write', 'OVERWRITE'),  # only overwriting phonebook
0589         ('calendar', 'read', None),   # all calendar reading
0590         ('calendar', 'write', 'OVERWRITE'),   # only overwriting calendar
0591         ('ringtone', 'read', None),   # all ringtone reading
0592         ('ringtone', 'write', 'OVERWRITE'),
0593         ('wallpaper', 'read', None),  # all wallpaper reading
0594         ('wallpaper', 'write', 'OVERWRITE'),
0595         ('memo', 'read', None),     # all memo list reading DJP
0596         ('memo', 'write', 'OVERWRITE'),  # all memo list writing DJP
0597         ('todo', 'read', None),     # all todo list reading DJP
0598         ('todo', 'write', 'OVERWRITE'),  # all todo list writing DJP
0599         ('sms', 'read', None),     # all SMS list reading DJP
0600         )
0601 
0602     if __debug__:
0603         _supportedsyncs+=(('sms', 'write', 'OVERWRITE'),)
0604 
0605     def convertphonebooktophone(self, helper, data):
0606         return data
0607 
0608     __audio_ext={ 'MIDI': 'mid', 'QCP': 'qcp', 'PMD': 'pmd' }
0609     def QueryAudio(self, origin, currentextension, afi):
0610         # we don't modify any of these
0611         if afi.format in ("MIDI", "QCP", "PMD"):
0612             for k,n in self.RINGTONE_LIMITS.items():
0613                 setattr(afi, k, n)
0614             return currentextension, afi
0615         d=self.RINGTONE_LIMITS.copy()
0616         d['format']='QCP'
0617         return ('qcp', fileinfo.AudioFileInfo(afi, **d))
0618 
0619     # fill in your own image origins using these
0620     # use this temorarily until the stock one is finalized
0621     imageorigins={}
0622     imageorigins.update(common.getkv(com_samsung.Profile.stockimageorigins, "images"))
0623   
0624     imagetargets={}
0625     imagetargets.update(common.getkv(com_samsung.Profile.stockimagetargets, "wallpaper",
0626                                       {'width': 128, 'height': 128, 'format': "PNG"}))
0627     imagetargets.update(common.getkv(com_samsung.Profile.stockimagetargets, "fullscreen",
0628                                       {'width': 128, 'height': 160, 'format': "PNG"}))
0629     
0630     def GetImageOrigins(self):
0631         # Note: only return origins that you can write back to the phone
0632         return self.imageorigins
0633 
0634     def GetTargetsForImageOrigin(self, origin):
0635         if origin=='images':
0636             return self.imagetargets
0637 
0638 #-------------------------------------------------------------------------------
0639 class FileEntries:
0640     def __init__(self, phone, info):
0641         self.__phone=phone
0642         self.__file_type, self.__index_type, self.__origin, self.__path, self.__max_file_len, self.__max_file_count=info
0643 
0644     def get_media(self, result, download_info=None):
0645         self.__phone.log('Getting media for type '+self.__file_type)
0646         if download_info is None:
0647             return self.__get_media_by_dir(result)
0648         else:
0649             return self.__get_media_by_index(result, download_info)
0650 
0651     def __get_media_by_dir(self, result):
0652         media=result.get(self.__file_type, {})
0653         idx=result.get(self.__index_type, {})
0654         file_cnt, idx_k=0, len(idx)
0655         path_len=len(self.__path)+1
0656         try:
0657             file_list=self.__phone.getfilesystem(self.__path, 0)
0658             for k in file_list:
0659                 try:
0660                     index=k[path_len:]
0661                     # print k, index
0662                     media[index]=self.__phone.getfilecontents(k, True)
0663                     idx[idx_k]={ 'name': index, 'origin': self.__origin }
0664                     idx_k+=1
0665                     file_cnt += 1
0666                 except:
0667                     self.__phone.log('Failed to read file '+k)
0668         except:
0669             self.__phone.log('Failed to read dir '+self.__path)
0670         result[self.__file_type]=media
0671         result[self.__index_type]=idx
0672         if file_cnt > self.__max_file_count:
0673             self.__phone.log('This phone only supports %d %s.  %d %s read, weird things may happen.' % \
0674                                 (self.__max_file_count, self.__file_type,
0675                                  file_cnt, self.__file_type))
0676         return result
0677 
0678     def __get_media_by_index(self, result, rt_info):
0679         media=result.get(self.__file_type, {})
0680         media_index=result.get(self.__index_type, {})
0681         for k, m in media_index.items():
0682             file_key=m.get('name', None)
0683             file_name=rt_info.get(file_key, None)
0684             if file_key is not None and file_name is not None:
0685                 try :
0686                     media[file_key]=self.__phone.getfilecontents(file_name, True)
0687                 except:
0688                     self.__phone.log('Failed to read file '+file_name)
0689         result[self.__file_type]=media
0690         return result
0691 
0692     def save_media(self, result, dl_info):
0693         self.__phone.log('Saving media for type '+self.__file_type)
0694         media, idx=result[self.__file_type], result[self.__index_type]
0695         # check for files selected for deletion
0696         media_names=[media[k]['name'] for k in media]
0697         dl_info_keys=dl_info.keys()
0698         deleted_keys=[k for k in dl_info_keys if k not in media_names]
0699         new_keys=[k for k in media if media[k]['name'] not in dl_info_keys]
0700         # deleting files
0701         for k in deleted_keys:
0702             file_name=dl_info[k]
0703             self.__phone.log('Deleting file: '+file_name)
0704             try:
0705                 self.__phone.rmfile(file_name)
0706             except:
0707                 self.__phone.log('Failed to delete file: '+file_name)
0708         # writing new files
0709         # make sure dir exists to write new files
0710         if len(new_keys):
0711             try:
0712                 self.__phone.mkdirs(self.__path)
0713             except:
0714                 pass
0715         file_count=0
0716         for k in new_keys:
0717             n=media[k]
0718             origin=n.get('origin', None)
0719             if origin is not None and origin != self.__origin:
0720                 continue
0721             if len(n['name']) > self.__max_file_len:
0722                 self.__phone.log('%s %s name is too long and not sent to phone'% \
0723                                  (self.__file_type, n['name']))
0724                 continue
0725             file_count+=1
0726             if file_count>self.__max_file_count:
0727                 # max # of files reached, bailing out
0728                 self.__phone.log('This phone only supports %d %s.  Save operation stopped.'%\
0729                                     (self.__max_file_count, self.__file_type))
0730                 break
0731             file_name=self.__path+'/'+n['name']
0732             if self.__origin=='images':
0733                 # try to optimize it if it's a png image file
0734                 file_contents=conversions.convertto8bitpng_joe(n['data'])
0735             else:
0736                 file_contents=n['data']
0737             self.__phone.log('Writing file: '+file_name)
0738             try:
0739                 self.__phone.writefile(file_name, file_contents)
0740             except:
0741                 self.__phone.log('Failed to write file: '+file_name)
0742             media[k]['origin']=self.__origin
0743 
0744         return result
0745 
0746 #-------------------------------------------------------------------------------
0747 class RingtoneIndex:
0748     __builtin_ringtones=( 'Inactive',
0749                        'Bell 1', 'Bell 2', 'Bell 3', 'Bell 4', 'Bell 5',
0750                        'Melody 1', 'Melody 2', 'Melody 3', 'Melody 4', 'Melody 5',
0751                        'Melody 6', 'Melody 7', 'Melody 8', 'Melody 9', 'Melody 10')
0752 
0753     def __init__(self, phone):
0754         self.__phone=phone
0755 
0756     def get_builtin_index(self):
0757         r={}
0758         for k, n in enumerate(self.__builtin_ringtones):
0759             r[k]={ 'name': n, 'origin': 'builtin' }
0760         return r
0761 
0762     def get_download_index(self):
0763         r={}
0764         try:
0765             rt_idx=self.__phone.protocolclass.ringtones()
0766             buf=prototypes.buffer(self.__phone.getfilecontents( \
0767                 self.__phone.protocolclass.ringtone_index_file_name))
0768             rt_idx.readfrombuffer(buf, logtitle="Read ringtone index file")
0769             idx=len(self.__builtin_ringtones)
0770             l=len(self.__phone.protocolclass.ringtone_file_path)+1
0771             for i in range(self.__phone.protocolclass.max_ringtone_entries):
0772                 e=rt_idx.entry[i]
0773                 if e.name_len:
0774                     r[idx+i]={ 'name': e.file_name[l:e.file_name_len],
0775                                'origin': 'ringtone' }
0776         except:
0777             pass
0778         return r
0779 
0780     def get(self):
0781         r=self.get_builtin_index()
0782         r.update(self.get_download_index())
0783         return r
0784 
0785     def get_download_info(self):
0786         r={}
0787         try:
0788             rt_idx=self.__phone.protocolclass.ringtones()
0789             buf=prototypes.buffer(self.__phone.getfilecontents( \
0790                 self.__phone.protocolclass.ringtone_index_file_name))
0791             rt_idx.readfrombuffer(buf, logtitle="Read ringtone download index")
0792             l=len(self.__phone.protocolclass.ringtone_file_path)+1
0793             for i in range(self.__phone.protocolclass.max_ringtone_entries):
0794                 e=rt_idx.entry[i]
0795                 if e.name_len:
0796                     r[e.file_name[l:e.file_name_len]]=e.file_name[:e.file_name_len]
0797         except:
0798             pass
0799         return r
0800 
0801 #-------------------------------------------------------------------------------
0802 class ImageIndex:
0803     __builtin_images=( 'Clock1', 'Dual Clock', 'Calendar', 'Aquarium',
0804                       'Landscape', 'Water Drop' )
0805 
0806     def __init__(self, phone):
0807         self.__phone=phone
0808 
0809     def get_builtin_index(self):
0810         r={}
0811         for k, n in enumerate(self.__builtin_images):
0812             r[k]={ 'name': n, 'origin': 'builtin' }
0813         return r
0814 
0815     def get_download_index(self):
0816         r={}
0817         try:
0818             img_idx=self.__phone.protocolclass.images()
0819             buf=prototypes.buffer(self.__phone.getfilecontents( \
0820                 self.__phone.protocolclass.image_index_file_name))
0821             img_idx.readfrombuffer(buf, logtitle="Read image download index")
0822             idx=len(self.__builtin_images)
0823             l=len(self.__phone.protocolclass.image_file_path)+1
0824             for i in range(self.__phone.protocolclass.max_image_entries):
0825                 e=img_idx.entry[i]
0826                 if e.name_len:
0827                     r[idx+i]={ 'name': e.file_name[l:e.file_name_len],
0828                                'origin': 'images' }
0829         except:
0830             raise
0831         return r
0832 
0833     def get(self):
0834         r=self.get_builtin_index()
0835         r.update(self.get_download_index())
0836         return r
0837 
0838     def get_download_info(self):
0839         r={}
0840         try:
0841             img_idx=self.__phone.protocolclass.images()
0842             buf=prototypes.buffer(self.__phone.getfilecontents( \
0843                 self.__phone.protocolclass.image_index_file_name))
0844             img_idx.readfrombuffer(buf, logtitle="Read image download index")
0845             l=len(self.__phone.protocolclass.image_file_path)+1
0846             for i in range(self.__phone.protocolclass.max_image_entries):
0847                 e=img_idx.entry[i]
0848                 if e.name_len:
0849                     r[e.file_name[l:e.file_name_len]]=e.file_name[:e.file_name_len]
0850         except:
0851             pass
0852         return r
0853 
0854 #-------------------------------------------------------------------------------
0855 class PhoneNumbers:
0856     def __init__(self, phone):
0857         self.__phone=phone
0858         self.__numbers=None
0859 
0860     def read(self):
0861         try:
0862             buf=prototypes.buffer(self.__phone.getfilecontents(\
0863                 self.__phone.protocolclass.number_file_name))
0864             self.__numbers=self.__phone.protocolclass.numbers()
0865             self.__numbers.readfrombuffer(buf, logtitle="Read number file "+self.__phone.protocolclass.number_file_name)
0866         except:
0867             self.__phone.log('Failed to read numbers file')
0868             self.__numbers=[]
0869 
0870     def get(self, index, default=None):
0871         if index>=self.__phone.protocolclass.max_number_entries:
0872             return default
0873         e=self.__numbers.entry[index]
0874         if e.valid:
0875             return e.name[:e.length]
0876         return default
0877     
0878 #-------------------------------------------------------------------------------
0879 class PhoneBook:
0880 
0881     __pb_numbers= ({'home': 'home_num_index' },
0882                     {'office': 'office_num_index' },
0883                     {'cell': 'mobile_num_index' },
0884                     {'pager': 'pager_num_index' },
0885                     {'fax': 'fax_num_index' })
0886     def __init__(self, phone):
0887         self.__phone=phone
0888         self.__pb=None
0889         self.__numbers=None
0890         self.__groups=None
0891         self.__rt_index=None
0892         self.__id=None
0893         self.__slots=None
0894 
0895     def read(self):
0896         try:
0897             buf=prototypes.buffer(self.__phone.getfilecontents(\
0898                 self.__phone.protocolclass.pb_file_name))
0899             self.__pb=self.__phone.protocolclass.pbbook()
0900             self.__pb.readfrombuffer(buf, logtitle="Read "+self.__phone.protocolclass.pb_file_name)
0901         except:
0902             self.__pb=[]
0903             self.__phone.log('Failed to read phonebook')
0904 
0905     def get_ringtone(self, index):
0906         """
0907         Return the ringtone index of this entry.
0908         """
0909         if self.__pb is None:
0910             self.read()
0911         rt=self.__pb.entry[index].ringer_type
0912         if rt:
0913             rt-=71
0914         return rt
0915 
0916     def __extract_entry(self, e, pb_cnt, mem_index):
0917         res={}
0918         # serials
0919         res['serials']=[ {'sourcetype': self.__phone.serialsname,
0920                           'sourceuniqueid': self.__id,
0921                           'serial1': `pb_cnt`,
0922                           'serial2': `mem_index` }]
0923         # only one name
0924         res['names']=[ {'full': e.name } ]
0925         if e.alias_num_index:
0926             res['names'][0]['nickname']=self.__numbers.get(e.alias_num_index, '')
0927 
0928         # only one category
0929         res['categories']=[ {'category': self.__groups[e.group_num]['name'] } ]
0930 
0931         # emails
0932         if e.email_index:
0933             res['emails']=[ { 'email': self.__numbers.get(e.email_index, '') } ]
0934 
0935         # urls: N/A
0936         # private: N/A
0937         # memos: N/A
0938         # wallpapers: N/A
0939 
0940         # ringtones
0941         rt=e.ringer_type
0942         if rt:
0943             rt-=71
0944         res['ringtones']=[ { 'ringtone': self.__rt_index[rt]['name'],
0945                              'use': 'call' } ]
0946 
0947         # numbers
0948         speed_dial=e.speed_dial_index
0949         res['numbers']=[]
0950         for k, a in enumerate(self.__pb_numbers):
0951             for key, attr in a.items():
0952                 idx=getattr(e, attr, 0)
0953                 if idx:
0954                     num=self.__numbers.get(idx, '')
0955                     if idx==speed_dial:
0956                         res['numbers'].append({ 'number': num,
0957                                         'type': key,
0958                                         'speeddial': mem_index  } )
0959                     else:
0960                         res['numbers'].append({ 'number': num,
0961                                         'type': key })
0962         # done
0963         return res
0964         
0965     def get_dict(self, result):
0966         # read the phonebook if not already done so
0967         if self.__pb is None:
0968             self.read()
0969         # read the phone numbers
0970         if self.__numbers is None:
0971             self.__numbers=PhoneNumbers(self.__phone)
0972             self.__numbers.read()
0973         # read the slot entries
0974         if self.__slots is None:
0975             self.__slots=PBSlot(self.__phone)
0976             self.__slots.read()
0977         # get fundamental info
0978         self.__groups=result.get('groups', {})
0979         self.__rt_index=result.get('ringtone-index', {})
0980         self.__id=result.get('uniqueserial', '')
0981         # loop through the phonebook and extract each entry
0982         r={}
0983         for pb_cnt, i in enumerate(self.__slots):
0984             if i==0:
0985                 # empty slot
0986                 continue
0987             e=self.__pb.entry[i]
0988             if e.mem_index:
0989                 if i != e.mem_index:
0990                     self.__phone.log('i: %d, mem_index: %d'%(i, e.mem_index))
0991                 r[pb_cnt]=self.__extract_entry(e, pb_cnt, i)
0992         return r
0993 
0994 #-------------------------------------------------------------------------------
0995 class PBSlot:
0996     """ Class to handle Phonebook entry slot -> memory slot """
0997     def __init__(self, phone):
0998         self.__phone=phone
0999         self.__slots=None
1000 
1001     def read(self):
1002         try:
1003             buf=prototypes.buffer(self.__phone.getfilecontents(\
1004                 self.__phone.protocolclass.slot_file_name))
1005             self.__slots=self.__phone.protocolclass.pbslots()
1006             self.__slots.readfrombuffer(buf, logtitle="Read slots file "+self.__phone.protocolclass.slot_file_name)
1007         except:
1008             self.__slots=[]
1009             self.__phone.log('Failed to read slot file')
1010 
1011     def __getitem__(self, key):
1012         if type(key) is not int:
1013             raise KeyError
1014         if key<0 or key>=self.__phone.protocolclass.max_pb_slots:
1015             raise IndexError
1016         if self.__slots is None:
1017             self.read()
1018         return self.__slots.slot[key].pbbook_index
1019 

Generated by PyXR 0.9.4