2 # -*- coding: utf-8 -*-
3 ## This program is free software; you can redistribute it and/or modify
4 ## it under the terms of the GNU General Public License as published
5 ## by the Free Software Foundation; version 2 and higer.
7 ## Martin Grimme (martin.grimme # gmail.com) 2010
8 ## Guseynov Alexey (kibergus # gmail.com) 2010
23 LANG_UNSPECIFIED = 0xf
26 GSM_DEFAULT_ALPHABET = [
167 Decodes the given string using the given cell broadcast data coding scheme.
169 @param s: string to decode
170 @param n: GSM cell broadcast data coding scheme
171 @return: UTF-8 string
174 # separate into nibbles
175 hbits = (n & 0xf0) >> 4
180 return _decode_language(s, lbits)
182 elif (0x1 <= hbits <= 0x3):
186 elif (0x4 <= hbits <= 0x7):
187 # general data coding indication
188 return _decode_general_data_coding(s, hbits, lbits)
190 elif (0x8 <= hbits <= 0xe):
191 # reserved coding group
195 # data coding / message handling
199 def _decode_language(s, lang):
201 return _decode_default_alphabet(s)
204 def _decode_default_alphabet(s):
206 # ought to be all in the 7 bit GSM character map
207 # modem is in 8 bit mode, so it makes 7 bit unpacking itself
208 chars = [ GSM_DEFAULT_ALPHABET[ord(c)] for c in s ]
209 u_str = "".join(chars)
210 return u_str.encode("utf-8")
215 return s.decode("hex")
220 return s.decode("hex").decode("utf-16-be").encode("utf-8")
223 def _decode_general_data_coding(s, h, l):
225 is_compressed = (h & 0x2)
227 alphabet = (l & 0xc) >> 2
229 if (alphabet == 0x0):
231 return _decode_default_alphabet(s)
233 elif (alphabet == 0x1):
235 # actually, encoding is user-defined, but let's assume hex'd ASCII
237 return _decode_hex(s)
239 elif (alphabet == 0x2):
241 return _decode_usc2(s)
242 elif (alphabet == 0x3):
246 def decode_number(number):
250 dnumber += str(int((i & 0xf)))
251 if (i & 0xf0) >> 4 < 10:
252 dnumber += str(int((i & 0xf0) >> 4))
255 def decode_timestamp(timestamp):
257 res['year'] = str(timestamp[0] & 0xf) + str((timestamp[0] & 0xf0) >> 4)
258 res['month'] = str(timestamp[1] & 0xf) + str((timestamp[1] & 0xf0) >> 4)
259 res['day'] = str(timestamp[2] & 0xf) + str((timestamp[2] & 0xf0) >> 4)
260 res['hour'] = str(timestamp[3] & 0xf) + str((timestamp[3] & 0xf0) >> 4)
261 res['minute'] = str(timestamp[4] & 0xf) + str((timestamp[4] & 0xf0) >> 4)
262 res['second'] = str(timestamp[5] & 0xf) + str((timestamp[5] & 0xf0) >> 4)
263 res['timezone'] = str(timestamp[6] & 0xf) + str((timestamp[6] & 0xf0) >> 4)
266 def decode_pdu (pdumsg):
268 pdu['type'] = int(pdumsg[0])
269 if pdu['type'] & 0x3 == 0x0:
270 pdu['address_len'] = int(pdumsg[1])
271 pdu['type_of_address'] = int(pdumsg[2])
272 base = 3+(pdu['address_len']+1)/2
273 pdu['sender'] = decode_number(pdumsg[3:base])
274 pdu['pid'] = int(pdumsg[base])
275 pdu['dcs'] = int(pdumsg[base+1])
276 pdu['timestamp'] = decode_timestamp (pdumsg[base+2:base+9]);
277 pdu['udl'] = int(pdumsg[base+9])
278 pdu['user_data'] = pdumsg[base+10:len(pdumsg)]
280 alphabet = (pdu['dcs'] & 0xc) >> 2
282 # This is 7-bit data. Taking of only pdu['udl'] bytes is important because we can't distinguish 0 at the end from @ if only one bit is used in last bite
283 pdu['user_data'] = _decode_default_alphabet(deoctify(pdu['user_data']))[0:pdu['udl']]
284 elif alphabet == 0x1:
285 # actually, encoding is user-defined, but let's assume ASCII
286 pdu['user_data'] = ''.join([chr(i) for i in pdu['user_data']])
287 elif (alphabet == 0x2):
289 pdu['user_data'] = (''.join([chr(i) for i in pdu['user_data'][6:len(pdu['user_data'])]])).decode("utf-16-be").encode("utf-8")
290 elif (alphabet == 0x3):
292 pdu['user_data'] = ''.join([chr(i) for i in pdu['user_data']])
294 if pdu['type'] & 0x4 == 0:
299 # TODO support other types of messages
300 # This is not incoming message
301 # pdu['type'] & 0x3 == 2 means delivery report