From c4fdb0680ae67a8da9e34e197fe9c66cd4c073fe Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 24 Mar 2015 14:58:52 +1100 Subject: [PATCH] gsm: add sms.py library. This is used by gsmd2 to get sms messages. Signed-off-by: NeilBrown --- gsm/sms.py | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 gsm/sms.py diff --git a/gsm/sms.py b/gsm/sms.py new file mode 100644 index 0000000..f8df696 --- /dev/null +++ b/gsm/sms.py @@ -0,0 +1,129 @@ +# GSM uses a 7-bit code that is not the same as ASCII... +# -*- coding: utf8 -*- +gsm = (u"@£$¥èéùìòÇ\nØø\rÅåΔ_ΦΓΛΩΠΨΣΘΞ\x1bÆæßÉ !\"#¤%&'()*+,-./0123456789:;<=>?" + u"¡ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑÜ`¿abcdefghijklmnopqrstuvwxyzäöñüà") +ext = (u"````````````````````^```````````````````{}`````\\````````````[~]`" + u"|````````````````````````````````````€``````````````````````````") + +# Take a unicode string and produce a byte string for GSM +def gsm_encode(plaintext): + res = "" + for c in plaintext: + idx = gsm.find(c); + if idx != -1: + res += chr(idx) + continue + idx = ext.find(c) + if idx != -1: + res += chr(27) + res += chr(idx) + return res +# take a GSM byte string (7-in-8 conversion already done) and produce unicode +def gsm_decode(code): + uni = u'' + esc = False + for c in code: + n = ord(c) + if esc: + uni += ext[n] + esc = False + elif n == 27: + esc = True + else: + uni += gsm[n] + return uni + + +def sms_decode(msg,pos = 1): + #msg is a 7-in-8 encoding of a longer message. + carry = 0 + str = '' + while msg: + c = msg[0:2] + msg = msg[2:] + b = int(c, 16) + if pos == 0: + if carry: + str += chr(carry + (b&1)*64) + carry = 0 + b /= 2 + else: + b = (b << (pos-1)) | carry + carry = (b & 0xff80) >> 7 + b &= 0x7f + if (b & 0x7f) != 0: + str += chr(b&0x7f) + pos = (pos+1) % 7 + return gsm_decode(str) + +def unicode_decode(msg): + # 2bytes unicode numbers - 4 syms each + m = u'' + for i in range(len(msg)/4): + c = int(msg[i*4:i*4+4],16) + m += unichr(c) + return m + +def cvt_telnum(type, msg, len): + if type == '81' or type == '91': + n = '' + for i in range(len): + n += msg[i + 1 - (i%2)*2] + if type == '91': + return '+' + n + else: + return n + if type == 'D0': + return sms_decode(msg) + return "?" + type + msg + +def cvt_date(msg): + #YYMMDDHHMMSSZZ -> 20YY/MM/DD HH:MM:SS+ZZ swapping letters + sep='0//,::+' + dt = '2' + for i in range(len(msg)/2): + dt += sep[i] + msg[i*2+1] + msg[i*2] + return dt + +def extract(msg): + hlen = int(msg[:2], 16) + hdr = msg[2:(2+hlen*2)] + # hdr is the sending number - don't care + msg = msg[2+hlen*2:] + # typ == 04 - SMS-DELIVER + typ = int(msg[0:2], 16) + nlen = int(msg[2:4], 16) + ntype = msg[4:6] + numlen = (nlen + nlen%2) + sender = cvt_telnum(ntype, msg[6:6+numlen], nlen) + msg = msg[6+numlen:] + proto = msg[0:2] + coding = msg[2:4] + date = cvt_date(msg[4:18]) + body_len = int(msg[18:20], 16) + body = msg[20:] + ref = None; part = None + + if body[0:6] == '050003': + # concatenated message with 8bit ref number + ref = body[6:8] + part = (int(body[10:12],16), int(body[8:10], 16)) + if coding == '08': + txt = unicode_decode(body[12:]) + else: + txt = sms_decode(body[12:], 0) + elif body[0:6] == '060504': + # VCARD?? + txt = sms_decode(body[14:]) + elif coding == '00': + txt = sms_decode(body) + elif coding == '01': + txt = sms_decode(body) + elif coding == '08': + txt = unicode_decode(body) + elif coding == 'F1': + txt = sms_decode(body) + else: + txt = 'Unrecognised: ' + body + + return (sender, date, ref, part, txt) -- 2.39.5