diff --git a/messaging/__init__.py b/messaging/__init__.py index 4287930..f8b05c8 100644 --- a/messaging/__init__.py +++ b/messaging/__init__.py @@ -1,7 +1,4 @@ -from messaging.pdu import (PDU, SEVENBIT_SIZE, UCS2_SIZE, SEVENBIT_MP_SIZE, - UCS2_MP_SIZE) -from messaging.gsm0338 import is_valid_gsm_text +from messaging.pdu import PDU VERSION = (0, 3, 0) -__all__ = ["PDU", "SEVENBIT_SIZE", "SEVENBIT_MP_SIZE", "UCS2_SIZE", - "UCS2_MP_SIZE", "is_valid_gsm_text"] +__all__ = ["PDU"] diff --git a/messaging/pdu.py b/messaging/pdu.py index 75feb5c..c83df27 100644 --- a/messaging/pdu.py +++ b/messaging/pdu.py @@ -24,7 +24,9 @@ from cStringIO import StringIO from binascii import hexlify, unhexlify from datetime import datetime, timedelta -from messaging import gsm0338 +from messaging.gsm0338 import is_valid_gsm_text +from messaging.utils import (bytes_to_str, str_to_bytes, swap, encode_byte, + encode_seq, debug) SEVENBIT_FORMAT = 0x00 EIGHTBIT_FORMAT = 0x04 @@ -53,25 +55,6 @@ ABBREVIATED = 6 RESERVED = 7 -def debug(s): - # set this to True if you want to poke at PDU encoding/decoding - if False: - print s - - -def swap(s): - """Swaps ``address`` according to GSM 23.040""" - address = list(hexlify(s).replace('f', '')) - for n in range(1, len(address), 2): - address[n-1], address[n] = address[n], address[n-1] - - return ''.join(address).strip() - - -def encode_byte(i): - return hexlify(chr(i)) - - class PDU(object): def __init__(self): @@ -184,7 +167,7 @@ class PDU(object): Format of received SMS """ pdu = pdu.upper() - d = StringIO(unhexlify(pdu)) + d = StringIO(bytes_to_str(unhexlify(pdu))) # Service centre address smscl = ord(d.read(1)) smscertype = ord(d.read(1)) @@ -223,9 +206,12 @@ class PDU(object): sndtype = (ord(d.read(1)) >> 4) & 0x07 # bits 654 if sndtype == ALPHANUMERIC: # coded according to 3GPP TS 23.038 [9] GSM 7-bit default alphabet - sender = hexlify(d.read(int(sndlen/2.0))) + sender = hexlify(str_to_bytes(d.read(int(sndlen/2.0)))) sender = self._unpack_msg(sender) - sender = sender.decode("gsm0338") + try: + sender = sender.decode("gsm0338") + except AttributeError: + pass else: # Extract phone number of sender sender = swap(d.read(int(sndlen/2.0))) @@ -247,7 +233,7 @@ class PDU(object): datestr = '' if sms_type == SMS_DELIVER: # Get date stamp (sender's local time) - date = list(hexlify(d.read(6))) + date = list(hexlify(str_to_bytes(d.read(6)))) for n in range(1, len(date), 2): date[n-1], date[n] = date[n], date[n-1] @@ -386,7 +372,7 @@ class PDU(object): pl = len(ps) ps = chr(pl) + ps - return hexlify(ps) + return encode_seq(ps) def _get_tpmessref_pdu(self, msgref): if msgref is None: @@ -412,7 +398,7 @@ class PDU(object): ps += chr(int(num, 16)) ps = chr(pl) + ps - return hexlify(ps) + return encode_seq(ps) def _clean_number(self, number): return number.strip().replace(' ', '') @@ -435,7 +421,7 @@ class PDU(object): def _get_msg_pdu(self, text, validity_period, store, rand_id): # Data coding scheme - if gsm0338.is_valid_gsm_text(text): + if is_valid_gsm_text(text): dcs = SEVENBIT_FORMAT else: dcs = UNICODE_FORMAT @@ -492,16 +478,16 @@ class PDU(object): mlen = len(text) * 2 message = chr(mlen) + nmesg - return hexlify(message) + return encode_seq(message) def _pack_8bits_to_7bits(self, message, udh=None): pdu = "" - txt = message.encode("gsm0338") + txt = bytes_to_str(message.encode("gsm0338")) if udh is None: tl = len(txt) txt += '\x00' - msgl = len(txt) * 7 / 8 + msgl = int(len(txt) * 7 / 8) op = [-1] * msgl c = shift = 0 @@ -521,7 +507,7 @@ class PDU(object): tl = len(txt) txt += '\x00' - msgl = len(txt) * 7 / 8 + msgl = int(len(txt) * 7 / 8) op = [-1] * msgl c = shift = 0 @@ -540,7 +526,7 @@ class PDU(object): pdu = chr(tl) + ''.join(map(chr, op)) - return hexlify(pdu) + return encode_seq(pdu) def _split_sms_message(self, text, encoding=SEVENBIT_FORMAT, limit=SEVENBIT_SIZE, rand_id=None): diff --git a/messaging/utils.py b/messaging/utils.py new file mode 100644 index 0000000..fdb0b4d --- /dev/null +++ b/messaging/utils.py @@ -0,0 +1,40 @@ +from binascii import hexlify +import sys + + +def bytes_to_str(b): + if sys.version_info >= (3,): + return b.decode('latin1') + + return b + + +def str_to_bytes(s): + if sys.version_info >= (3,): + return s.encode('latin1') + + return s + + +def debug(s): + # set this to True if you want to poke at PDU encoding/decoding + if 1: + #sys.stdout.write('%s\n' % s) + print(s) + + +def swap(s): + """Swaps ``address`` according to GSM 23.040""" + address = list(bytes_to_str(hexlify(str_to_bytes(s))).replace('f', '')) + for n in range(1, len(address), 2): + address[n-1], address[n] = address[n], address[n-1] + + return ''.join(address).strip() + + +def encode_seq(seq): + return ''.join(["%02x" % ord(n) for n in seq]) + + +def encode_byte(i): + return ''.join(["%02x" % ord(n) for n in chr(i)]) diff --git a/setup.py b/setup.py index 4c72ced..1a177b0 100644 --- a/setup.py +++ b/setup.py @@ -1,23 +1,27 @@ from distribute_setup import use_setuptools use_setuptools() from setuptools import setup, find_packages +import sys -import messaging +extra = {} +if sys.version_info >= (3,): + extra['use_2to3'] = True setup(name="python-messaging", - version='.'.join(map(str, messaging.VERSION)), + version='0.3.0', description='SMS encoder/decoder', license='GPL', packages=find_packages(), install_requires=['nose >= 0.8.3',], zip_safe=True, test_suite='messaging.test', - classifiers = [ + classifiers=[ 'Development Status :: 4 - Beta', 'License :: OSI Approved :: GNU General Public License (GPL)', 'Natural Language :: English', 'Operating System :: POSIX :: Linux', 'Programming Language :: Python', 'Topic :: Communications :: Telephony', - ] + ], + **extra )