--- /dev/null
+# 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)