📄 smsdecoder.py
字号:
__license__ = """
This file was part of DoomiN's Phone Manager program.
Copyright 2003 by Dominik Pytlewski <d (dot) pytlewski (at) gazeta (dot) pl>
DoomiN's Phone Manager is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as published by
the Free Software Foundation
DoomiN's Phone Manager is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DoomiN's Phone Manager; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Modifications by Florian Finkernagel, 2006.
Same GNU General Public License applies, of course.
"""
import re
import sys
import string
from string import *
import time
__char2bitsCache = None
def hex2int( p_hex):
return int (p_hex, 16)
def byteSwap( p_byte ):
return "%c%c" % ( p_byte[1], p_byte[0] )
def char2bits( p_char):
global __char2bitsCache
if __char2bitsCache == None:
__char2bitsCache = {}
if __char2bitsCache.has_key(p_char):
return __char2bitsCache[p_char]
inputChar = hex2int( p_char)
mask = 1
output = ''
bitNo = 1
while bitNo<=8 :
if inputChar & mask > 0:
output = '1'+output
else:
output = '0'+output
mask = mask<<1
bitNo+=1
__char2bitsCache[p_char] = output
return output
def bits2int( p_bits ):
mask=1
i = 0
end = len(p_bits)-1
result = 0
while i<=end:
if p_bits[end-i] == "1":
result += mask
mask = mask<<1
i+=1
return result
def decodeText16Bit( p_src):
chars = u''
i=0
while i<len(p_src):
h1 = p_src[i:i+2]
h2 = p_src[i+2:i+4]
c1 = hex2int(h1)
c2 = hex2int(h2)
unicodeIntChar = (256*c1)+c2
unicodeChar = unichr( unicodeIntChar ) #in original code, it is: chr ( unicodeIntChar )
chars += unicodeChar
i+=4
return chars
def decodeText8Bit( p_src):
return "8bit"
def decodeText7Bit( p_src, iTextLength):
bits = ''
i = 0
l = len(p_src)-1
while i<l:
bits += char2bits( p_src[i:i+2] )
i+=2
# now decoding those pseudo-8bit octets
char_nr = 0
i = 1
tmp_out = ''
acumul = ''
decoded = ''
while char_nr <= len(bits) and len(decoded) < iTextLength:
byte = bits[char_nr+i:char_nr+8]
tmp_out += byte +"+"+acumul+ " "
byte+=acumul
c = chr( bits2int( byte ))
decoded += c
acumul = bits[char_nr:char_nr+i]
i+=1
char_nr+=8
if i==8:
i=1
char_nr
decoded+=chr(bits2int(acumul))
acumul=''
tmp_out+="\n"
return decoded, int (char_nr / 8)
def parseTimeStamp( p_time ):
y = byteSwap( p_time[0:2] )
m = byteSwap( p_time[2:4] )
d = byteSwap( p_time[4:6] )
hour = byteSwap( p_time[6:8] )
min = byteSwap( p_time[8:10] )
sec = byteSwap( p_time[10:12] )
return "%s/%s/%s %s:%s" % (y,m,d,hour,min)
def translateSMSAlphabetToAscii ( str ):
#this could easily be exteded to actually output these unicode bytes...
translationTable = {0x00:0x0040,
0x01:0x00A3,
0x02:0x0024,
0x03:0x00A5,
0x04:0x00E8,
0x05:0x00E9,
0x06:0x00F9,
0x07:0x00EC,
0x08:0x00F2,
0x09:0x00E7,
0x0A:0x000A,
0x0B:0x00D8,
0x0C:0x00F8,
0x0D:0x000D,
0x0E:0x00C5,
0x0F:0x00E5,
#0x10:0x0394,
0x11:0x005F,
#0x12:0x03A6,
#0x13:0x0393,
#0x14:0x039B,
#0x15:0x03A9,
#0x16:0x03A0,
#0x17:0x03A8,
#0x18:0x03A3,
#0x19:0x0398,
#0x1A:0x039E,
0x1B:0x00A0,
#0x1B0A:0x000C,
#0x1B14:0x005E,
#0x1B28:0x007B,
#0x1B29:0x007D,
#0x1B2F:0x005C,
#0x1B3C:0x005B,
#0x1B3D:0x007E,
#0x1B3E:0x005D,
#0x1B40:0x007C,
#0x1B65:0x20AC,
0x1C:0x00C6,
0x1D:0x00E6,
0x1E:0x00DF,
0x1F:0x00C9,
0x20:0x0020,
0x21:0x0021,
0x22:0x0022,
0x23:0x0023,
0x24:0x00A4,
0x25:0x0025,
0x26:0x0026,
0x27:0x0027,
0x28:0x0028,
0x29:0x0029,
0x2A:0x002A,
0x2B:0x002B,
0x2C:0x002C,
0x2D:0x002D,
0x2E:0x002E,
0x2F:0x002F,
0x30:0x0030,
0x31:0x0031,
0x32:0x0032,
0x33:0x0033,
0x34:0x0034,
0x35:0x0035,
0x36:0x0036,
0x37:0x0037,
0x38:0x0038,
0x39:0x0039,
0x3A:0x003A,
0x3B:0x003B,
0x3C:0x003C,
0x3D:0x003D,
0x3E:0x003E,
0x3F:0x003F,
0x40:0x00A1,
0x41:0x0041,
0x42:0x0042,
0x43:0x0043,
0x44:0x0044,
0x45:0x0045,
0x46:0x0046,
0x47:0x0047,
0x48:0x0048,
0x49:0x0049,
0x4A:0x004A,
0x4B:0x004B,
0x4C:0x004C,
0x4D:0x004D,
0x4E:0x004E,
0x4F:0x004F,
0x50:0x0050,
0x51:0x0051,
0x52:0x0052,
0x53:0x0053,
0x54:0x0054,
0x55:0x0055,
0x56:0x0056,
0x57:0x0057,
0x58:0x0058,
0x59:0x0059,
0x5A:0x005A,
0x5B:0x00C4,
0x5C:0x00D6,
0x5D:0x00D1,
0x5E:0x00DC,
0x5F:0x00A7,
0x60:0x00BF,
0x61:0x0061,
0x62:0x0062,
0x63:0x0063,
0x64:0x0064,
0x65:0x0065,
0x66:0x0066,
0x67:0x0067,
0x68:0x0068,
0x69:0x0069,
0x6A:0x006A,
0x6B:0x006B,
0x6C:0x006C,
0x6D:0x006D,
0x6E:0x006E,
0x6F:0x006F,
0x70:0x0070,
0x71:0x0071,
0x72:0x0072,
0x73:0x0073,
0x74:0x0074,
0x75:0x0075,
0x76:0x0076,
0x77:0x0077,
0x78:0x0078,
0x79:0x0079,
0x7A:0x007A,
0x7B:0x00E4,
0x7C:0x00F6,
0x7D:0x00F1,
0x7E:0x00FC,
0x7F:0x00E0,
0x0642:0x0642, # unicode for kz
0x1575:0x1575,
0x1586:0x1586,
0x1575:0x1575
}
res = []
for x in str:
if translationTable.has_key(ord(x)):
res.append(chr(translationTable[ord(x)])) #try res.append(unichr(translationTable[ord(x)]))
else:
res.append('?')
return "".join(res)
#
## this class decodes sms stored in PDU format
#
class SmsDecoder:
def __init__( self, p_encodedText ):
self.errorStr = ''
self.success = self.decodeSms( p_encodedText )
self.p_enc = p_encodedText
return
#
# return decoded message
#
def getMessage( self ):
if self.success:
return self.decodedMsg
#
# return decoded phone number
#
def getPhoneNumber( self ):
if self.success:
return self.headers['sender_number']
#
# return time stamp
#
def getTimestamp( self ):
if self.success:
return self.headers['time_stamp']
else:
return False
def getUnixTimestamp (self):
if self.headers['time_stamp'] == False:
return -1
try:
t = time.strptime(self.headers['time_stamp'],'%y/%m/%d %H:%M')
except ValueError:
return -1
return int ( time.mktime(t) )
#
# decoding status
#
def isOk( self ):
return self.success
def __del__( self ):
return
def decodeSMSCNumber (self, sender_number):
s = 0
e = len(sender_number)-1
sender_len = len(sender_number) - 1
tmp_sender = ''
while s<e:
tmp_sender += sender_number[s+1]
tmp_sender += sender_number[s]
s+=2
if sender_len % 2 == 1:
# need to cut of 'F'
tmp_sender = tmp_sender[0:-1]
return tmp_sender
def decodeHeader( self, p_encSms ):
header = {}
smsc_len = hex2int( p_encSms[0:2] )
type_of_address = hex2int( p_encSms[2:4] )
smsc_number = ''
i = 4
while i/2 <= smsc_len:
smsc_number += p_encSms[i+1]
if i/2 != smsc_len:
smsc_number += p_encSms[i]
i+=2
header[ 'smsc_number' ] = smsc_number
## decoding sms sender information
pdu_flags = hex2int(p_encSms[i:i+2])
if pdu_flags & 1 == 0 and pdu_flags & 2 == 0:
pdu_is_sms_deliver = True
else:
pdu_is_sms_deliver = False
if pdu_flags & 32 != 0:
status_report_present = True
else:
status_report_present = False
if pdu_flags & 64 != 0:
user_header_present = True
else:
user_header_present = False
if pdu_flags & 64 != 0:
reply_path_present = True
else:
reply_path_present = False
if not pdu_is_sms_deliver:
self.errorStr = "isSmsDeliver != True"
i += 2
if pdu_is_sms_deliver:
sender_len = hex2int( p_encSms[i:i+2])
i += 2
sender_address_type = p_encSms[i:i+2]
i += 2
if sender_len % 2 == 1:
sender_number = p_encSms[i:i+sender_len+1]
i += sender_len+1
else:
sender_number = p_encSms[i:i+sender_len]
i += sender_len
tmp_sender = self.decodeSMSCNumber ( sender_number )
header['sender_number'] = tmp_sender
else:
# load target number
i += 2 #message reference number
target_len = hex2int( p_encSms[i:i+2])
i += 2 #/len
i += 2 #ton
if target_len %2 == 1:
header['sender_number'] = self.decodeSMSCNumber( p_encSms[i: i + target_len + 1])
i += target_len + 1
else:
header['sender_number'] = self.decodeSMSCNumber( p_encSms[i: i + target_len])
i += target_len
## load DATA CODING SCHEME and FLAGS
protocol_id = p_encSms[i:i+2]
i+=2
dcs_mode = p_encSms[i:i+2]
i+=2
dcs_bits = hex2int( dcs_mode)
if dcs_bits & 128 == 1 and dcs_bits & 64 == 1 and dcs_bits & 32 == 1 and dcs_bits & 16 == 1:
special_coding = True
else:
special_coding = False
if (dcs_bits & 8 == 0 and dcs_bits & 4 == 0) or special_coding == True:
user_data_coding = 7
elif dcs_bits & 8 >0 and dcs_bits & 4 == 0:
user_data_coding = 16
#ascii 8bit
elif dcs_bits & 8 == 0 and dcs_bits & 4 > 0:
user_data_coding = 8
#UCS2
else:
self.errorStr = "%s %s" %( 'unknown encoding == %d', str ( dcs_bits ) )
return FAlse
header['user_data_coding'] = user_data_coding
if pdu_is_sms_deliver:
send_time_stamp = p_encSms[i:i+14]
header['time_stamp'] = parseTimeStamp( send_time_stamp )
i+= 14
header['message_len'] = hex2int( p_encSms[i:i+2] )
i += 2
else:
#'no idea what these are', p_encSms[i:i + 4]
i += 4
header['time_stamp'] = False
header['message_len'] = hex2int( p_encSms[i:i+2] )
header['bUserHeaderPresent' ] = user_header_present
header['position']=i
return header
def __str__ (self):
return 'Decoded SmsMessage: %s-%s %s - %s\r\n' % \
(self.getPhoneNumber () , \
self.getTimestamp (), \
self.getMessage (), \
self.p_enc)
def __repr__(self):
return self.__str__()
def decodeSms( self, p_encSms ):
decoded = ''
smsc_len = hex2int( p_encSms[0:2])
## check if stripped sms in nokia's outbox archive
if smsc_len > 0:
headers = self.decodeHeader( p_encSms )
else:
headers = { 'position':16, 'message_len':len( p_encSms )-2, 'user_data_coding':7, 'time_stamp':'', 'sender_number':'' }
self.headers = headers
if headers['message_len'] > 0:
i=headers['position']
message_enc = p_encSms[i:i+(headers['message_len']*2)-1] #? check
if headers['user_data_coding'] == 7:
message_dec, chars_needed = decodeText7Bit( message_enc , headers['message_len'])
elif headers['user_data_coding'] == 8:
message_dec = decodeText8Bit( message_enc )
else:
message_dec = decodeText16Bit( message_enc )
if message_dec[-1] == chr(0):
message_dec = message_dec[:-1]
if (headers['bUserHeaderPresent']):
message_dec = message_dec[message_dec.rfind(chr(0)) + 1:]
self.decodedMsg = translateSMSAlphabetToAscii( message_dec) #cut off trailing 0
if headers['user_data_coding'] == 7: #line not exit in original codes
i += chars_needed
else:
self.decodedMsg = ''
return True
return True
if __name__ == "__main__":
import sys
if len(sys.argv) == 1:
print 'usage: smsdecoder PDU'
else:
pdu = sys.argv[1]
#print 'decoding', pdu
objDecoder = SmsDecoder(pdu)
print objDecoder
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -