]> git.neil.brown.name Git - plato.git/commitdiff
gsm: add sms.py library.
authorNeilBrown <neil@brown.name>
Tue, 24 Mar 2015 03:58:52 +0000 (14:58 +1100)
committerNeilBrown <neil@brown.name>
Tue, 24 Mar 2015 03:59:17 +0000 (14:59 +1100)
This is used by gsmd2 to get sms messages.

Signed-off-by: NeilBrown <neil@brown.name>
gsm/sms.py [new file with mode: 0644]

diff --git a/gsm/sms.py b/gsm/sms.py
new file mode 100644 (file)
index 0000000..f8df696
--- /dev/null
@@ -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)