'========================================================== ' SMS,EMS Decoder ' 2005-2-20 '1.Description ' This class decode a SMS or EMS PDU code to a certain 'class. You can use it in your software to read SMSs and 'EMSs. All of this is done under GSM 03.40. I tested it 'on my SIEMENS M55 and NOKIA 8xxx and it works well. '2.Useage ' If you know what type of PDU code, you can create a 'new instance of class like DIM s as SMS(myPDUCode) 'When instance is created, you read its public variable 'to get what you want. ' When TP_DCS=0, PDU code is coded from 7bit 'charactor (see GSM 03.38), use shared function 'Deocde7Bit to decode it. ' When TP_DCS=8, PDU code is coded from Unicode 'charactor (see GSM 03.38), use shared funtion 'DecodeUnicode to decode it. '3.Bugs ' So far in my tests I found none. '4.When you use it ' You can freely use it or modify it in your program, 'but when you find bugs or improved it please publish it 'or send one copy to me. Thanks '5.About me ' I am writting a program which can list folders and 'files in SIEMENS M55 mobile phone. It can also read 'and send SMS,EMS. Some documents are hard to find on 'internet, but I keep on my mind to study it and finally 'I found it is full of interests. ' I like freedom, so'I exchange my ideas with all of 'the world. It is so happy that you can use my classes! ' In the end, sorry for my poor english. '6.Contact me ' Email:hesicong@mail.sc.cninfo.net ' QQ:38288890 ' Homepage:http://dream-world.nease.net (Chinese) ' Thanks for using it! ' ----By HESICONG ' 'Revision: ' 2004-10-29: ' Fix bug in decode "@" charactor. ' Add functions in "decode 7 bit code to english" region ' 2005-2-20: ' Final version released. Fixed minor bugs. Imports System.text Namespace SMSNamespace SMS Namespace DecoderNamespace Decoder PublicMustInheritClass SMSBaseClass SMSBase 'Note all of following various with TP_ can be found in GSM 03.40 Public SCAddressLength AsByte'Service Center Address length Public SCAddressType AsByte'Service Center Type[See GSM 03.40] Public SCAddressValue AsString'Service Center nuber Public FirstOctet AsByte'See GSM 03.40 Public TP_PID AsByte Public TP_DCS AsByte Public TP_UDL AsByte Public TP_UD AsString Public Text AsString Public Type As SMSType Public UserData AsString PublicEnum SMSTypeEnum SMSType SMS_RECEIVED =0 SMS_STATUS_REPORT =2 SMS_SUBMIT =1 EMS_RECEIVED =64'It is "Reserved" on my phone?? EMS_SUBMIT =65 End Enum PublicMustOverrideSub GetOrignalData()Sub GetOrignalData(ByVal PDUCode AsString) 'Get a byte from PDU string SharedFunction GetByte()Function GetByte(ByRef PDUCode AsString) AsByte Dim r AsByte=Val("&H"+Mid(PDUCode, 1, 2)) PDUCode =Mid(PDUCode, 3) Return r End Function 'Get a string of certain length SharedFunction GetString()Function GetString(ByRef PDUCode AsString, ByVal Length AsInteger) AsString Dim r AsString=Mid(PDUCode, 1, Length) PDUCode =Mid(PDUCode, Length +1) Return r End Function 'Get date from SCTS format SharedFunction GetDate()Function GetDate(ByRef SCTS AsString) AsDate Dimyear, month, day, hour, minute, second, timezone AsInteger year=Val(Swap(GetString(SCTS, 2))) +2000 month=Val(Swap(GetString(SCTS, 2))) day=Val(Swap(GetString(SCTS, 2))) hour=Val(Swap(GetString(SCTS, 2))) minute=Val(Swap(GetString(SCTS, 2))) second=Val(Swap(GetString(SCTS, 2))) timezone =Val(Swap(GetString(SCTS, 2))) Dim result AsNewDate(year, month, day, hour, minute, second) Return result End Function 'Swap two bit SharedFunction Swap()Function Swap(ByRef TwoBitStr AsString) AsString Dim c() AsChar= TwoBitStr.ToCharArray Dim t AsChar t = c(0) c(0) = c(1) c(1) = t Return (c(0) + c(1)).ToString End Function 'Get phone address SharedFunction GetAddress()Function GetAddress(ByRef Address AsString) AsString Dim tmpChar AsChar() = Address.ToCharArray Dim i AsInteger, result AsString For i =0To tmpChar.GetUpperBound(0) Step2 result += Swap(tmpChar(i) + tmpChar(i +1)) Next IfInStr(result, "F") Then result =Mid(result, 1, result.Length -1) Return result End Function SharedFunction GetSMSType()Function GetSMSType(ByVal PDUCode AsString) As SMSBase.SMSType 'Get first october Dim FirstOctet AsByte Dim L AsInteger= SMSBase.GetByte(PDUCode) SMSBase.GetByte(PDUCode) SMSBase.GetString(PDUCode, (L -1) *2) FirstOctet = SMSBase.GetByte(PDUCode) '[Chinese]取得特征码 '[Chinese]取得基本码 最后两个bit + 是否有header作为标记 'Get base code. Use last 2 bit and whether there's a header as remark Dim t1 AsInteger= FirstOctet And3'00000011 Dim t2 AsInteger= FirstOctet And64'01000000 '[Chinese]特别处理 If t1 =3And t2 =64ThenReturn SMSBase.SMSType.EMS_SUBMIT Return t1 + t2 End Function 'Deoce a unicode string SharedFunction DecodeUnicode()Function DecodeUnicode(ByVal strUnicode AsString) AsString Dim Code AsString Dim i, j AsInteger Dim c() AsString'temp ReDim c(strUnicode.Length /4) '2 Byte a Unicode char For j =0To strUnicode.Length \4-1 Dim d() AsChar= strUnicode.ToCharArray(j *4, 4) c(j) ="&H"&CType(d, String) c(j) =ChrW(Val(c(j))) Code += c(j) Next Return Code End Function 'Deocde 7Bit to english#Region "'Deocde 7Bit to english" '2004-10-29:Region added 'Fixed decode "@" charactor 'I use a new method, it is easily to understand but look much longer than before. SharedFunction InvertHexString()Function InvertHexString(ByVal HexString AsString) AsString 'For example: '123456 '===> '563412 Dim Result AsNew StringBuilder Dim i AsInteger For i = HexString.Length -2To0Step-2 Result.Append(HexString.Substring(i, 2)) Next Return Result.ToString End Function SharedFunction ByteToBinary()Function ByteToBinary(ByVal Dec AsByte) AsString Dim Result AsString Dim Temp AsByte= Dec Do Result = (Temp Mod2) & Result If Temp =1Or Temp =0ThenExitDo Temp = Temp \2 Loop Result = Result.PadLeft(8, "0") Return Result End Function SharedFunction BinaryToInt()Function BinaryToInt(ByVal Binary AsString) AsInteger Dim Result AsInteger Dim i AsInteger For i =0To Binary.Length -1 Result = Result +Val(Binary.Substring(Binary.Length - i -1, 1)) *2^ i Next Return Result End Function SharedFunction Decode7Bit()Function Decode7Bit(ByVal str7BitCode AsString, ByVal charCount AsInteger) AsString Dim Inv7BitCode AsString= InvertHexString(str7BitCode) Dim Binary AsString Dim Result AsString Dim i AsInteger For i =0To Inv7BitCode.Length -1Step2 Binary += ByteToBinary(Val("&H"& Inv7BitCode.Substring(i, 2))) Next Dim Temp AsInteger For i =1To charCount Temp = BinaryToInt(Binary.Substring(Binary.Length - i *7, 7)) 'There is a problem: '"@" charactor is decoded to binary "0000000", but its Ascii Code is 64!! 'Don't know what to do with it,maybe it is a bug! If Temp =0Then Temp =64 Result = Result +ChrW(Temp) Next Return (Result) End Function #End Region End Class PublicClass SMS_RECEIVEDClass SMS_RECEIVED Inherits SMSBase Public SrcAddressLength AsByte Public SrcAddressType AsByte Public SrcAddressValue AsString Public TP_SCTS AsDate Sub New()SubNew(ByVal PDUCode AsString) Type = SMSBase.SMSType.SMS_RECEIVED GetOrignalData(PDUCode) End Sub PublicOverridesSub GetOrignalData()Sub GetOrignalData(ByVal PDUCode AsString) SCAddressLength = GetByte(PDUCode) SCAddressType = GetByte(PDUCode) SCAddressValue = GetAddress((GetString(PDUCode, (SCAddressLength -1) *2))) FirstOctet = GetByte(PDUCode) SrcAddressLength = GetByte(PDUCode) SrcAddressType = GetByte(PDUCode) SrcAddressLength += SrcAddressLength Mod2 SrcAddressValue = GetAddress((GetString(PDUCode, SrcAddressLength))) TP_PID = GetByte(PDUCode) TP_DCS = GetByte(PDUCode) TP_SCTS = GetDate(GetString(PDUCode, 14)) TP_UDL = GetByte(PDUCode) TP_UD = GetString(PDUCode, TP_UDL *2) End Sub End Class PublicClass SMS_SUBMITClass SMS_SUBMIT Inherits SMSBase Public TP_MR AsByte Public DesAddressLength AsByte Public DesAddressType AsByte Public DesAddressValue AsString Public TP_VP AsByte Sub New()SubNew(ByVal PDUCode AsString) Type = SMSBase.SMSType.SMS_SUBMIT GetOrignalData(PDUCode) End Sub PublicOverridesSub GetOrignalData()Sub GetOrignalData(ByVal PDUCode AsString) SCAddressLength = GetByte(PDUCode) SCAddressType = GetByte(PDUCode) SCAddressValue = GetAddress((GetString(PDUCode, (SCAddressLength -1) *2))) FirstOctet = GetByte(PDUCode) TP_MR = GetByte(PDUCode) DesAddressLength = GetByte(PDUCode) DesAddressType = GetByte(PDUCode) DesAddressLength += DesAddressLength Mod2 DesAddressValue = GetAddress((GetString(PDUCode, DesAddressLength))) TP_PID = GetByte(PDUCode) TP_DCS = GetByte(PDUCode) TP_VP = GetByte(PDUCode) TP_UDL = GetByte(PDUCode) TP_UD = GetString(PDUCode, TP_UDL *2) End Sub End Class PublicClass EMS_RECEIVEDClass EMS_RECEIVED Inherits SMS_RECEIVED PublicStructure InfoElemStructure InfoElem 'See document "How to create EMS" Public Identifier AsByte Public Length AsByte Public Data AsString End Structure Public TP_UDHL AsByte Public IE() As InfoElem Sub New()SubNew(ByVal PDUCode AsString) MyBase.New(PDUCode) End Sub PublicOverridesSub GetOrignalData()Sub GetOrignalData(ByVal PDUCode AsString) SCAddressLength = GetByte(PDUCode) SCAddressType = GetByte(PDUCode) SCAddressValue = GetAddress(GetString(PDUCode, (SCAddressLength -1) *2)) FirstOctet = GetByte(PDUCode) SrcAddressLength = GetByte(PDUCode) SrcAddressType = GetByte(PDUCode) SrcAddressLength += SrcAddressLength Mod2 SrcAddressValue = GetAddress((GetString(PDUCode, SrcAddressLength))) TP_PID = GetByte(PDUCode) TP_DCS = GetByte(PDUCode) TP_SCTS = GetDate(GetString(PDUCode, 14)) TP_UDL = GetByte(PDUCode) TP_UDHL = GetByte(PDUCode) IE = GetIE(GetString(PDUCode, TP_UDHL *2)) TP_UD = GetString(PDUCode, TP_UDL *2) End Sub 'Get Informat Elements SharedFunction GetIE()Function GetIE(ByVal IECode AsString) As InfoElem() Dim tmp AsString= IECode, t AsInteger=0 Dim result() As InfoElem DoUntil IECode ="" ReDimPreserve result(t) With result(t) .Identifier = GetByte(IECode) .Length = GetByte(IECode) .Data = GetString(IECode, .Length *2) EndWith t +=1 Loop Return result End Function End Class PublicClass EMS_SUBMITClass EMS_SUBMIT Inherits SMS_SUBMIT Sub New()SubNew(ByVal PDUCode AsString) MyBase.New(PDUCode) Type = SMSBase.SMSType.EMS_SUBMIT End Sub Public TP_UDHL AsByte Public IE() As EMS_RECEIVED.InfoElem PublicOverridesSub GetOrignalData()Sub GetOrignalData(ByVal PDUCode AsString) SCAddressLength = GetByte(PDUCode) SCAddressType = GetByte(PDUCode) SCAddressValue = GetAddress(GetString(PDUCode, (SCAddressLength -1) *2)) FirstOctet = GetByte(PDUCode) TP_MR = GetByte(PDUCode) DesAddressLength = GetByte(PDUCode) DesAddressType = GetByte(PDUCode) DesAddressLength += DesAddressLength Mod2 DesAddressValue = GetAddress(GetString(PDUCode, DesAddressLength)) TP_PID = GetByte(PDUCode) TP_DCS = GetByte(PDUCode) TP_VP = GetByte(PDUCode) TP_UDL = GetByte(PDUCode) TP_UDHL = GetByte(PDUCode) IE = EMS_RECEIVED.GetIE(GetString(PDUCode, TP_UDHL *2)) TP_UD = GetString(PDUCode, TP_UDL *2) End Sub End Class PublicClass SMS_STATUS_REPORTClass SMS_STATUS_REPORT Inherits SMS_RECEIVED Public TP_MR AsByte Public TP_DP AsDate Public Status As EnumStatus PublicEnum EnumStatusEnum EnumStatus Success =0 NotSend =96 NoResponseFromSME =98 End Enum Sub New()SubNew(ByVal PDUCode AsString) MyBase.New(PDUCode) Type = SMSBase.SMSType.SMS_STATUS_REPORT End Sub PublicOverridesSub GetOrignalData()Sub GetOrignalData(ByVal PDUCode AsString) SCAddressLength = GetByte(PDUCode) SCAddressType = GetByte(PDUCode) SCAddressValue = GetAddress(GetString(PDUCode, (SCAddressLength -1) *2)) FirstOctet = GetByte(PDUCode) TP_MR = GetByte(PDUCode) SrcAddressLength = GetByte(PDUCode) SrcAddressType = GetByte(PDUCode) SrcAddressLength += SrcAddressLength Mod2 SrcAddressValue = GetAddress(GetString(PDUCode, SrcAddressLength)) TP_SCTS = GetDate(GetString(PDUCode, 14)) TP_DP = GetDate(GetString(PDUCode, 14)) Status = GetByte(PDUCode) 'Status report do not have content so I set it a zero length string TP_UD ="" End Sub End Class PublicClass PDUDecoderClass PDUDecoder PublicStructure BaseInfoStructure BaseInfo Public SourceNumber AsString Public DestinationNumber AsString Public ReceivedDate AsDate Public Text AsString Public Type As SMS.Decoder.SMSBase.SMSType Public EMSTotolPiece AsInteger Public EMSCurrentPiece AsInteger Public StatusFromReport As SMS_STATUS_REPORT.EnumStatus Public DestinationReceivedDate End Structure Sub New()SubNew(ByVal PDUCode AsString) Decode(PDUCode) End Sub PublicSharedFunction Decode()Function Decode(ByVal PDUCode AsString) As BaseInfo Dim Result As BaseInfo Try Dim s AsObject Dim T As SMSBase.SMSType = SMSBase.GetSMSType(PDUCode) Result.Type = T SelectCase T Case SMSBase.SMSType.EMS_RECEIVED s =New EMS_RECEIVED(PDUCode) Result.SourceNumber = s.SrcAddressValue If s.SrcAddressType =&H91 Then Result.SourceNumber ="+"+ Result.SourceNumber Result.ReceivedDate = s.TP_SCTS IfNot (s.IE IsNothing) Then Dim Data AsString= s.IE(0).Data Result.EMSTotolPiece =CInt(Mid(Data, 5, 2)) Result.EMSCurrentPiece =CInt(Mid(Data, 7, 2)) EndIf Case SMSBase.SMSType.SMS_RECEIVED s =New SMS_RECEIVED(PDUCode) Result.SourceNumber = s.SrcAddressValue If s.SrcAddressType =&H91 Then Result.SourceNumber ="+"+ Result.SourceNumber Result.ReceivedDate = s.TP_SCTS Case SMSBase.SMSType.EMS_SUBMIT s =New EMS_SUBMIT(PDUCode) Result.DestinationNumber = s.DesAddressValue If s.DesAddressType =&H91 Then Result.DestinationNumber ="+"+ Result.DestinationNumber IfNot (s.IE IsNothing) Then Dim Data AsString= s.IE(0).Data Result.EMSTotolPiece =CInt(Mid(Data, 5, 2)) Result.EMSCurrentPiece =CInt(Mid(Data, 7, 2)) EndIf Case SMSBase.SMSType.SMS_SUBMIT s =New SMS_SUBMIT(PDUCode) Result.DestinationNumber = s.DesAddressValue If s.DesAddressType =&H91 Then Result.DestinationNumber ="+"+ Result.DestinationNumber Case SMSBase.SMSType.SMS_STATUS_REPORT s =New SMS_STATUS_REPORT(PDUCode) Result.SourceNumber = s.SrcAddressValue If s.SrcAddressType =&H91 Then Result.SourceNumber ="+"+ Result.SourceNumber Result.ReceivedDate = s.TP_SCTS Result.DestinationReceivedDate = s.TP_DP() Result.StatusFromReport = s.status CaseElse Stop EndSelect '########################### 'Correct when s is SMS type, no TP_UDL is found. 'Note:Only EMS has the TP_UDHL and TP_UDH see 3GPP TS 23.040 V6.5.0 (2004-09) '########################### If s.tp_DCS =0Then If T = SMSBase.SMSType.SMS_RECEIVED Or T = SMSBase.SMSType.SMS_STATUS_REPORT Or T = SMSBase.SMSType.SMS_SUBMIT Then '############################# 'add a parameter '############################ Result.Text = s.decode7bit(s.tp_UD, s.TP_UDL) EndIf If T = SMSBase.SMSType.EMS_RECEIVED Or T = SMSBase.SMSType.EMS_SUBMIT Then Result.Text = s.decode7bit(s.tp_ud, s.tp_udl -8* (1+ s.tp_udhl) /7) EndIf Else Result.Text = s.DecodeUnicode(s.TP_UD) EndIf Catch err As Exception Result.Text ="PDU解码错误:"& PDUCode EndTry Return Result End Function End Class End Namespace End Namespace