0001 ### BITPIM 0002 ### 0003 ### Copyright (C) 2006 Joe Pham <djpham@bitpim.org> 0004 ### Copyright (C) 2006 Stephen Wood <saw@bitpim.org> 0005 ### 0006 ### This program is free software; you can redistribute it and/or modify 0007 ### it under the terms of the BitPim license as detailed in the LICENSE file. 0008 ### 0009 ### $Id: com_samsungscha870.py 4569 2008-01-15 01:03:05Z djpham $ 0010 0011 """Communicate with the Samsung SCH-A870 Phone""" 0012 0013 # System Models 0014 0015 # BitPim modules 0016 import bpcalendar 0017 import common 0018 import helpids 0019 import com_samsungscha950 as com_a950 0020 import p_samsungscha950 as p_a950 0021 import p_samsungscha870 as p_a870 0022 import prototypes 0023 0024 parentphone=com_a950.Phone 0025 class Phone(parentphone): 0026 desc='SCH-A870' 0027 helpid=helpids.ID_PHONE_SAMSUNGSCHA870 0028 protocolclass=p_a870 0029 serialsname='scha870' 0030 0031 # Detection stuff 0032 my_model='SCH-A870/187' 0033 my_manufacturer='SAMSUNG' 0034 detected_model='A870' 0035 0036 ringtone_noring_range='range_tones_preloaded_el_15' 0037 ringtone_default_range='range_tones_preloaded_el_01' 0038 builtin_ringtones={ 0039 'VZW Default Tone': 0x52, 0040 'Melody 1': 0x56, 0041 'Melody 2': 0x57, 0042 'Melody 3': 0x58, 0043 'Melody 4': 0x59, 0044 'Melody 5': 0x5A, 0045 'Melody 6': 0x5B, 0046 'Bell 1': 0x53, 0047 'Bell 2': 0x54, 0048 'Bell 3': 0x55, 0049 'Beep Once': 0x93, 0050 'No Ring': 0xC2, 0051 'Default': None, 0052 } 0053 builtin_sounds={ 0054 'Clapping': 0x5C, 0055 'Crowd': 0x5D, 0056 'Happy Birthday': 0x5E, 0057 'Rain Forest': 0x5F, 0058 'Train': 0x60, 0059 # same as ringtones ?? 0060 } 0061 builtin_wallpapers={ 0062 'No Picture': None, 0063 } 0064 0065 def __init__(self, logtarget, commport): 0066 "Calls all the constructors and sets initial modes" 0067 parentphone.__init__(self, logtarget, commport) 0068 global PBEntry, CalendarEntry 0069 self.pbentryclass=PBEntry 0070 self.calendarclass=CalendarEntry 0071 0072 def getfilecontents(self, filename, use_cache=False): 0073 if filename and filename[0]!='/': 0074 return parentphone.getfilecontents(self, '/'+filename, use_cache) 0075 return parentphone.getfilecontents(self, filename, use_cache) 0076 0077 def get_groups(self): 0078 _res={} 0079 _buf=prototypes.buffer(self.getfilecontents(self.protocolclass.GROUP_INDEX_FILE_NAME)) 0080 _index_file=self.protocolclass.GroupIndexFile() 0081 _index_file.readfrombuffer(_buf) 0082 for _entry in _index_file.items: 0083 if _entry.name: 0084 _res[_entry.index-1]={ 'name': _entry.name } 0085 return _res 0086 0087 def _get_dir_index(self, idx, result, pathname, origin, excludenames=()): 0088 # build the index list by listing contents of the specified dir 0089 for _path in self.listfiles(pathname): 0090 _file=common.basename(_path) 0091 if _file in excludenames: 0092 continue 0093 result[idx]={ 'name': _file, 0094 'filename': _path, 0095 'origin': origin, 0096 } 0097 idx+=1 0098 return idx 0099 0100 def get_ringtone_index(self): 0101 _res={} 0102 _idx=self._get_builtin_ringtone_index(0, _res) 0103 _idx=self._get_dir_index(_idx, _res, 0104 self.protocolclass.RT_PATH, 'ringers', 0105 self.protocolclass.RT_EXCLUDED_FILES) 0106 _idx=self._get_dir_index(_idx, _res, 0107 self.protocolclass.SND_PATH, 'sounds', 0108 self.protocolclass.SND_EXCLUDED_FILES) 0109 return _res 0110 0111 def _get_file_wallpaper_index(self, idx, result): 0112 try: 0113 _buf=prototypes.buffer(self.getfilecontents(self.protocolclass.PIC_INDEX_FILE_NAME)) 0114 except (com_brew.BrewNoSuchFileException, 0115 com_brew.BrewBadPathnameException, 0116 com_brew.BrewFileLockedException, 0117 com_brew.BrewAccessDeniedException): 0118 return idx 0119 except: 0120 if __debug__: 0121 raise 0122 return idx 0123 _index_file=self.protocolclass.PictureIndexFile() 0124 _index_file.readfrombuffer(_buf) 0125 for _entry in _index_file.items: 0126 result[idx]={ 'name': _entry.name, 0127 'filename': _entry.pathname, 0128 'origin': 'images', 0129 } 0130 idx+=1 0131 return idx 0132 0133 def get_wallpaper_index(self): 0134 _res={} 0135 _idx=self._get_builtin_wallpaper_index(0, _res) 0136 _idx=self._get_file_wallpaper_index(_idx, _res) 0137 return _res 0138 0139 def _get_del_new_list(self, index_key, media_key, merge, fundamentals, 0140 origins): 0141 """Return a list of media being deleted and being added""" 0142 _index=fundamentals.get(index_key, {}) 0143 _media=fundamentals.get(media_key, {}) 0144 _index_file_list=[_entry['name'] for _entry in _index.values() \ 0145 if _entry.has_key('filename') and \ 0146 _entry.get('origin', None) in origins ] 0147 _bp_file_list=[_entry['name'] for _entry in _media.values() \ 0148 if _entry.get('origin', None) in origins ] 0149 if merge: 0150 # just add the new files, don't delete anything 0151 _del_list=[] 0152 _new_list=_bp_file_list 0153 else: 0154 # Delete specified files and add everything 0155 _del_list=[x for x in _index_file_list if x not in _bp_file_list] 0156 _new_list=_bp_file_list 0157 return _del_list, _new_list 0158 0159 def saveringtones(self, fundamentals, merge): 0160 """Save ringtones to the phone""" 0161 self.log('Writing ringtones to the phone') 0162 try: 0163 _del_list, _new_list=self._get_del_new_list('ringtone-index', 0164 'ringtone', 0165 merge, 0166 fundamentals, 0167 frozenset(('ringers', 'sounds'))) 0168 if __debug__: 0169 self.log('Delete list: '+','.join(_del_list)) 0170 self.log('New list: '+','.join(_new_list)) 0171 self._replace_files('ringtone-index', 'ringtone', 0172 _new_list, fundamentals) 0173 self._add_files('ringtone-index', 'ringtone', 0174 _new_list, fundamentals) 0175 fundamentals['rebootphone']=True 0176 except: 0177 if __debug__: 0178 raise 0179 return fundamentals 0180 0181 def _add_files(self, index_key, media_key, 0182 new_list, fundamentals): 0183 """Add new file using BEW""" 0184 _index=fundamentals.get(index_key, {}) 0185 _media=fundamentals.get(media_key, {}) 0186 _files_added=[] 0187 for _file in new_list: 0188 _data=self._item_from_index(_file, 'data', _media) 0189 if not _data: 0190 self.log('Failed to write file %s due to no data'%_file) 0191 continue 0192 if self._item_from_index(_file, None, _index) is None: 0193 # new file 0194 _origin=self._item_from_index(_file, 'origin', _media) 0195 if _origin=='ringers': 0196 _path=self.protocolclass.RT_PATH 0197 elif _origin=='sounds': 0198 _path=self.protocolclass.SND_PATH 0199 elif _origin=='images': 0200 _path=self.protocolclass.PIC_PATH 0201 else: 0202 selg.log('File %s has unknown origin, skip!'%_file) 0203 continue 0204 _file_name=_path+'/'+_file 0205 try: 0206 self.writefile(_file_name, _data) 0207 _files_added.append({ 'filename': _file, 0208 'filesize': len(_data) }) 0209 except: 0210 self.log('Failed to write file '+_file_name) 0211 if __debug__: 0212 raise 0213 return _files_added 0214 0215 def _update_wp_index_file(self, filelist): 0216 # update the wp/picture index file with list of new files 0217 if not filelist: 0218 # no new files to update, bail 0219 return 0220 _index_file=self.protocolclass.PictureIndexFile() 0221 try: 0222 # read existing index items ... 0223 _data=self.getfilecontents(self.protocolclass.PIC_INDEX_FILE_NAME) 0224 if _data: 0225 _index_file.readfrombuffer(prototypes.buffer(_data)) 0226 except (com_brew.BrewNoSuchFileException, 0227 com_brew.BrewBadPathnameException, 0228 com_brew.BrewFileLockedException, 0229 com_brew.BrewAccessDeniedException): 0230 pass 0231 # and append the new files 0232 for _fileitem in filelist: 0233 _index_file.items.append(self.protocolclass.PictureIndexEntry(**_fileitem)) 0234 # and write out the new index file 0235 _buffer=prototypes.buffer() 0236 _index_file.writetobuffer(_buffer) 0237 self.writefile(self.protocolclass.PIC_INDEX_FILE_NAME, 0238 _buffer.getvalue()) 0239 0240 def savewallpapers(self, fundamentals, merge): 0241 # send wallpapers to the phone 0242 """Save ringtones to the phone""" 0243 self.log('Writing wallpapers to the phone') 0244 try: 0245 _del_list, _new_list=self._get_del_new_list('wallpaper-index', 0246 'wallpapers', 0247 merge, 0248 fundamentals, 0249 frozenset(['images'])) 0250 if __debug__: 0251 self.log('Delete list: '+','.join(_del_list)) 0252 self.log('New list: '+','.join(_new_list)) 0253 self._replace_files('wallpaper-index', 'wallpapers', 0254 _new_list, fundamentals) 0255 _files_added=self._add_files('wallpaper-index', 'wallpapers', 0256 _new_list, fundamentals) 0257 self._update_wp_index_file(_files_added) 0258 fundamentals['rebootphone']=True 0259 except: 0260 if __debug__: 0261 raise 0262 return fundamentals 0263 0264 def _read_ringtone_range(self, fundamentals): 0265 pass 0266 def _add_wp_cache(self, wp, idx, fundamentals): 0267 # check to see if it already exists 0268 pass 0269 0270 # PBEntry class----------------------------------------------------------------- 0271 parentpbentry=com_a950.PBEntry 0272 class PBEntry(parentpbentry): 0273 0274 # Building a phonebook rec from a bp phone dict----------------------------- 0275 def _build_number(self, number, ringtone, primary): 0276 # build a number rec 0277 _num_type=self._pb_type_dict.get(number['type'], None) 0278 if not _num_type: 0279 # we don's support this type 0280 return 0281 # check for cell2 0282 if _num_type=='cell' and self.pb.cell.number: 0283 _num_type='cell2' 0284 # build a number entry 0285 _entry=self.phone.protocolclass.ss_number_entry() 0286 _entry.number=number['number'] 0287 _sd=number.get('speeddial', None) 0288 if _sd is not None: 0289 _entry.speeddial=_sd 0290 if primary: 0291 _entry.primary=1 0292 # add it to the contact 0293 setattr(self.pb, _num_type, _entry) 0294 0295 def _build_wallpaper(self, wallpaper): 0296 # set the wallpaper if specified 0297 if not wallpaper: 0298 return 0299 for _rt in self.fundamentals.get('wallpaper-index', {}).values(): 0300 if _rt.get('name', None)==wallpaper and \ 0301 _rt.get('filename', None): 0302 self.pb.wallpaper='%(name)s|%(pathname)s'% { 0303 'name': _rt['name'], 0304 'pathname': _rt['filename'] } 0305 break 0306 0307 def _build_ringtone(self, ringtone): 0308 # set the ringtone if specified 0309 if not ringtone: 0310 self.pb.ringtone='Default' 0311 return 0312 for _wp in self.fundamentals.get('ringtone-index', {}).values(): 0313 if _wp.get('name', None)==ringtone: 0314 if _wp.get('filename', None): 0315 self.pb.ringtone=_wp['filename'] if _wp['filename'][0]=='/' \ 0316 else '/'+_wp['filename'] 0317 elif _wp.get('origin', None)=='builtin': 0318 self.pb.ringtone=_wp['name'] 0319 break 0320 0321 def _build(self, entry): 0322 # Build a phone dict base on the phone data 0323 super(PBEntry, self)._build(entry) 0324 self._build_ringtone(entry.get('ringtones', [{}])[0].get('ringtone', None)) 0325 0326 # Extracting data from the phone-------------------------------------------- 0327 def _extract_wallpaper(self, entry, p_class): 0328 if self.pb.info&p_class.PB_FLG_WP and \ 0329 self.pb.wallpaper: 0330 entry['wallpapers']=[{ 'wallpaper': self.pb.wallpaper.partition('|')[0], 0331 'use': 'call' }] 0332 def _extract_ringtone(self, entry, p_class): 0333 if self.pb.info&p_class.PB_FLG_CRINGTONE and \ 0334 self.pb.ringtone: 0335 entry['ringtones']=[{ 'ringtone': common.basename(self.pb.ringtone), 0336 'use': 'call' }] 0337 def getvalue(self): 0338 _entry=super(PBEntry, self).getvalue() 0339 self._extract_ringtone(_entry, self.phone.protocolclass) 0340 return _entry 0341 0342 # CalendarEntry class----------------------------------------------------------- 0343 calendarentryparent=com_a950.CalendarEntry 0344 class CalendarEntry(calendarentryparent): 0345 """Transient class to handle calendar data being sent to, retrieved from 0346 the phone. 0347 """ 0348 # Extracting routine-------------------------------------------------------- 0349 def _extract_ringtone(self): 0350 # extract the builtin ringtone value, if possible 0351 for _rt_name, _rt_code in self.phone.builtin_ringtones.items(): 0352 if _rt_code==self.cal.ringtoneindex: 0353 return _rt_name 0354 for _rt_name, _rt_code in self.phone.builtin_sounds.items(): 0355 if _rt_code==self.cal.ringtoneindex: 0356 return _rt_name 0357 0358 def getvalue(self): 0359 # return a BitPim calendar entry equivalence 0360 _entry=bpcalendar.CalendarEntry() 0361 _entry.desc_loc=self.cal.title 0362 _entry.start=self.cal.start 0363 _entry.end=self._extract_end() 0364 _entry.alarm=self._extract_alarm() 0365 _entry.ringtone=self._extract_ringtone() 0366 _entry.vibrate=self.cal.alert==self.ALERT_VIBRATE 0367 return _entry 0368 0369 # building routines--------------------------------------------------------- 0370 def _build_ringtone(self, entry): 0371 _rt_name=entry.ringtone 0372 if self.phone.builtin_ringtones.get(_rt_name, None): 0373 return self.phone.builtin_ringtones[_rt_name] 0374 elif self.phone.builtin_sounds.get(_rt_name, None): 0375 return self.phone.builtin_sounds[_rt_name] 0376 else: 0377 return 0 0378 0379 def _build(self, entry): 0380 # populate this object with data from BitPim 0381 self.cal.titlelen=len(entry.desc_loc) 0382 self.cal.title=entry.desc_loc 0383 self.cal.start=entry.start 0384 self.cal.exptime=entry.end[3:5] 0385 self.cal.alarm=self._build_alarm(entry) 0386 self.cal.alert=self._build_alert(entry) 0387 self.cal.duration=self._build_duration(entry) 0388 self.cal.ringtoneindex=self._build_ringtone(entry) 0389 0390 #------------------------------------------------------------------------------- 0391 parentprofile=com_a950.Profile 0392 class Profile(parentprofile): 0393 serialsname=Phone.serialsname 0394 # main LCD resolution, (external LCD is 96x96) 0395 WALLPAPER_WIDTH=128 0396 WALLPAPER_HEIGHT=160 0397 # For phone detection 0398 phone_manufacturer=Phone.my_manufacturer 0399 phone_model=Phone.my_model 0400 autodetect_delay=5 0401 # "Warning" media size limit 0402 RINGTONE_LIMITS= { 0403 'MAXSIZE': 290000 0404 } 0405 0406 # fill in the list of ringtone/sound origins on your phone 0407 ringtoneorigins=('ringers', 'sounds') 0408 # ringtone origins that are not available for the contact assignment 0409 excluded_ringtone_origins=() 0410 0411 # all dumped in "images" 0412 imageorigins={} 0413 imageorigins.update(common.getkv(parentprofile.stockimageorigins, "images")) 0414 def GetImageOrigins(self): 0415 return self.imageorigins 0416 0417 # our targets are the same for all origins 0418 imagetargets={} 0419 imagetargets.update(common.getkv(parentprofile.stockimagetargets, "wallpaper", 0420 {'width': 128, 'height': 128, 'format': "JPEG"})) 0421 imagetargets.update(common.getkv(parentprofile.stockimagetargets, "pictureid", 0422 {'width': 96, 'height': 84, 'format': "JPEG"})) 0423 imagetargets.update(common.getkv(parentprofile.stockimagetargets, "fullscreen", 0424 {'width': 128, 'height': 160, 'format': "JPEG"})) 0425 imagetargets.update(common.getkv(parentprofile.stockimagetargets, "outsidelcd", 0426 {'width': 96, 'height': 84, 'format': "JPEG"})) 0427 def __init__(self): 0428 parentprofile.__init__(self) 0429 0430 _supportedsyncs=( 0431 ('phonebook', 'read', None), # all phonebook reading 0432 ('phonebook', 'write', 'OVERWRITE'), # only overwriting phonebook 0433 ('calendar', 'read', None), # all calendar reading 0434 ('calendar', 'write', 'OVERWRITE'), # only overwriting calendar 0435 ('ringtone', 'read', None), # all ringtone reading 0436 ('ringtone', 'write', 'MERGE'), 0437 ('wallpaper', 'read', None), # all wallpaper reading 0438 ('wallpaper', 'write', 'MERGE'), 0439 ('memo', 'read', None), # all memo list reading DJP 0440 ('memo', 'write', 'OVERWRITE'), # all memo list writing DJP 0441 ('call_history', 'read', None),# all call history list reading 0442 ('sms', 'read', None), # all SMS list reading DJP 0443 ) 0444
Generated by PyXR 0.9.4