| Trees | Indices | Help | 
 | 
|---|
|  | 
  1  ### BITPIM 
  2  ### 
  3  ### Copyright (C) 2004-2005 Stephen Wood <saw@bitpim.org> 
  4  ### Copyright (C) 2005 Todd Imboden 
  5  ### 
  6  ### This program is free software; you can redistribute it and/or modify 
  7  ### it under the terms of the BitPim license as detailed in the LICENSE file. 
  8  ### 
  9  ### $Id: com_samsungspha620.py 4371 2007-08-22 04:22:40Z sawecw $ 
 10   
 11  """Communicate with a Samsung SPH-A620""" 
 12   
 13  import sha 
 14  import re 
 15  import struct 
 16   
 17  import common 
 18  import commport 
 19  import p_samsungspha620 
 20  import p_brew 
 21  import com_brew 
 22  import com_phone 
 23  import com_samsung_packet 
 24  import prototypes 
 25  import fileinfo 
 26  import helpids 
 27   
 28  numbertypetab=('home','office','cell','pager','fax','none') 
 29   
 31      "Talk to a Samsung SPH-A620 phone" 
 32   
 33      desc="SPH-A620" 
 34      helpid=helpids.ID_PHONE_SAMSUNGOTHERS 
 35      protocolclass=p_samsungspha620 
 36      serialsname='spha620' 
 37   
 38      # digital_cam/jpeg Remove first 148 characters 
 39   
 40      imagelocations=( 
 41          # offset, index file, files location, origin, maximumentries, header offset 
 42          # Offset is arbitrary.  100 is reserved for amsRegistry indexed files 
 43          (400, "digital_cam/wallet", "camera", 100, 148), 
 44          (300, "digital_cam/jpeg", "camera", 100, 148), 
 45          ) 
 46   
 47      ringtonelocations=( 
 48          # offset, index file, files location, type, maximumentries, header offset 
 49          ) 
 50           
 51      __audio_mimetype={ 'mid': 'audio/midi', 'qcp': 'audio/vnd.qcelp', 'pmd': 'application/x-pmd'} 
 52      __image_mimetype={ 'jpg': 'image/jpg', 'jpeg': 'image/jpeg', 'gif': 'image/gif', 'bmp': 'image/bmp', 'png': 'image/png'} 
 53   
 55          com_samsung_packet.Phone.__init__(self, logtarget, commport) 
 56          self.numbertypetab=numbertypetab 
 57          self.mode=self.MODENONE 
 58   
 60          """Gets information fundamental to interopating with the phone and UI.""" 
 61          self.amsanalyze(results) 
 62   
 63          # use a hash of ESN and other stuff (being paranoid) 
 64          self.log("Retrieving fundamental phone information") 
 65          self.log("Phone serial number") 
 66          self.setmode(self.MODEMODEM) 
 67          results['uniqueserial']=sha.new(self.get_esn()).hexdigest() 
 68   
 69          self.log("Reading group information") 
 70          results['groups']=self.read_groups() 
 71          # Comment the next to out if you want to read the phonebook 
 72          #self.getwallpaperindices(results) 
 73          #self.getringtoneindices(results) 
 74          self.log("Fundamentals retrieved") 
 75          return results 
 76   
 78          buf=prototypes.buffer(self.getfilecontents(self.protocolclass.AMSREGISTRY)) 
 79          ams=self.protocolclass.amsregistry() 
 80          ams.readfrombuffer(buf, logtitle="Read AMS registry") 
 81          rt={}   #Todd added for ringtone index 
 82          nrt=0     #Todd added for ringtone index 
 83          wp={} 
 84          nwp=0 
 85          for i in range(ams.nfiles): 
 86              filetype=ams.info[i].filetype 
 87              if filetype: 
 88                  dir_ptr=ams.info[i].dir_ptr 
 89                  name_ptr=ams.info[i].name_ptr 
 90                  mimetype_ptr=ams.info[i].mimetype_ptr 
 91                  version_ptr=ams.info[i].version_ptr 
 92                  vendor_ptr=ams.info[i].vendor_ptr 
 93                  dir=self.getstring(ams.strings,dir_ptr) 
 94                  name=self.getstring(ams.strings,name_ptr) 
 95                  mimetype=self.getstring(ams.strings,mimetype_ptr) 
 96                  version=self.getstring(ams.strings,version_ptr) 
 97                  vendor=self.getstring(ams.strings,vendor_ptr) 
 98   
 99                  #downloaddomain_ptr=ams.info[i].downloaddomain_ptr 
100                  print i, filetype, version, dir, vendor, name, mimetype 
101                  #if downloaddomainptr_ptr: 
102                  # print self.getstring(ams.strings,misc_ptr) 
103                  print ams.info[i].num2, ams.info[i].num7, ams.info[i].num8, ams.info[i].num9, ams.info[i].num12, ams.info[i].num13, ams.info[i].num14, ams.info[i].num15, ams.info[i].num16, ams.info[i].num17 
104                  print " " 
105   
106          # Todd's added info 
107                  if filetype==12:     #this will add the file extension 
108                      if mimetype=="audio/vnd.qcelp": 
109                          filetype='.qcp' 
110                      elif mimetype=="audio/midi": 
111                          filetype='.mid' 
112                      elif mimetype=="application/x-pmd": 
113                          filetype='.pmd' 
114                      elif mimetype=="audio/mp3": 
115                          filetype='.mp3' 
116                      else: 
117                          filetype='' 
118                      rt[100+nrt]={'name':name+filetype,'location':'ams/'+dir,'origin':'ringers'} 
119                      nrt+=1 
120                  elif filetype==13: 
121                      if mimetype=="image/jpeg": 
122                          filetype='.jpg' 
123                      elif mimetype=="image/png": 
124                          filetype='.png' 
125                      elif mimetype=="image/gif": 
126                          filetype='.gif' 
127                      elif mimetype=="image/bmp": 
128                          filetype='.bmp' 
129                      else: 
130                          filetype='' 
131                      wp[100+nwp]={'name':name+filetype,'location':'ams/'+dir,'origin':'images'} 
132                      nwp+=1 
133                       
134          results['ringtone-index']=rt 
135          results['wallpaper-index']=wp 
136           
138          "Extend incomplete lines" 
139          # VGA1000 Firmware WG09 doesn't return a full line unless birthday 
140          # is set.  Add extra commas so packet decoding works 
141          nfields=26                      # Can we get this from packet def? 
142          ncommas=self.countcommas(line) 
143          if ncommas<0:                   # Un terminated quote 
144              line+='"' 
145              ncommas = -ncommas 
146          if nfields-ncommas>1: 
147              line=line+","*(nfields-ncommas-1) 
148          return line 
149   
151          inquote=False 
152          ncommas=0 
153          for c in line: 
154              if c == '"': 
155                  inquote = not inquote 
156              elif not inquote and c == ',': 
157                  ncommas+=1 
158   
159          if inquote: 
160              ncommas = -ncommas 
161           
162          return ncommas 
163           
165          self.getmediaindex(self.ringtonelocations, results,'ringtone-index') 
166          return self.getmedia(self.ringtonelocations, results, 'ringtone') 
167       
169          self.getmediaindex(self.imagelocations, results,'wallpaper-index') 
170          return self.getmedia(self.imagelocations, results, 'wallpapers') 
171   
172       
174          """Returns the contents of media as a dicxt where the key is a name 
175          returned by getindex, and the value is the contents of the media""" 
176           
177          media={} 
178          if key=="ringtone": 
179              index_key="ringtone-index" 
180              origin="ringers" 
181          elif key=="wallpapers": 
182              index_key="wallpaper-index" 
183              origin="images" 
184               
185          # Read the files indexed in ams Registry 
186          for k in results[index_key].keys(): 
187              e=results[index_key][k] 
188              if e['origin']==origin: 
189                  self.log("Reading "+e['name']) 
190                  contents=self.getfilecontents(e['location']) 
191                  media[e['name']]=contents 
192   
193          # Now read from the directories in the maps array 
194          for offset,location,type,maxentries, headeroffset in maps: 
195              for item in self.listfiles(location).values(): 
196                  filename=item['name'] 
197                  p=filename.rfind("/") 
198                  basefilename=filename[p+1:]+".jpg" 
199                  contents=self.getfilecontents(filename) 
200   
201                  name_len=ord(contents[5]) 
202                  new_basefilename=filename[p+1:]+"_"+contents[6:6+name_len]+".jpg" 
203                  duplicate=False 
204                  # Fix up duplicate filenames 
205                  for k in results[index_key].keys(): 
206                      if results[index_key][k]['name']==new_basefilename: 
207                          duplicate=True 
208                          break 
209                      if results[index_key][k]['name']==basefilename: 
210                          ksave=k 
211                  if duplicate: 
212                      new_basefilename=basefilename 
213                  else: 
214                      self.log("Renaming to "+new_basefilename) 
215                      results[index_key][ksave]['name']=new_basefilename                   
216                  media[new_basefilename]=contents[headeroffset:] 
217   
218          results[key]=media 
219   
221          """Get the media (wallpaper/ringtone) index for stuff not in amsRegistry 
222   
223          @param results: places results in this dict 
224          @param maps: the list of locations 
225          @param key: key to place results in 
226          """ 
227          self.log("Reading "+key) 
228   
229          media=results[key] # Get any existing indices 
230          for offset,location,origin,maxentries, headeroffset in maps: 
231              i=0 
232              for item in self.listfiles(location).values(): 
233                  print item 
234                  filename=item['name'] 
235                  p=filename.rfind("/") 
236                  filename=filename[p+1:]+".jpg" 
237                  media[offset+i]={'name': filename, 'origin': origin} 
238                  i+=1 
239   
240          results[key] = media 
241          return 
242   
244          if name is None: 
245              return 0 
246          for i in index: 
247              if index[i]['name']==name: 
248                  return i 
249          # Not found in index, assume Vision download 
250          pos=name.find('_') 
251          if(pos>=0): 
252              i=int(name[pos+1:]) 
253              return i 
254           
255          return 0 
256           
258          "Get a null terminated string from contents" 
259          i=start 
260          while contents[i:i+1]!='\0': 
261              i+=1 
262          return contents[start:i] 
263   
265          "Build a GCD file for filename" 
266          ext=common.getext(filename.lower()) 
267          try: 
268              mimetype=mimetable[ext] 
269          except: 
270              return "" 
271           
272          noextname=common.stripext(filename) 
273          gcdcontent="Content-Type: "+mimetype+"\nContent-Name: "+noextname+"\nContent-Version: 1.0\nContent-Vendor: BitPim\nContent-URL: file:"+filename+"\nContent-Size: "+`size`+"\n\n\n" 
274          return gcdcontent 
275           
277          dircache=self.DirCache(self) 
278          media_prefix=self.protocolclass.RINGERPREFIX 
279          endtransactionpath=self.protocolclass.ENDTRANSACTION 
280          media=result.get('ringtone', {}) 
281          media_index=result.get('ringtone-index', {}) 
282          media_names=[x['name'] for x in media.values()] 
283          index_names=[x['name'] for x in media_index.values()] 
284          if merge: 
285              del_names=[] 
286          else: 
287              del_names=[common.stripext(x) for x in index_names if x not in media_names] 
288              gcdpattern=re.compile("[\n\r]Content-Name: +(.*?)[\n\r]") 
289          new_names=[x for x in media_names if x not in index_names] 
290   
291          progressmax=len(del_names)+len(new_names) 
292          progresscur=0 
293          self.log("Writing ringers") 
294          self.progress(progresscur, progressmax, "Writing ringers") 
295   
296          for icnt in range(1,101): 
297              if not (new_names or del_names): 
298                  break 
299              fname=media_prefix+`icnt` 
300              fnamegcd=media_prefix+`icnt`+".gcd" 
301              fstat=dircache.stat(fnamegcd) 
302              if del_names and fstat: 
303                  # See if this file is in list of files to delete 
304                  gcdcontents=dircache.readfile(fnamegcd) 
305                  thisfile=gcdpattern.search(gcdcontents).groups()[0] 
306                  if thisfile in del_names: 
307                      self.log("Deleting ringer "+thisfile) 
308                      self.progress(progresscur, progressmax, "Deleting ringer "+thisfile) 
309                      progresscur+=1 
310                      dircache.rmfile(fname) 
311                      dircache.rmfile(fnamegcd) 
312                      del_names.remove(thisfile) 
313                      fstat=False 
314              if new_names and not fstat: 
315                  newname=new_names.pop() 
316                  contents="" 
317                  for k in media.keys(): 
318                      if media[k]['name']==newname: 
319                          contents=media[k]['data'] 
320                          break 
321   
322                  contentsize=len(contents) 
323                  if contentsize: 
324                      gcdcontents=self.makegcd(newname,contentsize,self.__audio_mimetype) 
325                      self.log("Writing ringer "+newname) 
326                      self.progress(progresscur, progressmax, "Deleting ringer "+newname) 
327                      progresscur+=1 
328                      dircache.writefile(fname,contents) 
329                      dircache.writefile(fnamegcd,gcdcontents) 
330   
331          fstat=dircache.stat(endtransactionpath) 
332          self.log("Finished writing ringers") 
333          self.progress(progressmax, progressmax, "Finished writing ringers") 
334          if fstat: 
335              dircache.rmfile(endtransactionpath) 
336          result['rebootphone']=True 
337   
338          return 
339   
341          dircache=self.DirCache(self) 
342          media_prefix=self.protocolclass.WALLPAPERPREFIX 
343          endtransactionpath=self.protocolclass.ENDTRANSACTION 
344          media=result.get('wallpapers', {}) 
345          for i in media.keys(): 
346              try: 
347                  if media[i]['origin']=='camera': 
348                      del media[i] 
349              except: 
350                  pass 
351          media_index=result.get('wallpaper-index', {}) 
352          media_names=[x['name'] for x in media.values()] 
353          index_names=[x['name'] for x in media_index.values()] 
354          if merge: 
355              del_names=[] 
356          else: 
357              del_names=[common.stripext(x) for x in index_names if x not in media_names] 
358              gcdpattern=re.compile("[\n\r]Content-Name: +(.*?)[\n\r]") 
359          new_names=[x for x in media_names if x not in index_names] 
360   
361          progressmax=len(del_names)+len(new_names) 
362          progresscur=0 
363          self.log("Writing images") 
364          self.progress(progresscur, progressmax, "Writing images") 
365   
366          for icnt in range(1,101): 
367              if not (new_names or del_names): 
368                  break 
369              fname=media_prefix+`icnt` 
370              fnamegcd=media_prefix+`icnt`+".gcd" 
371              fstat=dircache.stat(fnamegcd) 
372              if del_names and fstat: 
373                  # See if this file is in list of files to delete 
374                  gcdcontents=dircache.readfile(fnamegcd) 
375                  thisfile=gcdpattern.search(gcdcontents).groups()[0] 
376                  if thisfile in del_names: 
377                      self.log("Deleting image "+thisfile) 
378                      self.progress(progresscur, progressmax, "Deleting image "+thisfile) 
379                      progresscur+=1 
380                      dircache.rmfile(fname) 
381                      dircache.rmfile(fnamegcd) 
382                      del_names.remove(thisfile) 
383                      fstat=False 
384              if new_names and not fstat: 
385                  newname=new_names.pop() 
386                  contents="" 
387                  for k in media.keys(): 
388                      if media[k]['name']==newname: 
389                          contents=media[k]['data'] 
390                          break 
391   
392                  contentsize=len(contents) 
393                  if contentsize: 
394                      gcdcontents=self.makegcd(newname,contentsize,self.__image_mimetype) 
395                      self.log("Writing image "+newname) 
396                      self.progress(progresscur, progressmax, "Deleting image "+newname) 
397                      progresscur+=1 
398                      dircache.writefile(fname,contents) 
399                      dircache.writefile(fnamegcd,gcdcontents) 
400   
401          fstat=dircache.stat(endtransactionpath) 
402          self.log("Finished writing images") 
403          self.progress(progressmax, progressmax, "Finished writing images") 
404          if fstat: 
405              dircache.rmfile(endtransactionpath) 
406          result['rebootphone']=True 
407   
408          return 
409   
410           
412      protocolclass=Phone.protocolclass 
413      serialsname=Phone.serialsname 
414   
415      MAX_RINGTONE_BASENAME_LENGTH=19 
416      RINGTONE_FILENAME_CHARS="abcdefghijklmnopqrstuvwxyz0123456789_ ." 
417      RINGTONE_LIMITS= { 
418          'MAXSIZE': 250000 
419      } 
420      phone_manufacturer='SAMSUNG' 
421      phone_model='SPH-A620/152' 
422   
426   
427      _supportedsyncs=( 
428          ('phonebook', 'read', None),  # all phonebook reading 
429          ('phonebook', 'write', 'OVERWRITE'),  # only overwriting phonebook 
430          ('wallpaper', 'read', None),  # all wallpaper reading 
431          ('wallpaper', 'write', None), # Image conversion needs work 
432          ('ringtone', 'read', None),   # all ringtone reading 
433          ('ringtone', 'write', None), 
434          ('calendar', 'read', None),   # all calendar reading 
435          ('calendar', 'write', 'OVERWRITE'),   # only overwriting calendar 
436          ('todo', 'read', None),     # all todo list reading 
437          ('todo', 'write', 'OVERWRITE'),  # all todo list writing 
438          ('memo', 'read', None),     # all memo list reading 
439          ('memo', 'write', 'OVERWRITE'),  # all memo list writing 
440          ) 
441   
442      __audio_ext={ 'MIDI': 'mid', 'PMD': 'pmd', 'QCP': 'qcp' } 
444          # we don't modify any of these 
445          print "afi.format=",afi.format 
446          if afi.format in ("MIDI", "PMD", "QCP"): 
447              for k,n in self.RINGTONE_LIMITS.items(): 
448                  setattr(afi, k, n) 
449              return currentextension, afi 
450          d=self.RINGTONE_LIMITS.copy() 
451          d['format']='QCP' 
452          return ('qcp', fileinfo.AudioFileInfo(afi, **d)) 
453   
| Trees | Indices | Help | 
 | 
|---|
| Generated by Epydoc 3.0.1 on Sun Jan 24 16:22:01 2010 | http://epydoc.sourceforge.net |