RE: Updates to vx8100
"Simon" <[email protected]>
| Newsgroups | gmane.comp.mobile.bitpim.devel |
|---|---|
| Message-ID | <000001c5a49b$2de16700$6400a8c0@HOME> |
Joe, >I also added GPSDATE to prototypeslg if you want to take advantage of it. I have made changes to use this new class. >Please test out your code from CVS, and if everything works ok, I'll ask Roger to do a build some time next week. It worked ok. I have also added the ability to read SMS messages. Code changes and diffs attached. Simon
com_lgvx8100.py
(application/octet-stream, 21.7 KB)
### BITPIM ### ### Copyright (C) 2003-2005 Roger Binns <[email protected]> ### Copyright (C) 2005 Simon Capper <[email protected]> ### ### This program is free software; you can redistribute it and/or modify ### it under the terms of the BitPim license as detailed in the LICENSE file. ### """Communicate with the LG VX8100 cell phone The VX8100 is substantially similar to the VX7000 but also supports video. """ # standard modules import re import time import cStringIO import sha # my modules import common import copy import p_lgvx8100 import com_lgvx7000 import com_brew import com_phone import com_lg import prototypes import bpcalendar import call_history import sms from prototypes import * class Phone(com_lgvx7000.Phone): "Talk to the LG VX8100 cell phone" desc="LG-VX8100" protocolclass=p_lgvx8100 serialsname='lgvx8100' builtinringtones= ('Low Beep Once', 'Low Beeps', 'Loud Beep Once', 'Loud Beeps', 'VZW Default Ringtone') + \ tuple(['Ringtone '+`n` for n in range(1,11)]) + \ ('No Ring',) ringtonelocations= ( # type index-file size-file directory-to-use lowest-index-to-use maximum-entries type-major ( 'ringers', 'dload/my_ringtone.dat', 'dload/my_ringtonesize.dat', 'brew/16452/ms', 100, 50, 1), ) builtinwallpapers = () # none wallpaperlocations= ( ( 'images', 'dload/image.dat', 'dload/imagesize.dat', 'brew/16452/mp', 100, 50, 0), ) def getfundamentals(self, results): """Gets information fundamental to interopating with the phone and UI. Currently this is: - 'uniqueserial' a unique serial number representing the phone - 'groups' the phonebook groups - 'wallpaper-index' map index numbers to names - 'ringtone-index' map index numbers to ringtone names This method is called before we read the phonebook data or before we write phonebook data. """ # use a hash of ESN and other stuff (being paranoid) self.log("Retrieving fundamental phone information") self.log("Phone serial number") results['uniqueserial']=sha.new(self.getfilecontents("nvm/$SYS.ESN")).hexdigest() # now read groups self.log("Reading group information") buf=prototypes.buffer(self.getfilecontents("pim/pbgroup.dat")) g=self.protocolclass.pbgroups() g.readfrombuffer(buf) self.logdata("Groups read", buf.getdata(), g) groups={} for i in range(len(g.groups)): if len(g.groups[i].name): # sometimes have zero length names groups[i]={'name': g.groups[i].name } results['groups']=groups self.getwallpaperindices(results) self.getringtoneindices(results) self.log("Fundamentals retrieved") return results def savegroups(self, data): groups=data['groups'] keys=groups.keys() keys.sort() g=self.protocolclass.pbgroups() for k in keys: e=self.protocolclass.pbgroup() e.name=groups[k]['name'] g.groups.append(e) buffer=prototypes.buffer() g.writetobuffer(buffer) self.logdata("New group file", buffer.getvalue(), g) self.writefile("pim/pbgroup.dat", buffer.getvalue()) _smspatterns={'Inbox': re.compile(r"^.*/inbox[0-9][0-9][0-9]\.dat$"), 'Outbox': re.compile(r"^.*/outbox[0-9][0-9][0-9]\.dat$"), 'Saved': re.compile(r"^.*/sf[0-9][0-9]\.dat$"), } def getsms(self, result): res={} # go through the sms directory looking for messages for item in self.getfilesystem("sms").values(): if item['type']=='file': folder=None for f,pat in self.smspatterns.items(): if pat.match(item['name']): folder=f break if folder=='Inbox': self._getinboxmessage(item['name'], res) elif folder=='Sent': self._getoutboxmessage(item['name'], res) elif folder=='Saved': self._getsavedmessage(item['name'], res) result['sms']=res return result def _getinboxmessage(self, file, res): buf=prototypes.buffer(self.getfilecontents(file)) sf=self.protocolclass.sms_in() sf.readfrombuffer(buf) self.logdata("SMS message in file "+file, buf.getdata(), sf) entry=sms.SMSEntry() entry.folder=entry.Folder_Inbox entry.datetime="%d%02d%02dT%02d%02d%02d" % (sf.GPStime) entry._from=self._getsender(sf.sender, sf.sender_length) entry.subject=sf.subject entry.locked=sf.locked txt="" if sf.num_msg_elements==1 and sf.bin_header1==0: txt=self._get_text_from_sms_msg_without_header(sf.msgs[0].msg, sf.msglengths[0].msglength) else: for i in range(sf.num_msg_elements): txt+=self._get_text_from_sms_msg_with_header(sf.msgs[i].msg, sf.msglengths[i].msglength) entry.text=unicode(txt, errors='ignore') entry.callback=sf.callback res[entry.id]=entry return def _getoutboxmessage(self, file, res): buf=prototypes.buffer(self.getfilecontents(file)) sf=self.protocolclass.sms_out() sf.readfrombuffer(buf) self.logdata("SMS message in file "+file, buf.getdata(), sf) entry=sms.SMSEntry() entry.folder=entry.Folder_Sent entry.datetime="%d%02d%02dT%02d%02d%02d" % (sf.GPStime) entry._to="" first=1 # add all the recipients to the _to field, separated with a : for i in range(9): if sf.recipients[i].number!="": if first: first=0 else: entry._to+=": " entry._to+=sf.recipients[i].number entry.subject=sf.subject txt="" if sf.num_msg_elements==1 and sf.messages[0].unknown2==0: txt=self._get_text_from_sms_msg_without_header(sf.messages[0].msg, sf.messages[0].length) else: for i in range(sf.num_msg_elements): txt+=self._get_text_from_sms_msg_with_header(sf.messages[i].msg, sf.messages[i].length) entry.text=unicode(txt, errors='ignore') entry.callback=sf.callback res[entry.id]=entry return def _getsavedmessage(self, file, res): buf=prototypes.buffer(self.getfilecontents(file)) sf=self.protocolclass.sms_saved() sf.readfrombuffer(buf) self.logdata("SMS message in file "+file, buf.getdata(), sf) entry=sms.SMSEntry() entry.folder=entry.Folder_Saved entry.datetime="%d%02d%02dT%02d%02d%02d" % (sf.GPStime) first=1 # add all the recipients to the _to field, separated with a : for i in range(10): if sf.recipients[i].number!="": if first: first=0 else: entry._to+=": " entry._to+=sf.recipients[i].number entry.subject=sf.subject txt="" if sf.num_msg_elements==1 and sf.messages[0].unknown2==0: txt=self._get_text_from_sms_msg_without_header(sf.messages[0].msg, sf.messages[0].length) else: for i in range(sf.num_msg_elements): txt+=self._get_text_from_sms_msg_with_header(sf.messages[i].msg, sf.messages[i].length) entry.text=unicode(txt, errors='ignore') entry.callback=sf.callback res[entry.id]=entry return def _get_text_from_sms_msg_without_header(self, msg, num_septets): out="" for i in range(num_septets): tmp = (msg[(i*7)/8].byte<<8) | msg[((i*7)/8) + 1].byte bit_index = 9 - ((i*7) % 8) out += chr((tmp >> bit_index) & 0x7f) return out def _get_text_from_sms_msg_with_header(self, msg, num_septets): data_len = ((msg[0].byte+1)*8+6)/7 seven_bits={} raw={} out={} # re-order the text into the correct order for separating into # 7-bit characters for i in range((num_septets*7)/8+7): if(i%7==0): for k in range(7): raw[i+6-k]=msg[i+k].byte # extract the 7-bit chars for i in range(num_septets+7): tmp = (raw[(i*7)/8]<<8) | raw[((i*7)/8) + 1] bit_index = 9 - ((i*7) % 8) seven_bits[i] = (tmp >> bit_index) & 0x7f # correct the byte order and remove the data portion of the message i=0 for i in range(num_septets+7): if(i%8==0): for k in range(8): if(i+7-k-data_len>=0): if i+k<num_septets+7: out[i+7-k-data_len]=seven_bits[i+k] res="" for i in range(num_septets-data_len): res+=chr(out[i]) return res def _getsender(self, raw, len): result="" for i in range(len): if(raw[i].byte==10): result+="0" else: result+="%d" % raw[i].byte return result def getcallhistory(self, result): res={} # read the incoming call history file self._readhistoryfile("pim/missed_log.dat", 'Missed', res) self._readhistoryfile("pim/outgoing_log.dat", 'Outgoing', res) self._readhistoryfile("pim/incoming_log.dat", 'Incoming', res) result['call_history']=res return result def _readhistoryfile(self, fname, folder, res): try: buf=prototypes.buffer(self.getfilecontents(fname)) ch=self.protocolclass.callhistory() ch.readfrombuffer(buf) self.logdata("Call History", buf.getdata(), ch) for call in ch.calls: if call.number=='': #empty record break entry=call_history.CallHistoryEntry() entry.folder=folder entry.datetime=((call.GPStime)) entry.number=call.number res[entry.id]=entry except com_brew.BrewNoSuchFileException: pass # do nothing if file doesn't exist return def getcalendar(self,result): res={} # Read exceptions file first try: buf=prototypes.buffer(self.getfilecontents("sch/newschexception.dat")) ex=self.protocolclass.scheduleexceptionfile() ex.readfrombuffer(buf) self.logdata("Calendar exceptions", buf.getdata(), ex) exceptions={} for i in ex.items: try: exceptions[i.pos].append( (i.year,i.month,i.day) ) except KeyError: exceptions[i.pos]=[ (i.year,i.month,i.day) ] except com_brew.BrewNoSuchFileException: exceptions={} # Now read schedule try: buf=prototypes.buffer(self.getfilecontents("sch/newschedule.dat")) if len(buf.getdata())<3: # file is empty, and hence same as non-existent raise com_brew.BrewNoSuchFileException() sc=self.protocolclass.schedulefile() self.logdata("Calendar", buf.getdata(), sc) sc.readfrombuffer(buf) for event in sc.events: # the vx8100 has a bad entry when the calender is empty # stop processing the calender when we hit this record if event.pos==0: #invalid entry break entry=bpcalendar.CalendarEntry() entry.description=event.description entry.start=event.start entry.end=event.end entry.vibrate=~(event.alarmindex_vibrate&0x1) # vibarate bit is inverted in phone 0=on, 1=off entry.repeat = self.makerepeat(event.repeat) min=event.alarmminutes hour=event.alarmhours if min==0x64 or hour==0x64: entry.alarm=None # no alarm set else: entry.alarm=hour*60+min entry.ringtone=result['ringtone-index'][event.ringtone]['name'] entry.snoozedelay=0 # check for exceptions and remove them if event.repeat[3] and exceptions.has_key(event.pos): for year, month, day in exceptions[event.pos]: entry.suppress_repeat_entry(year, month, day) res[entry.id]=entry assert sc.numactiveitems==len(res) except com_brew.BrewNoSuchFileException: pass # do nothing if file doesn't exist result['calendar']=res return result def makerepeat(self, repeat): # get all the variables out of the repeat tuple # and convert into a bpcalender RepeatEntry type,dow,interval,exceptions=repeat if type==0: repeat_entry=None else: repeat_entry=bpcalendar.RepeatEntry() if type==1: #daily repeat_entry.repeat_type=repeat_entry.daily repeat_entry.interval=interval elif type==5: #'monfri' repeat_entry.repeat_type=repeat_entry.daily repeat_entry.interval=0 elif type==2: #'weekly' repeat_entry.repeat_type=repeat_entry.weekly repeat_entry.dow=dow repeat_entry.interval=interval elif type==3: #'monthly' repeat_entry.repeat_type=repeat_entry.monthly repeat_entry.interval=interval repeat_entry.dow=0 elif type==6: #'monthly' #Xth Y day (e.g. 2nd friday each month) repeat_entry.repeat_type=repeat_entry.monthly repeat_entry.interval=interval #X repeat_entry.dow=dow #Y else: # =4 'yearly' repeat_entry.repeat_type=repeat_entry.yearly return repeat_entry def savecalendar(self, dict, merge): # ::TODO:: # what will be written to the files eventsf=self.protocolclass.schedulefile() exceptionsf=self.protocolclass.scheduleexceptionfile() # what are we working with cal=dict['calendar'] newcal={} keys=cal.keys() keys.sort() pos=1 # number of entries eventsf.numactiveitems=len(keys) # play with each entry for k in keys: # entry is what we will return to user entry=cal[k] data=self.protocolclass.scheduleevent() data.pos=eventsf.packetsize() data.description=entry.description data.start=entry.start data.end=entry.end self.setalarm(entry, data) data.ringtone=0 for i in dict['ringtone-index']: if dict['ringtone-index'][i]['name']==entry.ringtone: data.ringtone=i # check for exceptions and add them to the exceptions list exceptions=0 if entry.repeat!=None: for i in entry.repeat.suppressed: de=self.protocolclass.scheduleexception() de.pos=data.pos de.day=i.date.day de.month=i.date.month de.year=i.date.year exceptions=1 exceptionsf.items.append(de) if entry.repeat != None: data.repeat=(self.getrepeattype(entry, exceptions)) else: data.repeat=((0,0,0,0)) data.unknown1=0 data.unknown2=0 # put entry in nice shiny new dict we are building entry=copy.copy(entry) newcal[data.pos]=entry eventsf.events.append(data) # scribble everything out buf=prototypes.buffer() eventsf.writetobuffer(buf) self.logdata("Writing calendar", buf.getvalue(), eventsf) self.writefile("sch/newschedule.dat", buf.getvalue()) buf=prototypes.buffer() exceptionsf.writetobuffer(buf) self.logdata("Writing calendar exceptions", buf.getvalue(), exceptionsf) self.writefile("sch/newschexception.dat", buf.getvalue()) # fix passed in dict dict['calendar']=newcal return dict def getrepeattype(self, entry, exceptions): #convert the bpcalender type into vx8100 type repeat_entry=bpcalendar.RepeatEntry() if entry.repeat.repeat_type==repeat_entry.monthly: dow=entry.repeat.dow if entry.repeat.dow==0: # set interval for month type 4 to start day of month, (required by vx8100) interval=entry.start[2] type=3 else: interval=entry.repeat.interval type=6 elif entry.repeat.repeat_type==repeat_entry.daily: dow=entry.repeat.dow interval=entry.repeat.interval if entry.repeat.interval==0: type=5 else: type=1 elif entry.repeat.repeat_type==repeat_entry.weekly: dow=entry.repeat.dow interval=entry.repeat.interval type=2 elif entry.repeat.repeat_type==repeat_entry.yearly: # set interval to start day of month, (required by vx8100) interval=entry.start[2] # set dow to start month, (required by vx8100) dow=entry.start[1] type=4 return (type, dow, interval, exceptions) def setalarm(self, entry, data): # vx8100 only allows certain repeat intervals, adjust to fit, it also stores an index to the interval # bitpim does not support vibrate so turn it off for all alarms if entry.alarm>=2880: entry.alarm=2880 data.alarmminutes=0 data.alarmhours=48 data.alarmindex_vibrate=0x10 elif entry.alarm>=1440: entry.alarm=1440 data.alarmminutes=0 data.alarmhours=24 data.alarmindex_vibrate=0xe elif entry.alarm>=120: entry.alarm=120 data.alarmminutes=0 data.alarmhours=2 data.alarmindex_vibrate=0xc elif entry.alarm>=60: entry.alarm=60 data.alarmminutes=0 data.alarmhours=1 data.alarmindex_vibrate=0xa elif entry.alarm>=15: entry.alarm=15 data.alarmminutes=15 data.alarmhours=0 data.alarmindex_vibrate=0x8 elif entry.alarm>=10: entry.alarm=10 data.alarmminutes=10 data.alarmhours=0 data.alarmindex_vibrate=0x6 elif entry.alarm>=5: entry.alarm=5 data.alarmminutes=10 data.alarmhours=0 data.alarmindex_vibrate=0x4 elif entry.alarm>=0: entry.alarm=0 data.alarmminutes=0 data.alarmhours=0 data.alarmindex_vibrate=0x2 else: # no alarm data.alarmminutes=0x64 data.alarmhours=0x64 data.alarmindex_vibrate=1 # set the vibrate bit if data.alarmindex_vibrate > 1 and entry.vibrate==0: data.alarmindex_vibrate+=1 return parentprofile=com_lgvx7000.Profile class Profile(parentprofile): protocolclass=Phone.protocolclass serialsname=Phone.serialsname BP_Calendar_Version=3 WALLPAPER_WIDTH=176 WALLPAPER_HEIGHT=184 MAX_WALLPAPER_BASENAME_LENGTH=32 WALLPAPER_FILENAME_CHARS="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 ." WALLPAPER_CONVERT_FORMAT="jpg" MAX_RINGTONE_BASENAME_LENGTH=32 RINGTONE_FILENAME_CHARS="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 ." # there is an origin named 'aod' - no idea what it is for except maybe # 'all other downloads' # the 8010 doesn't have seperate origins - they are all dumped in "images" imageorigins={} imageorigins.update(common.getkv(parentprofile.stockimageorigins, "images")) def GetImageOrigins(self): return self.imageorigins # our targets are the same for all origins imagetargets={} imagetargets.update(common.getkv(parentprofile.stockimagetargets, "wallpaper", {'width': 176, 'height': 184, 'format': "JPEG"})) imagetargets.update(common.getkv(parentprofile.stockimagetargets, "pictureid", {'width': 176, 'height': 184, 'format': "JPEG"})) imagetargets.update(common.getkv(parentprofile.stockimagetargets, "outsidelcd", {'width': 96, 'height': 80, 'format': "JPEG"})) imagetargets.update(common.getkv(parentprofile.stockimagetargets, "fullscreen", {'width': 176, 'height': 220, 'format': "JPEG"})) def GetTargetsForImageOrigin(self, origin): return self.imagetargets def __init__(self): parentprofile.__init__(self) _supportedsyncs=( ('phonebook', 'read', None), # all phonebook reading ('calendar', 'read', None), # all calendar reading ('wallpaper', 'read', None), # all wallpaper reading ('ringtone', 'read', None), # all ringtone reading ('sms', 'read', None), # all SMS list reading ('phonebook', 'write', 'OVERWRITE'), # only overwriting phonebook ('calendar', 'write', 'OVERWRITE'), # only overwriting calendar ('wallpaper', 'write', 'MERGE'), # merge and overwrite wallpaper ('wallpaper', 'write', 'OVERWRITE'), ('ringtone', 'write', 'MERGE'), # merge and overwrite ringtone ('ringtone', 'write', 'OVERWRITE'), ('call_history', 'read', None), )
com_lgvx8100.py.diff
(application/octet-stream, 8.4 KB)
Index: com_lgvx8100.py
===================================================================
RCS file: /cvsroot/bitpim/bitpim/com_lgvx8100.py,v
retrieving revision 1.2
diff -u -r1.2 com_lgvx8100.py
--- com_lgvx8100.py 17 Aug 2005 03:53:04 -0000 1.2
+++ com_lgvx8100.py 19 Aug 2005 08:26:53 -0000
@@ -14,6 +14,7 @@
"""
# standard modules
+import re
import time
import cStringIO
import sha
@@ -29,6 +30,7 @@
import prototypes
import bpcalendar
import call_history
+import sms
from prototypes import *
@@ -96,7 +98,6 @@
groups=data['groups']
keys=groups.keys()
keys.sort()
-
g=self.protocolclass.pbgroups()
for k in keys:
e=self.protocolclass.pbgroup()
@@ -107,6 +108,157 @@
self.logdata("New group file", buffer.getvalue(), g)
self.writefile("pim/pbgroup.dat", buffer.getvalue())
+ _smspatterns={'Inbox': re.compile(r"^.*/inbox[0-9][0-9][0-9]\.dat$"),
+ 'Outbox': re.compile(r"^.*/outbox[0-9][0-9][0-9]\.dat$"),
+ 'Saved': re.compile(r"^.*/sf[0-9][0-9]\.dat$"),
+ }
+
+ def getsms(self, result):
+ res={}
+ # go through the sms directory looking for messages
+ for item in self.getfilesystem("sms").values():
+ if item['type']=='file':
+ folder=None
+ for f,pat in self.smspatterns.items():
+ if pat.match(item['name']):
+ folder=f
+ break
+ if folder=='Inbox':
+ self._getinboxmessage(item['name'], res)
+ elif folder=='Sent':
+ self._getoutboxmessage(item['name'], res)
+ elif folder=='Saved':
+ self._getsavedmessage(item['name'], res)
+ result['sms']=res
+ return result
+
+ def _getinboxmessage(self, file, res):
+ buf=prototypes.buffer(self.getfilecontents(file))
+ sf=self.protocolclass.sms_in()
+ sf.readfrombuffer(buf)
+ self.logdata("SMS message in file "+file, buf.getdata(), sf)
+ entry=sms.SMSEntry()
+ entry.folder=entry.Folder_Inbox
+ entry.datetime="%d%02d%02dT%02d%02d%02d" % (sf.GPStime)
+ entry._from=self._getsender(sf.sender, sf.sender_length)
+ entry.subject=sf.subject
+ entry.locked=sf.locked
+ txt=""
+ if sf.num_msg_elements==1 and sf.bin_header1==0:
+ txt=self._get_text_from_sms_msg_without_header(sf.msgs[0].msg, sf.msglengths[0].msglength)
+ else:
+ for i in range(sf.num_msg_elements):
+ txt+=self._get_text_from_sms_msg_with_header(sf.msgs[i].msg, sf.msglengths[i].msglength)
+ entry.text=unicode(txt, errors='ignore')
+ entry.callback=sf.callback
+ res[entry.id]=entry
+ return
+
+ def _getoutboxmessage(self, file, res):
+ buf=prototypes.buffer(self.getfilecontents(file))
+ sf=self.protocolclass.sms_out()
+ sf.readfrombuffer(buf)
+ self.logdata("SMS message in file "+file, buf.getdata(), sf)
+ entry=sms.SMSEntry()
+ entry.folder=entry.Folder_Sent
+ entry.datetime="%d%02d%02dT%02d%02d%02d" % (sf.GPStime)
+ entry._to=""
+ first=1
+ # add all the recipients to the _to field, separated with a :
+ for i in range(9):
+ if sf.recipients[i].number!="":
+ if first:
+ first=0
+ else:
+ entry._to+=": "
+ entry._to+=sf.recipients[i].number
+ entry.subject=sf.subject
+ txt=""
+ if sf.num_msg_elements==1 and sf.messages[0].unknown2==0:
+ txt=self._get_text_from_sms_msg_without_header(sf.messages[0].msg, sf.messages[0].length)
+ else:
+ for i in range(sf.num_msg_elements):
+ txt+=self._get_text_from_sms_msg_with_header(sf.messages[i].msg, sf.messages[i].length)
+ entry.text=unicode(txt, errors='ignore')
+ entry.callback=sf.callback
+ res[entry.id]=entry
+ return
+
+ def _getsavedmessage(self, file, res):
+ buf=prototypes.buffer(self.getfilecontents(file))
+ sf=self.protocolclass.sms_saved()
+ sf.readfrombuffer(buf)
+ self.logdata("SMS message in file "+file, buf.getdata(), sf)
+ entry=sms.SMSEntry()
+ entry.folder=entry.Folder_Saved
+ entry.datetime="%d%02d%02dT%02d%02d%02d" % (sf.GPStime)
+ first=1
+ # add all the recipients to the _to field, separated with a :
+ for i in range(10):
+ if sf.recipients[i].number!="":
+ if first:
+ first=0
+ else:
+ entry._to+=": "
+ entry._to+=sf.recipients[i].number
+ entry.subject=sf.subject
+ txt=""
+ if sf.num_msg_elements==1 and sf.messages[0].unknown2==0:
+ txt=self._get_text_from_sms_msg_without_header(sf.messages[0].msg, sf.messages[0].length)
+ else:
+ for i in range(sf.num_msg_elements):
+ txt+=self._get_text_from_sms_msg_with_header(sf.messages[i].msg, sf.messages[i].length)
+ entry.text=unicode(txt, errors='ignore')
+ entry.callback=sf.callback
+ res[entry.id]=entry
+ return
+
+ def _get_text_from_sms_msg_without_header(self, msg, num_septets):
+ out=""
+ for i in range(num_septets):
+ tmp = (msg[(i*7)/8].byte<<8) | msg[((i*7)/8) + 1].byte
+ bit_index = 9 - ((i*7) % 8)
+ out += chr((tmp >> bit_index) & 0x7f)
+ return out
+
+ def _get_text_from_sms_msg_with_header(self, msg, num_septets):
+ data_len = ((msg[0].byte+1)*8+6)/7
+ seven_bits={}
+ raw={}
+ out={}
+ # re-order the text into the correct order for separating into
+ # 7-bit characters
+ for i in range((num_septets*7)/8+7):
+ if(i%7==0):
+ for k in range(7):
+ raw[i+6-k]=msg[i+k].byte
+ # extract the 7-bit chars
+ for i in range(num_septets+7):
+ tmp = (raw[(i*7)/8]<<8) | raw[((i*7)/8) + 1]
+ bit_index = 9 - ((i*7) % 8)
+ seven_bits[i] = (tmp >> bit_index) & 0x7f
+ # correct the byte order and remove the data portion of the message
+ i=0
+ for i in range(num_septets+7):
+ if(i%8==0):
+ for k in range(8):
+ if(i+7-k-data_len>=0):
+ if i+k<num_septets+7:
+ out[i+7-k-data_len]=seven_bits[i+k]
+ res=""
+ for i in range(num_septets-data_len):
+ res+=chr(out[i])
+ return res
+
+ def _getsender(self, raw, len):
+ result=""
+ for i in range(len):
+ if(raw[i].byte==10):
+ result+="0"
+ else:
+ result+="%d" % raw[i].byte
+ return result
+
def getcallhistory(self, result):
res={}
# read the incoming call history file
@@ -127,13 +279,8 @@
break
entry=call_history.CallHistoryEntry()
entry.folder=folder
- # convert from GPS to unix time
- unixtime=315964800+call.GPStime
- t=time.gmtime(315964800+call.GPStime)
- entry.datetime=((t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec))
+ entry.datetime=((call.GPStime))
entry.number=call.number
- #use the timestamp as the ID, it is unique
- entry.id=call.GPStime
res[entry.id]=entry
except com_brew.BrewNoSuchFileException:
pass # do nothing if file doesn't exist
@@ -428,11 +575,12 @@
('calendar', 'read', None), # all calendar reading
('wallpaper', 'read', None), # all wallpaper reading
('ringtone', 'read', None), # all ringtone reading
+ ('sms', 'read', None), # all SMS list reading
('phonebook', 'write', 'OVERWRITE'), # only overwriting phonebook
('calendar', 'write', 'OVERWRITE'), # only overwriting calendar
('wallpaper', 'write', 'MERGE'), # merge and overwrite wallpaper
('wallpaper', 'write', 'OVERWRITE'),
- ('ringtone', 'write', 'MERGE'), # merge and overwrite ringtone
+ ('ringtone', 'write', 'MERGE'), # merge and overwrite ringtone
('ringtone', 'write', 'OVERWRITE'),
('call_history', 'read', None),
)
p_lgvx8100.p
(application/octet-stream, 9.6 KB) - not displayed
p_lgvx8100.p.diff
(application/octet-stream, 6.7 KB)
Index: p_lgvx8100.p
===================================================================
RCS file: /cvsroot/bitpim/bitpim/p_lgvx8100.p,v
retrieving revision 1.2
diff -u -r1.2 p_lgvx8100.p
--- p_lgvx8100.p 17 Aug 2005 03:53:04 -0000 1.2
+++ p_lgvx8100.p 19 Aug 2005 08:05:21 -0000
@@ -97,7 +97,7 @@
* LIST {'elementclass': scheduleevent} +events
PACKET call:
- 4 UINT GPStime #no. of seconds since 0h 1-6-80, based off local time.
+ 4 GPSDATE GPStime #no. of seconds since 0h 1-6-80, based off local time.
4 UINT unknown2 # different for each call
4 UINT duration #seconds, not certain about length of this field
49 STRING {'raiseonunterminatedread': False} number
@@ -112,3 +112,135 @@
1 UINT unknown1
* LIST {'elementclass': call} +calls
+###
+### SMS
+###
+#
+# There are 3 types of SMS records, The inbox, outbox and unsent (pending)
+# Unlike other records in the phone each message is stored in a separate file
+# All messages are in the 'sms' directory in the root of the phone
+# Inbox messages are in files called 'inbox000.dat', the number 000 varies for
+# each message, typically there are no gaps in the numbering, but gaps can appear
+# if a message is deleted.
+# Outbox message are named 'outbox000.dat', unsent messages are named 'sf00.dat',
+# only two digit file name that suggests a max of 100 message for this type.
+# Messages in the outbox get updated when the message is received by the recipient,
+# they contain a delivery flag and a delivery time for all the possible 10 recipients.
+# The vx8100 supports SMS contatination, this allows you to send text messages that are
+# longer than 160 characters. The format is different for these type of messages, but
+# it is supported by this implementation.
+# The vx8100 also allows you to put small graphics, sounds and animations in a message.
+# This implementation does not support these, if they are contained in a message they
+# will be ignored and just the text will be shown when you view the message in bitpim.
+# The text in the the messages is stored in 7-bit characters, so they have
+# to be unpacked, in concatinated messages and messages with embeded graphics etc. the
+# format uses the GSM 03.38 specified format, a good example of this can be found at
+# "http://www.dreamfabric.com/sms/hello.html".
+# For simple messages less than 161 characters with no graphics the format is simpler,
+# the 7-bit characters are just packed into memory in the order they appear in the
+# message.
+
+PACKET msg_record:
+ 1 UINT unknown1 # 0
+ 1 UINT unknown2 # 0=simple text, 1=binary/concatinated
+ 1 UINT unknown3 # 0=simple text, 1=binary/concatinated
+ 1 UINT unknown4 # 0
+ 1 UINT unknown6 # 2=simple text, 9=binary/concatinated
+ 1 UINT length
+ * LIST {'length': 219} +msg:
+ 1 UINT byte "individual byte of message"
+
+PACKET recipient_record:
+ 49 STRING number
+ 1 UINT status # 1 when sent, 5 when received
+ 4 LGCALDATE timesent
+ 4 LGCALDATE timereceived
+ 1 UINT unknown1 # 0 when not received, set to 1 when received
+ 85 DATA unknown2
+
+PACKET sms_saved:
+ 4 UINT unknown1 # set to 1
+ 4 GPSDATE GPStime # num seconds since 0h 1-6-80, time message received by phone
+ 6 DATA unknown2
+ 4 LGCALDATE timesent # time the message was sent
+ 6 DATA unknown3
+ 21 STRING subject
+ 1 UINT unknown4
+ 1 UINT num_msg_elements # up to 7
+ * LIST {'elementclass': msg_record, 'length': 7} +messages
+ 1 UINT unknown5
+ 1 UINT priority # 0=normal, 1=high
+ 12 DATA unknown7
+ 3 DATA unknown8 # set to 01,00,01
+ 68 STRING callback
+ * LIST {'elementclass': recipient_record, 'length': 10} +recipients
+ 937 DATA unknown9 # all zeros
+
+PACKET sms_out:
+ 4 UINT index # starting from 1, unique
+ 2 UINT unknown1 # zero
+ 4 LGCALDATE timesent # time the message was sent
+ 2 UINT unknown2 # zero
+ 4 GPSDATE GPStime # num seconds since 0h 1-6-80, time message received by phone
+ 21 STRING subject
+ 1 UINT unknown4
+ 1 UINT num_msg_elements # up to 7
+ * LIST {'elementclass': msg_record, 'length': 7} +messages
+ 1 UINT unknown5
+ 1 UINT priority # 0=normal, 1=high
+ 12 DATA unknown7
+ 3 DATA unknown8 # set to 01,00,01
+ 68 STRING callback
+ * LIST {'elementclass': recipient_record,'length': 9} +recipients
+ 49 STRING recipient10number
+ 1 UINT recipient10status # 1 when sent, 5 when received
+ 4 LGCALDATE recipient10sent
+ 4 LGCALDATE recipient10received
+ 1 UINT recipient10unknown1 # 0, set to 1 when received
+ 42 DATA unknown9
+
+PACKET SMSINBOXMSGFRAGMENT:
+ * LIST {'length': 181} +msg:
+ 1 UINT byte "individual byte of message"
+
+PACKET sms_in:
+ 4 UINT msg_index1
+ 4 UINT msg_index2 # equal to the numerical part of the filename eg inbox002.dat
+ 2 UINT unknown2 # set to 0 for simple message and 3 for binary
+ 6 SMSDATE timesent
+ 3 UINT unknown
+ 1 UINT callback_length
+ 38 STRING callback
+ 1 UINT sender_length
+ * LIST {'length': 38} +sender:
+ 1 UINT byte "individual byte of senders phone number"
+ 12 DATA unknown3 # set to zeros
+ 4 LGCALDATE lg_time # time the message was sent
+ 3 UINT unknown4 # set to zeros
+ 4 GPSDATE GPStime # num seconds since 0h 1-6-80, time message received by phone
+ 4 UINT unknown5 # zero
+ 1 UINT read # 1 if message has been read, 0 otherwise
+ 1 UINT locked # 1 if the message is locked, 0 otherwise
+ 2 UINT unknown8 # zero
+ 1 UINT priority # 1 if the message is high priority, 0 otherwise
+ 6 DATA unknown11 # zero
+ 21 STRING subject
+ 1 UINT bin_header1 # 0 in simple message 1 if the message contains a binary header
+ 1 UINT bin_header2 # 0 in simple message 9 if the message contains a binary header
+ 2 UINT unknown6 # zeros
+ 2 UINT multipartID # multi-part message ID, used for concatinated messages only
+ 2 UINT unknown14
+ 1 UINT bin_header3 # 0 in simple message 2 if the message contains a binary header
+ 1 UINT num_msg_elements # max 20 elements (guessing on max here)
+ * LIST {'length': 20} +msglengths:
+ 1 UINT msglength "lengths of individual messages in septets"
+ * LIST {'length': 20, 'elementclass': SMSINBOXMSGFRAGMENT} +msgs
+ # 181 bytes per message,
+ # 20 messages, 7-bit ascii for simple text. for binary header
+ # first byte is header length not including the length byte
+ # rest depends on content of header, not known at this time.
+ # text alway follows the header although the format it different
+ # than a simple SMS
+ 60 DATA unknown12
+ 33 STRING senders_name
+ 169 DATA unknown9 # ?? inlcudes senders phone number in ascii