PyXR

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



0001 ### BITPIM
0002 ###
0003 ### Copyright (C) 2004 Joe Pham <djpham@netzero.com>
0004 ### Copyright (C) 2004 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_samsung.py 4365 2007-08-17 21:11:59Z djpham $
0010 
0011 """Communicate with a Samsung SCH-Axx phone using AT commands"""
0012 # standard modules
0013 import copy
0014 import datetime
0015 import re
0016 import time
0017 
0018 # site-packages
0019 from thirdparty import DSV
0020 
0021 # BitPim modules
0022 import bpcalendar
0023 import com_brew
0024 import com_phone
0025 import common
0026 import commport
0027 import memo
0028 import p_brew
0029 import phoneinfo
0030 import sms
0031 import todo
0032 
0033 class Phone(com_phone.Phone,com_brew.BrewProtocol):
0034     "Talk to a Samsung phone using AT commands"
0035 
0036     desc="Samsung SCH-Axx phone"
0037 
0038     MODEPHONEBOOK="modephonebook"
0039 
0040     _AT_str="AT"
0041     _OK_str="\r\nOK\r\n"
0042     _Error_str="\r\nERROR\r\n"
0043     _read_timeout=0.1
0044     # Calendar class vars
0045     _cal_entries_range=xrange(20)
0046     _cal_max_events=20
0047     _cal_max_events_per_day=9
0048     _cal_num_of_read_fields=7
0049     _cal_num_of_write_fields=6
0050     _cal_entry=0
0051     _cal_start_datetime=1
0052     _cal_end_datetime=2
0053     # if your phone does not support and end-datetime, set this to a default value
0054     # if it does support end-datetime, set this to None
0055     _cal_end_datetime_value='19800106T000000'
0056     _cal_datetime_stamp=3
0057     _cal_alarm_type=4
0058     _cal_read_name=6
0059     _cal_write_name=5
0060     _cal_alarm_values={
0061         '0': -1, '1': 0, '2': 10, '3': 30, '4': 60 }
0062     _cal_max_name_len=32
0063     _switch_mode_cmd='\x44\x58\xf4\x7e'
0064     
0065     def __init__(self, logtarget, commport):
0066         "Call all the contructors and sets initial modes"
0067         com_phone.Phone.__init__(self, logtarget, commport)
0068         com_brew.BrewProtocol.__init__(self)
0069         self.mode=self.MODENONE
0070 
0071     def _setmodephonebooktobrew(self):
0072         self.setmode(self.MODEMODEM)
0073         self.setmode(self.MODEBREW)
0074         return True
0075 
0076     def _setmodemodemtobrew(self):
0077         self.log('Switching from modem to BREW')
0078         try:
0079             self.comm.sendatcommand('$QCDMG')
0080             return True
0081         except:
0082             pass
0083         # give it another try
0084         self.log('Retry switching from modem to BREW')
0085         try:
0086             self.comm.sendatcommand('$QCDMG')
0087             return True
0088         except commport.ATError:
0089             return False
0090         except:
0091             if __debug__:
0092                 self.log('Got an excepetion')
0093             return False
0094 
0095     def _setmodebrew(self):
0096         # switch from None to BREW
0097         self.log('Switching from None to BREW')
0098         # do it the long, but sure, way: 1st try to switch to modem
0099         if not self._setmodemodem():
0100             # can't switch to modem, give up
0101             return False
0102         # then switch from modem to BREW
0103         return self._setmodemodemtobrew()
0104 
0105     def _setmodebrewtomodem(self):
0106         self.log('Switching from BREW to modem')
0107         try:
0108             self.comm.write(self._switch_mode_cmd, False)
0109             self.comm.readsome(numchars=5, log=False)
0110             return True
0111         except:
0112             pass
0113         # give it a 2nd try
0114         try:
0115             self.comm.write(self._switch_mode_cmd, False)
0116             self.comm.readsome(numchars=5, log=False)
0117             return True
0118         except:
0119             return False
0120 
0121     def _setmodemodemtophonebook(self):
0122         self.log('Switching from modem to phonebook')
0123         response=self.comm.sendatcommand("#PMODE=1")
0124         return True
0125 
0126     def _setmodemodem(self):
0127         self.log('Switching to modem')
0128         try:
0129             self.comm.sendatcommand('E0V1')
0130             return True
0131         except:
0132             pass
0133         # could be in BREW mode, try switch over
0134         self.log('trying to switch from BREW mode')
0135         if not self._setmodebrewtomodem():
0136             return False
0137         try:
0138             self.comm.sendatcommand('E0V1')
0139             return True
0140         except:
0141             return False
0142 
0143     def _setmodephonebook(self):
0144         self.setmode(self.MODEMODEM)
0145         self.setmode(self.MODEPHONEBOOK)
0146         return True
0147         
0148     def _setmodephonebooktomodem(self):
0149         self.log('Switching from phonebook to modem')
0150         response=self.comm.sendatcommand("#PMODE=0")
0151         return True
0152         
0153     def _get_at_response(self):
0154         s=self.comm.read(1, False)
0155         if not len(s):
0156             return ''
0157 
0158         # got at least one char, try to read the rest with short timeout
0159 
0160         i=self.comm.ser.getTimeout()
0161         self.comm.ser.setTimeout(self._read_timeout)
0162         while True:
0163             s1=self.comm.read(1, False)
0164             if len(s1):
0165                 s += s1
0166             else:
0167                 break
0168 
0169         self.comm.ser.setTimeout(i)
0170         return s
0171 
0172     def is_online(self):
0173         self.setmode(self.MODEPHONEBOOK)
0174         try:
0175             self.comm.sendatcommand("E0V1")
0176             return True
0177         except commport.ATError:
0178             return False
0179 
0180     def get_esn(self):
0181         try:
0182             s=self.comm.sendatcommand("+gsn")
0183             if len(s):
0184                 return ' '.join(s[0].split(": ")[1:])
0185         except commport.ATError:
0186             pass
0187         return ''
0188 
0189     def _send_and_get(self, at_command):
0190         try:
0191             s=self.comm.sendatcommand(str(at_command))
0192             if len(s):
0193                 return self.splitandunescape(s[0])
0194         except commport.ATError:
0195             pass
0196         return None
0197         
0198     def get_model(self):
0199         return ','.join(self._send_and_get('+GMM'))
0200     def get_manufacturer(self):
0201         return ','.join(self._send_and_get('+GMI'))
0202     def get_phone_number(self):
0203         return self._send_and_get('+MIN?')[0]
0204     def get_firmware_version(self):
0205         return ','.join(self._send_and_get('+GMR'))
0206     def get_battery_level(self):
0207         s=self._send_and_get('+CBC?')
0208         if s is not None and len(s)==2:
0209             return s[1]+'%'
0210     def get_signal_quality(self):
0211         s=self._send_and_get('+CSQ?')
0212         if s is not None and len(s)==2:
0213             return str(100*int(s[0])/31)+'%'
0214     def get_analog_digital(self):
0215         d={ '0': 'Analog', '1': 'Digital' }
0216         s=self._send_and_get('+CAD?')
0217         return d.get(s[0], '<Unknown>')
0218 
0219     def get_groups(self, groups_range):
0220 
0221         g=[]
0222         for i in groups_range:
0223             try:
0224                 s=self.comm.sendatcommand("#PBGRR=%d" % i)
0225                 if len(s):
0226                     g.append(s[0].split(': ')[1].split(',')[1].strip('"'))
0227                 else:
0228                     g.append('')
0229             except commport.ATError:
0230                 g.append('')
0231         return g
0232 
0233     def get_phone_entry(self, entry_index, alias_column=-1, num_columns=-1):
0234         try:
0235             s=self.comm.sendatcommand("#PBOKR=%d" % entry_index)
0236             if len(s):
0237                 line=s[0]
0238                 if alias_column >= 0 and alias_column < num_columns:
0239                     line=self.defrell(line, alias_column, num_columns)
0240                 return self.splitandunescape(line)
0241         except commport.ATError:
0242             pass
0243         return []
0244 
0245     def del_phone_entry(self, entry_index):
0246         try:
0247             s=self.comm.sendatcommand("#PBOKW=%d" % entry_index)
0248             return True
0249         except commport.ATError:
0250             return False
0251 
0252     def save_phone_entry(self, entry_str):
0253         try:
0254             s=self.comm.sendatcommand("#PBOKW="+entry_str)
0255             return True
0256         except commport.ATError:
0257             return False
0258 
0259     def get_time_stamp(self):
0260 
0261         now = time.localtime(time.time())
0262         return "%04d%02d%02dT%02d%02d%02d" % now[0:6]
0263 
0264     def phonize(self, str):
0265         """Convert the phone number into something the phone understands
0266         All digits, P, T, * and # are kept, everything else is removed"""
0267 
0268         return re.sub("[^0-9PT#*]", "", str)
0269 
0270     def get_calendar_entry(self, entry_index):
0271         try:
0272             s=self.comm.sendatcommand('#PISHR=%d' % entry_index)
0273             if len(s):
0274                 return self.splitandunescape(s[0])
0275         except commport.ATError:
0276             pass
0277         return []
0278 
0279     def save_calendar_entry(self, entry_str):
0280         try:
0281             self.comm.sendatcommand('#PISHW='+entry_str)
0282             return True
0283         except:
0284             return False
0285 
0286     def get_memo_entry(self, entry_index):
0287         try:
0288             s=self.comm.sendatcommand('#PIMMR=%d'%entry_index)
0289             if len(s):
0290                 return self.splitandunescape(s[0])
0291         except commport.ATError:
0292             pass
0293         return []
0294 
0295     def save_memo_entry(self, entry_str):
0296         try:
0297             self.comm.sendatcommand('#PIMMW='+entry_str)
0298             return True
0299         except:
0300             return False
0301 
0302     def get_todo_entry(self, entry_index):
0303         try:
0304             s=self.comm.sendatcommand('#PITDR=%d' % entry_index)
0305             if len(s):
0306                 return self.splitandunescape(s[0])
0307         except commport.ATError:
0308             pass
0309         return []
0310 
0311     def save_todo_entry(self, entry_str):
0312         try:
0313             self.comm.sendatcommand("#PITDW="+entry_str)
0314             return True
0315         except:
0316             return False
0317 
0318     def get_sms_inbox(self, entry_index):
0319         try:
0320             s=self.comm.sendatcommand('#psrmr=%d'%entry_index)
0321             if len(s):
0322                 return self.splitandunescape(s[0])
0323         except commport.ATError:
0324             pass
0325         return []
0326     def get_sms_saved(self, entry_index):
0327         try:
0328             s=self.comm.sendatcommand('#psfmr=%d'%entry_index)
0329             if len(s):
0330                 return self.splitandunescape(s[0])
0331         except commport.ATError:
0332             pass
0333         return []
0334     def get_sms_sent(self, entry_index):        
0335         try:
0336             s=self.comm.sendatcommand('#pssmr=%d'%entry_index)
0337             if len(s):
0338                 return self.splitandunescape(s[0])
0339         except commport.ATError:
0340             pass
0341         return []
0342     def get_canned_msg(self, entry_index):
0343         try:
0344             s=self.comm.sendatcommand('#psstr=%d'%entry_index)
0345             if len(s):
0346                 return self.splitandunescape(s[0])
0347         except commport.ATError:
0348             pass
0349         return []
0350     def save_canned_msg(self, entry_str):
0351         try:
0352             self.comm.sendatcommand('#psstw='+entry_str)
0353             return True
0354         except:
0355             return False
0356 
0357     def extract_timedate(self, td):
0358         # extract samsung timedate 'YYYYMMDDTHHMMSS' to (y, m, d, h, m)
0359         return (int(td[:4]), int(td[4:6]), int(td[6:8]), int(td[9:11]), int(td[11:13]))
0360 
0361     def encode_timedate(self, td):
0362         # reverse if extract_timedate
0363         return "%04d%02d%02dT%02d%02d00" % tuple(td)
0364 
0365     def splitandunescape(self, line):
0366         """Split fields and unescape double quote and right brace"""
0367         # Should unescaping be done on fields that are not surrounded by
0368         # double quotes?  DSV strips these quotes, so we have to do it to
0369         # all fields.
0370         col=line.find(": ")
0371         print line[col+2:]
0372         e=DSV.importDSV([line[col+2:]])[0]
0373         i=0
0374         while i<len(e):
0375             item=e[i]
0376             item=item.replace("}\002",'"')
0377             item=item.replace("}]","}")
0378             e[i]=item
0379             i+=1
0380             
0381         return e
0382 
0383     def samsungescape(self, s):
0384         """Escape double quotes and }'s in a string"""
0385         #s=s.replace("}","}]")
0386         #s=s.replace('"','}\002')
0387         return s
0388         
0389     def defrell(self, s, acol, ncol):
0390         """Fixes up phonebook responses with the alias field.  The alias field
0391         does not have quotes around it, but can still contain commas"""
0392         # Example with A670  self.defrell(s, 17, 26)
0393         if acol<0 or acol>=ncol: # Invalid alias column, do nothing
0394             return s
0395         e=s.split(",")
0396         i=0
0397 
0398         while i<len(e):
0399             # Recombine when ,'s in quotes
0400             if len(e[i]) and e[i][0]=='"' and e[i][-1]!='"':
0401                 while i+1<len(e) and (len(e[i+1])==0 or e[i+1][-1]!='"'):
0402                     e[i] += ","+e[i+1]
0403                     del e[i+1]
0404                 else:
0405                     if i+1<len(e):
0406                         e[i] += ","+e[i+1]
0407                         del e[i+1]
0408             i+=1
0409 
0410         if len(e)<=ncol: # Return original string if no excess commas
0411             return s
0412         
0413         for k in range(len(e)-ncol):
0414             e[acol]+=","+e[acol+1]
0415             del e[acol+1]
0416 
0417         e[acol]='"'+e[acol]+'"' # quote the string
0418     
0419         res=e[0]
0420         for item in e[1:]:  # Rejoin the columns
0421             res+=","+item
0422 
0423         return res
0424         
0425         
0426     def csvsplit(self, line):
0427         """Parse a Samsung comma separated list."""
0428         e=line.split(",")
0429         i=0
0430         print len(e)
0431         result=[]
0432         while i<len(e):
0433             # Recombine when ;'s in quotes
0434             if len(e[i]) and e[i][0]=='"' and e[i][-1]!='"':
0435                 while i+1<len(e) and (len(e[i+1])==0 or e[i+1][-1]!='"'):
0436                     e[i] = e[i]+","+e[i+1]
0437                     del e[i+1]
0438                 else:
0439                     if i+1<len(e):
0440                         e[i] = e[i]+","+e[i+1]
0441                         del e[i+1]
0442         
0443 
0444             # Identify type of each item
0445             # Strip quotes on strings
0446             # Un escape escaped characters
0447             item=e[i]
0448             if len(item)==0:
0449                 t=0
0450             elif item[0]=='"' or item[-1]=='"':
0451                 mo=re.match('^"?(.*?)"?$',item)
0452                 item=mo.group(1)
0453                 item=item.replace("}\002",'"')
0454                 item=item.replace("}]","}")
0455                 t='string'
0456             elif re.match('^\d+T\d+$',item):
0457                 t='timestamp'
0458             elif re.match('^[\dPT]+$',item):
0459                 # Number or phone number
0460                 t='number'
0461             elif re.match('^\(\d+-\d+\)',item):
0462                 t='range'
0463             elif re.match('^\d\d?/\d\d?/\d\d(\d\d)?$',item):
0464                 t='date'
0465             else:
0466                 t='other'
0467                 
0468             if t:
0469                 result.append({'type':t, 'value':item})
0470             else:
0471                 result.append(0)
0472                 
0473             i+=1
0474 
0475         return result
0476         
0477     def getcalendar(self, result):
0478         self.log("Getting calendar entries")
0479         self.setmode(self.MODEPHONEBOOK)
0480         res={}
0481         l=len(self._cal_entries_range)
0482         cal_cnt=0
0483         for k in self._cal_entries_range:
0484             r=self.get_calendar_entry(k)
0485             if not len(r):
0486                 # blank, no entry
0487                 self.progress(k+1, l, "Getting blank entry: %d"%k)
0488                 continue
0489             self.progress(k+1, l, "Getting "+r[self._cal_read_name])
0490 
0491             # build a calendar entry
0492             entry=bpcalendar.CalendarEntry()
0493 
0494             # start time date
0495             entry.start=self.extract_timedate(r[self._cal_start_datetime])
0496 
0497             
0498             if self._cal_end_datetime_value is None:
0499                 # valid end time
0500                 entry.end=self.extract_timedate(r[self._cal_end_datetime])
0501             else:
0502                 # no end time, end time=start time
0503                 entry.end=entry.start
0504 
0505             # description
0506             entry.description=r[self._cal_read_name]
0507 
0508             # alarm
0509             try:
0510                 alarm=self._cal_alarm_values[r[self._cal_alarm_type]]
0511             except:
0512                 alarm=None
0513             entry.alarm=alarm
0514 
0515             # update calendar dict
0516             res[entry.id]=entry
0517             cal_cnt += 1
0518         result['calendar']=res
0519         self.setmode(self.MODEMODEM)
0520         return result
0521 
0522     def process_calendar(self, dict):
0523         """ Optimize and expand calendar data suitable for phone download
0524         """
0525         # first go thru the dict to organize events by date
0526         # and also determine the latest event date
0527         r={}
0528         rp=[]
0529         today=datetime.date.today()
0530         last_date=today
0531         if __debug__:
0532             print 'original calendar:'
0533         for k,e in dict.items():
0534             if __debug__:
0535                 print e.description,':',e.start
0536             sd=datetime.date(*e.start[:3])
0537             ed=datetime.date(*e.end[:3])
0538             if ed>last_date:
0539                 last_date=ed
0540             if e.repeat is None:
0541                 if sd>=today:
0542                     r.setdefault(e.start[:3], []).append(Samsung_Calendar(e))
0543             else:
0544                 if ed>=today:
0545                     rp.append(e)
0546         # go through and expand on the repeated events
0547         delta_1=datetime.timedelta(1)
0548         for n in rp:
0549             current_date=today
0550             end_date=datetime.date(*n.end[:3])
0551             cnt=0
0552             while current_date<=end_date:
0553                 if n.is_active(current_date.year, current_date.month,
0554                                current_date.day):
0555                     cd_l=(current_date.year, current_date.month,
0556                           current_date.day)
0557                     r.setdefault(cd_l, []).append(\
0558                                       Samsung_Calendar(n, cd_l))
0559                     cnt+=1
0560                     if cnt>self._cal_max_events:
0561                         # enough for this one, breaking out
0562                         break
0563                 current_date+=delta_1
0564         # and put them all into a list
0565         res=[]
0566         keys=r.keys()
0567         # sort by date
0568         keys.sort()
0569         for k in keys:
0570             # sort by time within this date
0571             r[k].sort()
0572             # clip by max events/day
0573             if len(r[k])>self._cal_max_events_per_day:
0574                 res+=r[k][:self._cal_max_events_per_day]
0575             else:
0576                 res+=r[k]
0577         # clip by max events
0578         if len(res)>self._cal_max_events:
0579             res=res[:self._cal_max_events]
0580         return res
0581             
0582     def savecalendar(self, dict, merge):
0583         
0584         self.log("Sending calendar entries")
0585 
0586         cal=self.process_calendar(dict['calendar'])
0587         
0588         # testing
0589         if __debug__:
0590             print 'processed calendar: ', len(cal), ' items'
0591             for c in cal:
0592                 print c.description,':', c.start
0593         # testing
0594         self.setmode(self.MODEPHONEBOOK)
0595         self.log("Saving calendar entries")
0596         cal_cnt=0
0597         l=self._cal_max_events
0598         for c in cal:
0599             # Save this entry to phone
0600             e=['']*self._cal_num_of_write_fields
0601 
0602             # pos
0603             e[self._cal_entry]=`cal_cnt`
0604 
0605             # start date time
0606             e[self._cal_start_datetime]=self.encode_timedate(c.start)
0607 
0608             # end date time
0609             if self._cal_end_datetime_value is None:
0610                 # valid end-datetime
0611                 e[self._cal_end_datetime]=self.encode_timedate(c.end)
0612             else:
0613                 # no end-datetime, set to start-datetime
0614                 e[self._cal_end_datetime]=self._cal_end_datetime_value
0615 
0616             # time stamp
0617             e[self._cal_datetime_stamp]=self.get_time_stamp()
0618 
0619             # Alarm type
0620             e[self._cal_alarm_type]=c.alarm
0621 
0622             # Name, check for bad char & proper length
0623             name=c.description.replace('"', '')
0624             if len(name)>self._cal_max_name_len:
0625                 name=name[:self._cal_max_name_len]
0626             e[self._cal_write_name]='"'+name+'"'
0627 
0628             # and save it
0629             self.progress(cal_cnt+1, l, "Updating "+name)
0630             if not self.save_calendar_entry(",".join(e)):
0631                 self.log("Failed to save item: "+name)
0632             else:
0633                 cal_cnt += 1
0634 
0635         # delete the rest of the
0636         self.log('Deleting unused entries')
0637         for k in range(cal_cnt, l):
0638             self.progress(k, l, "Deleting entry %d" % k)
0639             self.save_calendar_entry(`k`)
0640 
0641         self.setmode(self.MODEMODEM)
0642 
0643         return dict
0644     # common methods for individual phones if they can use them w/o changes
0645     def _getmemo(self, result):
0646         self.setmode(self.MODEPHONEBOOK)
0647         m=MemoList(self)
0648         m.read()
0649         m_dict=m.get()
0650         result['memo']=m_dict
0651         self.setmode(self.MODEMODEM)
0652         return m_dict
0653 
0654     def _savememo(self, result, merge):
0655         self.setmode(self.MODEPHONEBOOK)
0656         m=MemoList(self)
0657         r=result.get('memo', {})
0658         m.set(r)
0659         m.write()
0660         self.setmode(self.MODEMODEM)
0661         return r
0662 
0663     def _gettodo(self, result):
0664         self.log("Getting todo entries")
0665         self.setmode(self.MODEPHONEBOOK)
0666         td_l=TodoList(self)
0667         td_l.read()
0668         result['todo']=td_l.get()
0669         self.setmode(self.MODEMODEM)
0670         return result
0671 
0672     def _savetodo(self, result, merge):
0673         self.log("Saving todo entries")
0674         self.setmode(self.MODEPHONEBOOK)
0675         td_l=TodoList(self, result.get('todo', {}))
0676         td_l.validate()
0677         td_l.write()
0678         self.setmode(self.MODEMODEM)
0679         return result
0680 
0681     def _getsms(self, result):
0682         self.log("Getting SMS entries")
0683         self.setmode(self.MODEPHONEBOOK)
0684         sms_l=SMSList(self)
0685         sms_l.read()
0686         result['sms']=sms_l.get()
0687         sms_canned=CannedMsgList(self)
0688         sms_canned.read()
0689         result['canned_msg']=sms_canned.get()
0690         self.setmode(self.MODEMODEM)
0691         return result
0692     def _savesms(self, result, merge):
0693         self.log("Saving SMS Canned Messages")
0694         self.setmode(self.MODEPHONEBOOK)
0695         canned_msg=CannedMsgList(self, result.get('canned_msg', {}))
0696         canned_msg.write()
0697         self.setmode(self.MODEMODEM)
0698         return result
0699     def _getphoneinfo(self, phone_info):
0700         self.log('Getting Phone Info')
0701         self.setmode(self.MODEPHONEBOOK)
0702         for e in phoneinfo.PhoneInfo.standard_keys:
0703             f=getattr(self, 'get_'+e[0])
0704             setattr(phone_info, e[0], f())
0705         phone_info.append('Analog/Digital:', self.get_analog_digital())
0706         self.setmode(self.MODEMODEM)
0707 
0708     def _send_at_and_get(self, cmd):
0709         try:
0710             resp=self.comm.sendatcommand(cmd)
0711             return ': '.join(resp[0].split(': ')[1:])
0712         except:
0713             return None
0714 
0715     def is_mode_modem(self):
0716         try:
0717             resp=self.comm.sendatcommand('E0V1')
0718             return True
0719         except:
0720             return False
0721 
0722     def get_detect_data(self, r):
0723         # get detection data
0724         r['manufacturer']=self._send_at_and_get('+GMI')
0725         r['model']=self._send_at_and_get('+GMM')
0726         r['firmware_version']=self._send_at_and_get('+GMR')
0727         r['esn']=self._send_at_and_get('+GSN')
0728 
0729     @classmethod
0730     def detectphone(_, coms, likely_ports, res, _module, _log):
0731         if not len(likely_ports):
0732             return None
0733         for port in likely_ports:
0734             if not res.has_key(port):
0735                 res[port]={ 'mode_modem': None, 'mode_brew': None,
0736                             'manufacturer': None, 'model': None,
0737                             'firmware_version': None, 'esn': None,
0738                             'firmwareresponse': None }
0739             try:
0740                 if res[port]['mode_modem']==False or \
0741                    res[port]['model']:
0742                     continue
0743                 p=Phone(_log, commport.CommConnection(_log, port, timeout=1))
0744                 if p.is_mode_modem():
0745                     res[port]['mode_modem']=True
0746                     p.get_detect_data(res[port])
0747                 else:
0748                     res[port]['mode_modem']=False
0749             except:
0750                 # this port is not available
0751                 if __debug__:
0752                     raise
0753 
0754 #------------------------------------------------------------------------------
0755 class Profile(com_phone.Profile):
0756 
0757     BP_Calendar_Version=3
0758 
0759     serialsname='samsung'
0760 
0761     usbids=( ( 0x04e8, 0x6601, 1),  # Samsung internal USB interface
0762         )
0763 
0764     # which device classes we are.
0765     deviceclasses=("modem", "serial")
0766 
0767     _supportedsyncs=()
0768 
0769     def __init__(self):
0770         com_phone.Profile.__init__(self)
0771 
0772 #------------------------------------------------------------------------------
0773 class Samsung_Calendar:
0774     _cal_alarm_values={
0775         '0': -1, '1': 0, '2': 10, '3': 30, '4': 60 }
0776     
0777     def __init__(self, calendar_entry, new_date=None):
0778         self._start=self._end=self._alarm=self._desc=None
0779         self._extract_cal_info(calendar_entry, new_date)
0780 
0781     def _extract_cal_info(self, cal_entry, new_date):
0782         s=cal_entry.start
0783         if new_date is not None:
0784             s=new_date[:3]+s[3:]
0785         self._start=s
0786         self._end=cal_entry.end
0787         self._desc=cal_entry.description
0788         # approximate the alarm value
0789         self._alarm='0'
0790         alarm=cal_entry.alarm
0791         _keys=self._cal_alarm_values.keys()
0792         _keys.sort()
0793         _keys.reverse()
0794         for k in _keys:
0795             if alarm>=self._cal_alarm_values[k]:
0796                 self._alarm=k
0797                 break
0798 
0799     def __lt__(self, rhs):
0800         return self.start<rhs.start
0801     def __le__(self, rhs):
0802         return self.start<=rhs.start
0803     def __eq__(self, rhs):
0804         return self.start==rhs.start
0805     def __ne__(self, rhs):
0806         return self.start!=rhs.start
0807     def __gt__(self, rhs):
0808         return self.start>rhs.start
0809     def __ge__(self, rhs):
0810         return self.start>=rhs.start
0811     
0812     def _get_start(self):
0813         return self._start
0814     start=property(fget=_get_start)
0815 
0816     def _get_end(self):
0817         return self._end
0818     end=property(fget=_get_end)
0819 
0820     def _get_desc(self):
0821         return self._desc
0822     description=property(fget=_get_desc)
0823 
0824     def _get_alarm(self):
0825         return self._alarm
0826     alarm=property(fget=_get_alarm)
0827 
0828 #-------------------------------------------------------------------------------
0829 class MemoList(object):
0830     # class constants
0831     _max_num_entries=10
0832     _range_entries=xrange(_max_num_entries)
0833     _max_text_len=60
0834     _max_subject_len=12
0835     _max_num_of_fields=4
0836     _text_index=3
0837     _date_index=1
0838     _max_write_fields=3
0839     _write_entry_index=0
0840     _write_date_index=1
0841     _write_text_index=2
0842     _continuation_char='-'
0843 
0844     def __init__(self, phone):
0845         self._phone=phone
0846         self._data={}
0847 
0848     def get(self):
0849         return copy.deepcopy(self._data, {})
0850 
0851     def read(self):
0852         self._data={}
0853         text=''
0854         for i in self._range_entries:
0855             try:
0856                 self._phone.progress(i, self._max_num_entries,
0857                                       'Reading Memo Entry: '+str(i))
0858                 s=self._phone.get_memo_entry(i)
0859                 if len(s)!=self._max_num_of_fields:
0860                     continue
0861                 t=s[self._text_index]
0862                 if len(t)==self._max_text_len and \
0863                    t[-1]==self._continuation_char:
0864                     # contination to the next record
0865                     text+=t[:len(t)-1]
0866                     continue
0867                 # new record
0868                 text+=t
0869                 m=memo.MemoEntry()
0870                 m.text=text
0871                 m.set_date_isostr(s[self._date_index])
0872                 self._data[m.id]=m
0873                 text=''
0874             except:
0875                 if __debug__: raise
0876 
0877     def write(self):
0878         keys=self._data.keys()
0879         keys.sort()
0880         count=0
0881         for k in keys:
0882             if count>=self._max_num_entries:
0883                 self._phone.log('Max number of memos sent')
0884                 break
0885             n=self._data[k]
0886             text=n.text
0887             subj=n.subject
0888             l=min(self._max_subject_len, len(text))
0889             if subj[:l]!=text[:l]:
0890                 text=subj+':'+text
0891             text.replace('"', '')
0892             while len(text) and count<self._max_num_entries:
0893                 if len(text)>self._max_text_len:
0894                     sub_text=text[:self._max_text_len-1]+self._continuation_char
0895                     text=text[self._max_text_len-1:]
0896                 else:
0897                     sub_text=text
0898                     text=''
0899                 entry_str=['']*self._max_write_fields
0900                 entry_str[self._write_entry_index]=`count`
0901                 entry_str[self._write_date_index]=self._phone.get_time_stamp()
0902                 entry_str[self._write_text_index]='"'+sub_text+'"'
0903                 self._phone.progress(count, self._max_num_entries,
0904                                       'Writing Memo Entry: '+str(count))
0905                 if self._phone.save_memo_entry(','.join(entry_str)):
0906                     self._phone.log('Sent memo %s to the phone'%subj)
0907                     count+=1
0908                 else:
0909                     self._phone.log("Failed to send memo"+subj)
0910         # clear out the rest of the slots
0911         for k in xrange(count, self._max_num_entries):
0912             self._phone.progress(k, self._max_num_entries,
0913                                   'Deleing Memo Entry: '+str(k))
0914             self._phone.save_memo_entry(`k`)
0915 
0916     def set(self, data):
0917         self._data={}
0918         self._data.update(data)
0919 
0920 #-------------------------------------------------------------------------------
0921 class TodoList(object):
0922     _td_max_read_fields=6
0923     _td_max_write_fields=5
0924     _td_max_entries=20
0925     _td_entry=0
0926     _td_priority=1
0927     _td_due_datetime=2
0928     _td_datetime_stamp=3
0929     _td_status=4
0930     _td_subject=5
0931     _td_write_subject=4
0932     _td_max_len_name=32
0933     
0934     def __init__(self, phone, data={}):
0935         self._phone=phone
0936         self._data=data
0937 
0938     def get(self):
0939         return copy.deepcopy(self._data, {})
0940 
0941     def _extract_fields(self, s):
0942         entry=todo.TodoEntry()
0943         i=int(s[self._td_priority])
0944         if i:
0945             entry.priority=1
0946         else:
0947             entry.priority=10
0948         entry.due_date=s[self._td_due_datetime][:8]
0949         entry.summary=s[self._td_subject]
0950         return entry
0951     
0952     def read(self):
0953         self._data={}
0954         cnt=0
0955         for i in xrange(self._td_max_entries):
0956             s=self._phone.get_todo_entry(i)
0957             if not len(s):
0958                 self._phone.progress(i+1, self._td_max_entries,
0959                                       'Getting blank entry: '+str(i))
0960                 continue
0961             self._phone.progress(i+1, self._td_max_entries, s[self._td_subject])
0962             e=self._extract_fields(s)
0963             self._data[e.id]=e
0964    
0965     def _encode_fields(self, i, entry):
0966         e=['']*self._td_max_write_fields
0967         e[self._td_entry]=`i`
0968         if entry.priority is not None and entry.priority<5:
0969             e[self._td_priority]='1'
0970         else:
0971             e[self._td_priority]='0'
0972         s=entry.due_date
0973         if s is None or not len(s):
0974             s=self._phone.get_time_stamp()
0975         else:
0976             s+='T000000'
0977         e[self._td_due_datetime]=s
0978         e[self._td_datetime_stamp]=self._phone.get_time_stamp()
0979         e[self._td_write_subject]='"'+entry.summary+'"'
0980         return ','.join(e)
0981         
0982     def _write_entry(self, i, entry):
0983         return self._phone.save_todo_entry(self._encode_fields(i, entry))
0984 
0985     def validate(self):
0986         for k,n in self._data.items():
0987             name=n.summary.replace('"', '')
0988             if len(name)>self._td_max_len_name:
0989                 name=name[:self._td_max_len_name]
0990             n.summary=name
0991 
0992     def write(self):
0993         keys=self._data.keys()
0994         keys.sort()
0995         cnt=0
0996         for k in keys:
0997             n=self._data[k]
0998             if cnt>self._td_max_entries:
0999                 break
1000             if self._write_entry(cnt, n):
1001                 cnt += 1
1002             else:
1003                 self._phone.log('Failed to save todo entry '+str(k))
1004             self._phone.progress(cnt, self._td_max_entries, 'Saving entry: '+n.summary)
1005         for i in xrange(cnt, self._td_max_entries):
1006             self._phone.progress(i, self._td_max_entries, 'Deleting entry: '+str(i))
1007             self._phone.save_todo_entry(`i`)
1008 
1009 #-------------------------------------------------------------------------------
1010 class SMS_Generic_List(object):
1011     def __init__(self, phone):
1012         self._phone=phone
1013         self._data={}
1014     def get(self):
1015         return self._data.copy()
1016     def read(self):
1017         raise NotImplementedError
1018 
1019 #-------------------------------------------------------------------------------
1020 class SMS_Inbox_List(SMS_Generic_List):
1021     _max_entries=100
1022     _valid_range=xrange(_max_entries)
1023     _datetime_index=3
1024     _body_index=4
1025     _callback_index=5
1026     _field_num=6
1027     def __init__(self, phone):
1028         super(SMS_Inbox_List, self).__init__(phone)
1029     def read(self):
1030         for i in self._valid_range:
1031             self._phone.progress(i, self._max_entries,
1032                                  'Reading SMS Inbox Entry '+str(i))
1033             s=self._phone.get_sms_inbox(i)
1034             if len(s)==self._field_num:
1035                 e=sms.SMSEntry()
1036                 e.folder=e.Folder_Inbox
1037                 e.datetime=s[self._datetime_index]
1038                 e._from, e.subject, txt=self._extract_body(s[self._body_index])
1039                 e.text=unicode(txt, errors='ignore')
1040                 e.callback=s[self._callback_index]
1041                 self._data[e.id]=e
1042 
1043     def _extract_body(self, s):
1044         try:
1045             # extract different components from the main text body
1046             _from=None
1047             l=s.split(' ')
1048             ss=l[0]
1049             if ss.find('@') != -1:
1050                 # this the 'from' email address
1051                 _from=ss
1052                 l=l[1:]
1053                 ss=l[0]
1054             _subj=[]
1055             if ss[0]=='(':
1056                 while l:
1057                     _subj.append(ss)
1058                     l=l[1:]
1059                     if ss[-1]==')':
1060                         break
1061                     if l:
1062                         ss=l[0]
1063             if l:
1064                 return (_from, ' '.join(_subj), ' '.join(l))
1065             else:
1066                 return (_from, '', ' '.join(_subj))
1067         except:
1068             # something happend, just return the original text
1069             return (None, '', s)
1070 
1071 #-------------------------------------------------------------------------------
1072 class SMS_Saved_List(SMS_Generic_List):
1073     _max_entries=20
1074     _valid_range=xrange(_max_entries)
1075     _field_num=5
1076     _datetime_index=1
1077     _from_index=2
1078     _body_index=4
1079     def __init__(self, phone):
1080         super(SMS_Saved_List, self).__init__(phone)
1081     def read(self):
1082         for i in self._valid_range:
1083             self._phone.progress(i, self._max_entries,
1084                                  'Reading SMS Saved Entry '+str(i))
1085             s=self._phone.get_sms_saved(i)
1086             if len(s)==self._field_num:
1087                 e=sms.SMSEntry()
1088                 e.folder=e.Folder_Saved
1089                 e.datetime=s[self._datetime_index]
1090                 e._from=s[self._from_index]
1091                 e.subject, txt=self._extract_body(s[self._body_index])
1092                 e.text=unicode(txt, errors='ignore')
1093                 self._data[e.id]=e
1094     def _extract_body(self, s):
1095         # extract different components from the main text body
1096         try:
1097             l=s.split(' ')
1098             ss=l[0]
1099             _subj=[]
1100             if ss[0]=='(':
1101                 while l:
1102                     _subj.append(ss)
1103                     l=l[1:]
1104                     if ss[-1]==')':
1105                         break
1106                     if l:
1107                         ss=l[0]
1108             if l:
1109                 return (' '.join(_subj), ' '.join(l))
1110             else:
1111                 return ('', ' '.join(_subj))
1112         except:
1113             return ('', s)
1114                 
1115 #-------------------------------------------------------------------------------
1116 class SMS_Sent_List(SMS_Generic_List):
1117     _max_entries=100
1118     _valid_range=xrange(_max_entries)
1119     _field_num=5
1120     _datetime_index=1
1121     _to_index=2
1122     _from_index=3
1123     _text_index=4
1124     def __init__(self, phone):
1125         super(SMS_Sent_List, self).__init__(phone)
1126     def read(self):
1127         for i in self._valid_range:
1128             self._phone.progress(i, self._max_entries,
1129                                  'Reading SMS Sent Entry '+str(i))
1130             s=self._phone.get_sms_sent(i)
1131             if len(s)==self._field_num:
1132                 e=sms.SMSEntry()
1133                 e.folder=e.Folder_Sent
1134                 e.datetime=s[self._datetime_index]
1135                 e._to=s[self._to_index]
1136                 e._from=s[self._from_index]
1137                 e.text=unicode(s[self._text_index], errors='ignore')
1138                 self._data[e.id]=e
1139 
1140 #-------------------------------------------------------------------------------
1141 class SMSList(object):
1142     def __init__(self, phone):
1143         self._phone=phone
1144         self._inbox=SMS_Inbox_List(phone)
1145         self._saved=SMS_Saved_List(phone)
1146         self._sent=SMS_Sent_List(phone)
1147         self._data={}
1148     def get(self):
1149         return self._data.copy()
1150     def read(self):
1151         self._inbox.read()
1152         self._data.update(self._inbox.get())
1153         self._saved.read()
1154         self._data.update(self._saved.get())
1155         self._sent.read()
1156         self._data.update(self._sent.get())
1157 
1158 #-------------------------------------------------------------------------------
1159 class CannedMsgList(SMS_Generic_List):
1160     _max_entries=20
1161     _valid_range=xrange(_max_entries)
1162     _field_num=4
1163     _text_index=3
1164     _data_key='canned_msg'
1165     _max_write_fields=3
1166     _count_index=0
1167     _timestamp_index=1
1168     _write_text_index=2
1169     def __init__(self, phone, data={}):
1170         super(CannedMsgList, self).__init__(phone)
1171         self._data=data
1172     def read(self):
1173         msg_list=[]
1174         for i in self._valid_range:
1175             self._phone.progress(i, self._max_entries,
1176                                  'Reading SMS Canned Msg '+str(i))
1177             s=self._phone.get_canned_msg(i)
1178             if len(s)==self._field_num:
1179                 msg_list.append({'text': s[self._text_index],
1180                                  'type': sms.CannedMsgEntry.user_type })
1181         self._data=msg_list
1182     def get(self):
1183         return copy.deepcopy(self._data, _nil=[])
1184     def validate(self):
1185         pass
1186     def write(self):
1187         msg_lst=[x['text'] for x in self._data if x['type']==sms.CannedMsgEntry.user_type]
1188         k=None
1189         for k,n in enumerate(msg_lst):
1190             if k>=self._max_entries:
1191                 # enough of that
1192                 break
1193             n=n.replace('"', '')
1194             self._phone.progress(k, self._max_entries,
1195                                  'Writing SMS Canned Msg '+str(k))
1196             s=`k`+','+self._phone.get_time_stamp()+',"'+n+'"'
1197             if not self._phone.save_canned_msg(s):
1198                 self._phone.log('Failed to write SMS Canned Msg entry: '+str(k))
1199         if k is None:
1200             k=0
1201         else:
1202             k+=1
1203         for i in xrange(k, self._max_entries):
1204             self._phone.progress(i, self._max_entries,
1205                                  'Deleting SMS Canned Msg entry: '+str(i))
1206             self._phone.save_canned_msg(`i`)
1207 
1208 #-------------------------------------------------------------------------------
1209 

Generated by PyXR 0.9.4