⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 smsdecoder.py

📁 for decoding sms massages
💻 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 + -