From 6484d7ff7ab001d9bba90b19237df525b8e6db32 Mon Sep 17 00:00:00 2001 From: Martin Harari Thuresson Date: Wed, 20 Dec 2017 16:13:31 +0100 Subject: [PATCH 01/30] Allow unkown TLV records --- smpplib/client.py | 6 +++++- smpplib/command.py | 12 +++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/smpplib/client.py b/smpplib/client.py index 6c68601..52668fe 100644 --- a/smpplib/client.py +++ b/smpplib/client.py @@ -322,9 +322,13 @@ def poll(self, ignore_error_codes=None): break self.read_once(ignore_error_codes) + def listen_stop(self): + self.run = False + def listen(self, ignore_error_codes=None): """Listen for PDUs and act""" - while True: + self.run = True + while self.run: self.read_once(ignore_error_codes) def send_message(self, **kwargs): diff --git a/smpplib/command.py b/smpplib/command.py index 6ae1211..5a94b3b 100644 --- a/smpplib/command.py +++ b/smpplib/command.py @@ -71,9 +71,7 @@ def get_optional_name(code): if value == code: return key - raise exceptions.UnknownCommandError( - 'Unknown SMPP command code "0x%x"' % code) - + return str(hex(code)) def get_optional_code(name): """Return optional_params code by given command name. If name is unknown, @@ -347,8 +345,12 @@ def parse_optional_params(self, data): type_code, pos = unpack_short(data, pos) field = get_optional_name(type_code) length, pos = unpack_short(data, pos) - - param = self.params[field] + if field in self.params: + param = self.params[field] + else: + param = Param(type=str, size=length) + self.params[field] = param + logger.warning('Unkown TLV: %s', field) if param.type is int: data, pos = self._parse_int(field, data, pos) elif param.type in (str, ostr): From e1a4f10628a76f0677f398c085dbad6a66cfee2c Mon Sep 17 00:00:00 2001 From: Martin Harari Thuresson Date: Thu, 21 Dec 2017 11:59:29 +0100 Subject: [PATCH 02/30] Allow listen to stop when unbind resp is received. --- smpplib/client.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/smpplib/client.py b/smpplib/client.py index 52668fe..4d4285b 100644 --- a/smpplib/client.py +++ b/smpplib/client.py @@ -301,6 +301,8 @@ def read_once(self, ignore_error_codes=None): self._enquire_link_received() elif p.command == 'enquire_link_resp': pass + elif p.command == 'unbind_resp': + self.run = False elif p.command == 'alert_notification': self._alert_notification(p) else: From 35981777e89c5891137cd9cf249d8832da04ca6a Mon Sep 17 00:00:00 2001 From: Martin Harari Thuresson Date: Wed, 3 Jan 2018 22:20:13 +0100 Subject: [PATCH 03/30] Added support for decoding gsm 7 chars. --- smpplib/gsm.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/smpplib/gsm.py b/smpplib/gsm.py index 4d51b1d..8f58f8c 100644 --- a/smpplib/gsm.py +++ b/smpplib/gsm.py @@ -36,6 +36,18 @@ def gsm_encode(plaintext, hex=False): raise EncodeError() return binascii.b2a_hex(res) if hex else res +def gsm_decode(instring, hex=False): + if hex: + instring = binascii.a2b_hex(instring) + chars = iter(instring) + result = [] + for c in chars: + if c == chr(27): + c = next(chars) + result.append(ext[ord(c)]) + else: + result.append(gsm[ord(c)]) + return ''.join(result) def make_parts(text): """Returns tuple(parts, encoding, esm_class)""" From 249e6e4fcdbe0cb30fef3fbccd36ed36bb66b78c Mon Sep 17 00:00:00 2001 From: Martin Harari Thuresson Date: Fri, 5 Jan 2018 19:50:24 +0100 Subject: [PATCH 04/30] Allow async handling of incomming submit_sm and allow unbind from listen --- smpplib/client.py | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/smpplib/client.py b/smpplib/client.py index 4d4285b..6fe9a8d 100644 --- a/smpplib/client.py +++ b/smpplib/client.py @@ -152,14 +152,8 @@ def bind_transceiver(self, **kwargs): def unbind(self): """Unbind from the SMSC""" - p = smpp.make_pdu('unbind', client=self) - self.send_pdu(p) - try: - return self.read_pdu() - except socket.timeout: - raise exceptions.ConnectionError() def send_pdu(self, p): """Send PDU to the SMSC""" @@ -233,14 +227,17 @@ def accept(self, obj): raise NotImplementedError('not implemented') def _message_received(self, p): - """Handler for received message event""" + """Handler for received message event, Return False from + message_received_handler to make your own deliver_sm_resp, + for example to handle asyc functions.""" status = self.message_received_handler(pdu=p) if status is None: status = consts.SMPP_ESME_ROK - dsmr = smpp.make_pdu('deliver_sm_resp', client=self, status=status) - #, message_id=args['pdu'].sm_default_msg_id) - dsmr.sequence = p.sequence - self.send_pdu(dsmr) + elif status != False: + dsmr = smpp.make_pdu('deliver_sm_resp', client=self, status=status) + #, message_id=args['pdu'].sm_default_msg_id) + dsmr.sequence = p.sequence + self.send_pdu(dsmr) def _enquire_link_received(self): """Response to enquire_link""" @@ -264,7 +261,6 @@ def set_message_sent_handler(self, func): @staticmethod def message_received_handler(pdu, **kwargs): """Custom handler to process received message. May be overridden""" - logger.warning('Message received handler (Override me)') @staticmethod @@ -302,7 +298,10 @@ def read_once(self, ignore_error_codes=None): elif p.command == 'enquire_link_resp': pass elif p.command == 'unbind_resp': - self.run = False + if p.status == const.SMPP_ESME_ROK: + self.run = False + else: + logger.warning('SMPP unbind failed with error "%s"', p.status) elif p.command == 'alert_notification': self._alert_notification(p) else: From b0b647f8b8211a48715bc505bf5ff7c51ef44501 Mon Sep 17 00:00:00 2001 From: Martin Harari Thuresson Date: Fri, 5 Jan 2018 19:51:44 +0100 Subject: [PATCH 05/30] Allow async handling of incomming submit_sm and allow unbind from listen --- smpplib/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smpplib/client.py b/smpplib/client.py index 6fe9a8d..4fd0d8d 100644 --- a/smpplib/client.py +++ b/smpplib/client.py @@ -298,7 +298,7 @@ def read_once(self, ignore_error_codes=None): elif p.command == 'enquire_link_resp': pass elif p.command == 'unbind_resp': - if p.status == const.SMPP_ESME_ROK: + if p.status == consts.SMPP_ESME_ROK: self.run = False else: logger.warning('SMPP unbind failed with error "%s"', p.status) From 5ae5b7afe4c2d990dbdbc4898d6759d3f4fca561 Mon Sep 17 00:00:00 2001 From: Martin Harari Thuresson Date: Mon, 15 Jan 2018 11:38:12 +0100 Subject: [PATCH 06/30] Use sequence numbers for the Unbind and Req.Link --- smpplib/command.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/smpplib/command.py b/smpplib/command.py index 5a94b3b..42b68ae 100644 --- a/smpplib/command.py +++ b/smpplib/command.py @@ -841,7 +841,7 @@ class Unbind(Command): def __init__(self, command, **kwargs): """Initialize""" - super(Unbind, self).__init__(command, need_sequence=False, **kwargs) + super(Unbind, self).__init__(command, **kwargs) class UnbindResp(Command): @@ -863,8 +863,7 @@ class EnquireLink(Command): def __init__(self, command, **kwargs): """Initialize""" - super(EnquireLink, self).__init__(command, need_sequence=False, - **kwargs) + super(EnquireLink, self).__init__(command, **kwargs) class EnquireLinkResp(Command): From eaa17487f2488cbc37b3773f40a6488d053f218a Mon Sep 17 00:00:00 2001 From: Martin Harari Thuresson Date: Tue, 23 Jan 2018 11:49:07 +0100 Subject: [PATCH 07/30] Make it easier to access unknown TLV --- smpplib/command.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smpplib/command.py b/smpplib/command.py index 42b68ae..f1c590b 100644 --- a/smpplib/command.py +++ b/smpplib/command.py @@ -71,7 +71,7 @@ def get_optional_name(code): if value == code: return key - return str(hex(code)) + return "TLV_%x" % code def get_optional_code(name): """Return optional_params code by given command name. If name is unknown, From 836d64be0eb6af784de3574f9f598a8561b04b23 Mon Sep 17 00:00:00 2001 From: Martin Harari Thuresson Date: Mon, 26 Feb 2018 08:57:56 +0100 Subject: [PATCH 08/30] Added support for unbind from SMSC --- smpplib/client.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/smpplib/client.py b/smpplib/client.py index 4fd0d8d..30aa0ff 100644 --- a/smpplib/client.py +++ b/smpplib/client.py @@ -286,8 +286,16 @@ def read_once(self, ignore_error_codes=None): '({}) {}: {}'.format(p.status, p.command, consts.DESCRIPTIONS.get(p.status, 'Unknown status')), int(p.status)) - if p.command == 'unbind': # unbind_res + if p.command == 'unbind': logger.info('Unbind command received') + resp_pdu = smpp.make_pdu( + 'unbind_resp', + client=self, + command_status=consts.SMPP_ESME_ROK, + sequence_number=resp_pdu.sequence_number) + self.send_pdu(resp_pdu) + logger.info('Unbind resp sent') + self.state = const.SMPP_CLIENT_STATE_OPEN return elif p.command == 'submit_sm_resp': self.message_sent_handler(pdu=p) From fd9146837c95e9f05520854c54798612f3569c8a Mon Sep 17 00:00:00 2001 From: Martin Harari Thuresson Date: Tue, 27 Feb 2018 10:43:16 +0100 Subject: [PATCH 09/30] Added support for UDH data --- smpplib/pdu.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/smpplib/pdu.py b/smpplib/pdu.py index c74324e..8364a8c 100644 --- a/smpplib/pdu.py +++ b/smpplib/pdu.py @@ -106,6 +106,19 @@ def get_status_desc(self, status=None): return desc + def parse_udh(self): + """Parsing the UDH""" + (udh_lenght) = struct.unpack('>B', self.short_message[0:1]) + (udh_data_type, udh_data_lenght ) = struct.unpack('>BB', self.short_message[1:3]) + + if udh_data_type == SMPP_UDHIEIE_CONCATENATED and udh_data_lenght == 3: + ( + self.sar_msg_ref_num, + self.sar_total_segments + ) = struct.unpack('>BB', self.short_message[3:udh_lenght]) + + self.short_message = self.short_message[udh_lenght+1:] + def parse(self, data): """Parse raw PDU""" @@ -132,6 +145,9 @@ def parse(self, data): if len(data) > 16: self.parse_params(data[16:]) + if pdu.esm_class & SMPP_GSMFEAT_UDHI: + self.parse_udh() + def generate(self): """Generate raw PDU""" From 2997acc2ac369395348d6738f104f4be47da3c00 Mon Sep 17 00:00:00 2001 From: Martin Harari Thuresson Date: Tue, 27 Feb 2018 10:46:50 +0100 Subject: [PATCH 10/30] Added seq parameter --- smpplib/pdu.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/smpplib/pdu.py b/smpplib/pdu.py index 8364a8c..856338f 100644 --- a/smpplib/pdu.py +++ b/smpplib/pdu.py @@ -114,8 +114,9 @@ def parse_udh(self): if udh_data_type == SMPP_UDHIEIE_CONCATENATED and udh_data_lenght == 3: ( self.sar_msg_ref_num, - self.sar_total_segments - ) = struct.unpack('>BB', self.short_message[3:udh_lenght]) + self.sar_total_segments, + self.sar_segment_seqnum + ) = struct.unpack('>BBB', self.short_message[3:udh_lenght]) self.short_message = self.short_message[udh_lenght+1:] From 257754a491b666aee156a1ff308069808082cf4d Mon Sep 17 00:00:00 2001 From: Martin Harari Thuresson Date: Tue, 27 Feb 2018 11:04:46 +0100 Subject: [PATCH 11/30] Fix from pdu to self --- smpplib/pdu.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smpplib/pdu.py b/smpplib/pdu.py index 856338f..889cd35 100644 --- a/smpplib/pdu.py +++ b/smpplib/pdu.py @@ -146,7 +146,7 @@ def parse(self, data): if len(data) > 16: self.parse_params(data[16:]) - if pdu.esm_class & SMPP_GSMFEAT_UDHI: + if 'esm_class' in self and self.esm_class & SMPP_GSMFEAT_UDHI: self.parse_udh() def generate(self): From 0e2d313c96799c0fa3ce0793c96f506cabab672f Mon Sep 17 00:00:00 2001 From: Martin Harari Thuresson Date: Tue, 27 Feb 2018 10:15:02 +0000 Subject: [PATCH 12/30] Update to handle UDH --- smpplib/pdu.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/smpplib/pdu.py b/smpplib/pdu.py index 889cd35..cd14d4a 100644 --- a/smpplib/pdu.py +++ b/smpplib/pdu.py @@ -111,7 +111,7 @@ def parse_udh(self): (udh_lenght) = struct.unpack('>B', self.short_message[0:1]) (udh_data_type, udh_data_lenght ) = struct.unpack('>BB', self.short_message[1:3]) - if udh_data_type == SMPP_UDHIEIE_CONCATENATED and udh_data_lenght == 3: + if udh_data_type == consts.SMPP_UDHIEIE_CONCATENATED and udh_data_lenght == 3: ( self.sar_msg_ref_num, self.sar_total_segments, @@ -146,7 +146,7 @@ def parse(self, data): if len(data) > 16: self.parse_params(data[16:]) - if 'esm_class' in self and self.esm_class & SMPP_GSMFEAT_UDHI: + if getattr(self, 'esm_class', 0) & consts.SMPP_GSMFEAT_UDHI: self.parse_udh() def generate(self): From f2c57bb8193a63c7efab5d182422e8c2231c676e Mon Sep 17 00:00:00 2001 From: Martin Harari Thuresson Date: Tue, 27 Feb 2018 12:43:38 +0100 Subject: [PATCH 13/30] Auto convert UDH length from tuple --- smpplib/pdu.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/smpplib/pdu.py b/smpplib/pdu.py index cd14d4a..ede8c14 100644 --- a/smpplib/pdu.py +++ b/smpplib/pdu.py @@ -108,16 +108,14 @@ def get_status_desc(self, status=None): def parse_udh(self): """Parsing the UDH""" - (udh_lenght) = struct.unpack('>B', self.short_message[0:1]) + (udh_lenght, ) = struct.unpack('>B', self.short_message[0:1]) (udh_data_type, udh_data_lenght ) = struct.unpack('>BB', self.short_message[1:3]) - if udh_data_type == consts.SMPP_UDHIEIE_CONCATENATED and udh_data_lenght == 3: ( self.sar_msg_ref_num, self.sar_total_segments, self.sar_segment_seqnum - ) = struct.unpack('>BBB', self.short_message[3:udh_lenght]) - + ) = struct.unpack('>BBB', self.short_message[3:3+udh_data_lenght]) self.short_message = self.short_message[udh_lenght+1:] def parse(self, data): @@ -146,7 +144,7 @@ def parse(self, data): if len(data) > 16: self.parse_params(data[16:]) - if getattr(self, 'esm_class', 0) & consts.SMPP_GSMFEAT_UDHI: + if int(getattr(self, 'esm_class', '0')) & consts.SMPP_GSMFEAT_UDHI: self.parse_udh() def generate(self): From f1e4a2a74ad8262ef5b088b1850947be8a9b7551 Mon Sep 17 00:00:00 2001 From: Martin Harari Thuresson Date: Thu, 1 Mar 2018 12:43:21 +0100 Subject: [PATCH 14/30] Bugfix for undbind --- smpplib/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smpplib/client.py b/smpplib/client.py index 30aa0ff..3f2f964 100644 --- a/smpplib/client.py +++ b/smpplib/client.py @@ -292,7 +292,7 @@ def read_once(self, ignore_error_codes=None): 'unbind_resp', client=self, command_status=consts.SMPP_ESME_ROK, - sequence_number=resp_pdu.sequence_number) + sequence_number=p.sequence_number) self.send_pdu(resp_pdu) logger.info('Unbind resp sent') self.state = const.SMPP_CLIENT_STATE_OPEN From cc9cab59e05d812d870c96b5f4562b193704b4e1 Mon Sep 17 00:00:00 2001 From: Martin Harari Thuresson Date: Fri, 2 Mar 2018 10:45:30 +0100 Subject: [PATCH 15/30] added missing param --- smpplib/command.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smpplib/command.py b/smpplib/command.py index f1c590b..0a35455 100644 --- a/smpplib/command.py +++ b/smpplib/command.py @@ -446,7 +446,7 @@ class BindTransmitterResp(Command): """Response for bind as a transmitter command""" params = { - 'system_id': Param(type=str), + 'system_id': Param(type=str, max=16), 'sc_interface_version': Param(type=int, size=1), } From 38fc0d4375368b6d01fea61a58ba07e820170d33 Mon Sep 17 00:00:00 2001 From: Martin Harari Thuresson Date: Fri, 2 Mar 2018 11:59:02 +0100 Subject: [PATCH 16/30] Keep timeout on restart --- smpplib/client.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/smpplib/client.py b/smpplib/client.py index 3f2f964..37f1e91 100644 --- a/smpplib/client.py +++ b/smpplib/client.py @@ -63,14 +63,15 @@ class Client(object): vendor = None _socket = None sequence_generator = None + timeout = 5 def __init__(self, host, port, timeout=5, sequence_generator=None): """Initialize""" - + self.timeout = timeout self.host = host self.port = int(port) self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self._socket.settimeout(timeout) + self._socket.settimeout(self.timeout) self.receiver_mode = False if sequence_generator is None: sequence_generator = SimpleSequenceGenerator() @@ -103,6 +104,7 @@ def connect(self): try: if self._socket is None: self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self._socket.settimeout(self.timeout) self._socket.connect((self.host, self.port)) self.state = consts.SMPP_CLIENT_STATE_OPEN except socket.error: From c1106b7dc5904737624b6d44a3c7aa97260d6762 Mon Sep 17 00:00:00 2001 From: Martin Harari Thuresson Date: Fri, 2 Mar 2018 12:16:28 +0100 Subject: [PATCH 17/30] Update for unbind from server --- smpplib/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smpplib/client.py b/smpplib/client.py index 37f1e91..7784d21 100644 --- a/smpplib/client.py +++ b/smpplib/client.py @@ -294,7 +294,7 @@ def read_once(self, ignore_error_codes=None): 'unbind_resp', client=self, command_status=consts.SMPP_ESME_ROK, - sequence_number=p.sequence_number) + sequence=p.sequence) self.send_pdu(resp_pdu) logger.info('Unbind resp sent') self.state = const.SMPP_CLIENT_STATE_OPEN From 90c36b812bb86c0d05bc3952b7a2c702f24da63f Mon Sep 17 00:00:00 2001 From: Martin Harari Thuresson Date: Fri, 2 Mar 2018 12:22:10 +0100 Subject: [PATCH 18/30] Added missing s --- smpplib/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smpplib/client.py b/smpplib/client.py index 7784d21..54c39b3 100644 --- a/smpplib/client.py +++ b/smpplib/client.py @@ -297,7 +297,7 @@ def read_once(self, ignore_error_codes=None): sequence=p.sequence) self.send_pdu(resp_pdu) logger.info('Unbind resp sent') - self.state = const.SMPP_CLIENT_STATE_OPEN + self.state = consts.SMPP_CLIENT_STATE_OPEN return elif p.command == 'submit_sm_resp': self.message_sent_handler(pdu=p) From 168667ec27f68ffddb30e0503c94d8a2abd7819c Mon Sep 17 00:00:00 2001 From: Martin Harari Thuresson Date: Tue, 6 Mar 2018 15:08:38 +0100 Subject: [PATCH 19/30] Added support to read submit_sm_resp result --- smpplib/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smpplib/client.py b/smpplib/client.py index 54c39b3..4ebc345 100644 --- a/smpplib/client.py +++ b/smpplib/client.py @@ -283,7 +283,7 @@ def read_once(self, ignore_error_codes=None): self.send_pdu(p) return - if p.is_error(): + if p.is_error() and not p.command =='submit_sm_resp': raise exceptions.PDUError( '({}) {}: {}'.format(p.status, p.command, consts.DESCRIPTIONS.get(p.status, 'Unknown status')), int(p.status)) From 879d444c7a121d9a13e32de1594f5becf2a9df57 Mon Sep 17 00:00:00 2001 From: Martin Harari Thuresson Date: Sat, 7 Apr 2018 22:49:39 +0200 Subject: [PATCH 20/30] Send correct seq number for link resp --- smpplib/client.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/smpplib/client.py b/smpplib/client.py index 4ebc345..f5ac4cd 100644 --- a/smpplib/client.py +++ b/smpplib/client.py @@ -241,10 +241,11 @@ def _message_received(self, p): dsmr.sequence = p.sequence self.send_pdu(dsmr) - def _enquire_link_received(self): + def _enquire_link_received(self, p): """Response to enquire_link""" ler = smpp.make_pdu('enquire_link_resp', client=self) #, message_id=args['pdu'].sm_default_msg_id) + ler.sequence = p.sequence self.send_pdu(ler) logger.debug("Link Enquiry...") @@ -304,7 +305,7 @@ def read_once(self, ignore_error_codes=None): elif p.command == 'deliver_sm': self._message_received(p) elif p.command == 'enquire_link': - self._enquire_link_received() + self._enquire_link_received(p) elif p.command == 'enquire_link_resp': pass elif p.command == 'unbind_resp': From 4ef5b594598d8423cf71e9c3ffcce369049141af Mon Sep 17 00:00:00 2001 From: Martin Harari Thuresson Date: Sat, 7 Apr 2018 23:21:56 +0200 Subject: [PATCH 21/30] Update for sequence ids on replys --- smpplib/client.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/smpplib/client.py b/smpplib/client.py index f5ac4cd..d7517a7 100644 --- a/smpplib/client.py +++ b/smpplib/client.py @@ -241,6 +241,19 @@ def _message_received(self, p): dsmr.sequence = p.sequence self.send_pdu(dsmr) + def _unbind_received(self, p): + """Response to unbind""" + logger.info('Unbind command received') + resp_pdu = smpp.make_pdu( + 'unbind_resp', + client=self, + command_status=consts.SMPP_ESME_ROK + ) + resp_pdu.sequence=p.sequence + self.send_pdu(resp_pdu) + logger.info('Unbind resp sent') + self.state = consts.SMPP_CLIENT_STATE_OPEN + def _enquire_link_received(self, p): """Response to enquire_link""" ler = smpp.make_pdu('enquire_link_resp', client=self) @@ -290,16 +303,7 @@ def read_once(self, ignore_error_codes=None): consts.DESCRIPTIONS.get(p.status, 'Unknown status')), int(p.status)) if p.command == 'unbind': - logger.info('Unbind command received') - resp_pdu = smpp.make_pdu( - 'unbind_resp', - client=self, - command_status=consts.SMPP_ESME_ROK, - sequence=p.sequence) - self.send_pdu(resp_pdu) - logger.info('Unbind resp sent') - self.state = consts.SMPP_CLIENT_STATE_OPEN - return + self._unbind_received(p) elif p.command == 'submit_sm_resp': self.message_sent_handler(pdu=p) elif p.command == 'deliver_sm': From 15b34212ca0f4b164f55b45d8d5d024f7ff5321f Mon Sep 17 00:00:00 2001 From: Martin Harari Thuresson Date: Tue, 10 Apr 2018 21:15:38 +0200 Subject: [PATCH 22/30] Bug fix for utf-16-be sms --- smpplib/gsm.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/smpplib/gsm.py b/smpplib/gsm.py index 8f58f8c..d51777a 100644 --- a/smpplib/gsm.py +++ b/smpplib/gsm.py @@ -58,10 +58,11 @@ def make_parts(text): partsize = consts.SEVENBIT_MP_SIZE encode = six.b except EncodeError: + text = binascii.hexlify(text.encode('utf-16-be')) encoding = consts.SMPP_ENCODING_ISO10646 - need_split = len(text) > consts.UCS2_SIZE - partsize = consts.UCS2_MP_SIZE - encode = lambda s: s.encode('utf-16-be') + need_split = len(text) > consts.UCS2_SIZE * 4 + partsize = consts.UCS2_MP_SIZE * 4 + encode = lambda s: binascii.unhexlify(s) esm_class = consts.SMPP_MSGTYPE_DEFAULT From 832e50285fbc2b9bd3aba3ed038c91e0210fb617 Mon Sep 17 00:00:00 2001 From: Martin Harari Thuresson Date: Sat, 14 Apr 2018 09:07:06 +0200 Subject: [PATCH 23/30] Handle multi packet PDUs --- smpplib/client.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/smpplib/client.py b/smpplib/client.py index d7517a7..0b178e4 100644 --- a/smpplib/client.py +++ b/smpplib/client.py @@ -207,8 +207,10 @@ def read_pdu(self): logger.warning('Receive broken pdu... %s', repr(raw_len)) raise exceptions.PDUError('Broken PDU') - raw_pdu = self._socket.recv(length - 4) - raw_pdu = raw_len + raw_pdu + logger.debug('Reading PDU of %s bytes', length) + raw_pdu = raw_len + while len(raw_pdu) < length: + raw_pdu += self._socket.recv(length - len(raw_pdu)) logger.debug('<<%s (%d bytes)', binascii.b2a_hex(raw_pdu), len(raw_pdu)) From 5594ba6aae2c8f024a047243f265caf5cd0a1279 Mon Sep 17 00:00:00 2001 From: Martin Harari Thuresson Date: Sun, 15 Apr 2018 17:55:31 +0200 Subject: [PATCH 24/30] Added support for unbind exception --- smpplib/client.py | 4 +++- smpplib/exceptions.py | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/smpplib/client.py b/smpplib/client.py index 0b178e4..0946489 100644 --- a/smpplib/client.py +++ b/smpplib/client.py @@ -245,7 +245,8 @@ def _message_received(self, p): def _unbind_received(self, p): """Response to unbind""" - logger.info('Unbind command received') + logger.info('Unbind command received stopping sending.') + self.state = consts.SMPP_CLIENT_STATE_OPEN resp_pdu = smpp.make_pdu( 'unbind_resp', client=self, @@ -255,6 +256,7 @@ def _unbind_received(self, p): self.send_pdu(resp_pdu) logger.info('Unbind resp sent') self.state = consts.SMPP_CLIENT_STATE_OPEN + raise UnbindFromServer('Server made unbind') def _enquire_link_received(self, p): """Response to enquire_link""" diff --git a/smpplib/exceptions.py b/smpplib/exceptions.py index 8f06f64..4389c75 100644 --- a/smpplib/exceptions.py +++ b/smpplib/exceptions.py @@ -11,9 +11,14 @@ class ConnectionError(Exception): """Connection error""" +class UnbindFromServer(Exception): + """Unbind from SMPP server""" + + class PDUError(RuntimeError): """Error processing PDU""" class MessageTooLong(ValueError): """Text too long to fit 255 SMS""" + From 0f22f5731a9feb13a808ebbac9d0d42ee0520724 Mon Sep 17 00:00:00 2001 From: Martin Harari Thuresson Date: Sun, 15 Apr 2018 18:49:37 +0200 Subject: [PATCH 25/30] Update to raise UnbindFromServer on after unbind_resp --- smpplib/client.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/smpplib/client.py b/smpplib/client.py index 0946489..8295d10 100644 --- a/smpplib/client.py +++ b/smpplib/client.py @@ -246,7 +246,6 @@ def _message_received(self, p): def _unbind_received(self, p): """Response to unbind""" logger.info('Unbind command received stopping sending.') - self.state = consts.SMPP_CLIENT_STATE_OPEN resp_pdu = smpp.make_pdu( 'unbind_resp', client=self, @@ -256,7 +255,7 @@ def _unbind_received(self, p): self.send_pdu(resp_pdu) logger.info('Unbind resp sent') self.state = consts.SMPP_CLIENT_STATE_OPEN - raise UnbindFromServer('Server made unbind') + raise exceptions.UnbindFromServer('Server made unbind') def _enquire_link_received(self, p): """Response to enquire_link""" From cbcc54d0d6a86ff6fe340db81074a25cc274319d Mon Sep 17 00:00:00 2001 From: Martin Harari Thuresson Date: Fri, 20 Apr 2018 07:13:33 +0200 Subject: [PATCH 26/30] Support for split size package --- smpplib/client.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/smpplib/client.py b/smpplib/client.py index 8295d10..62c3065 100644 --- a/smpplib/client.py +++ b/smpplib/client.py @@ -191,8 +191,10 @@ def read_pdu(self): logger.debug('Waiting for PDU...') + raw_len = '' try: - raw_len = self._socket.recv(4) + while len(raw_len) < 4: + raw_len += self._socket.recv(4 - len(raw_len)) except socket.timeout: raise except socket.error as e: From d32ca9b78d678a74b6fd979369aa29f91bd3baed Mon Sep 17 00:00:00 2001 From: Martin Harari Thuresson Date: Mon, 30 Apr 2018 08:23:55 +0100 Subject: [PATCH 27/30] Added support for external ubind --- smpplib/client.py | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/smpplib/client.py b/smpplib/client.py index 62c3065..2673522 100644 --- a/smpplib/client.py +++ b/smpplib/client.py @@ -239,25 +239,28 @@ def _message_received(self, p): status = self.message_received_handler(pdu=p) if status is None: status = consts.SMPP_ESME_ROK - elif status != False: + if status != False: dsmr = smpp.make_pdu('deliver_sm_resp', client=self, status=status) - #, message_id=args['pdu'].sm_default_msg_id) dsmr.sequence = p.sequence self.send_pdu(dsmr) def _unbind_received(self, p): """Response to unbind""" - logger.info('Unbind command received stopping sending.') - resp_pdu = smpp.make_pdu( - 'unbind_resp', - client=self, - command_status=consts.SMPP_ESME_ROK - ) - resp_pdu.sequence=p.sequence - self.send_pdu(resp_pdu) - logger.info('Unbind resp sent') - self.state = consts.SMPP_CLIENT_STATE_OPEN - raise exceptions.UnbindFromServer('Server made unbind') + status = self.unbind_received_handler(pdu=p) + if status is None: + status = consts.SMPP_ESME_ROK + if status != False: + resp_pdu = smpp.make_pdu( + 'unbind_resp', + client=self, + command_status=consts.SMPP_ESME_ROK + ) + logger.info('Unbind command received stopping sending.') + resp_pdu.sequence=p.sequence + self.send_pdu(resp_pdu) + logger.info('Unbind resp sent') + self.state = consts.SMPP_CLIENT_STATE_OPEN + raise exceptions.UnbindFromServer('Server made unbind') def _enquire_link_received(self, p): """Response to enquire_link""" @@ -279,9 +282,14 @@ def set_message_sent_handler(self, func): """Set new function to handle message sent event""" self.message_sent_handler = func + def set_unbind_received_handler(self, func): + """Set new function to handle message receive event""" + self.unbind_received_handler = func + @staticmethod def message_received_handler(pdu, **kwargs): - """Custom handler to process received message. May be overridden""" + """Custom handler to process received message. + May be overridden""" logger.warning('Message received handler (Override me)') @staticmethod @@ -290,6 +298,11 @@ def message_sent_handler(pdu, **kwargs): May be overridden""" logger.warning('Message sent handler (Override me)') + @staticmethod + def unbind_received_handlerpdu, **kwargs): + """Called when SMPP server sends undbind. + May be overridden""" + logger.warning('Ubind from SMPP server (Override me)') def read_once(self, ignore_error_codes=None): """Read a PDU and act""" From 85485cdcb91355b1c64fed4a0aec15a76fccfac0 Mon Sep 17 00:00:00 2001 From: Martin Harari Thuresson Date: Mon, 30 Apr 2018 16:36:52 +0100 Subject: [PATCH 28/30] Added support for server unbind --- smpplib/client.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/smpplib/client.py b/smpplib/client.py index 2673522..3d7f603 100644 --- a/smpplib/client.py +++ b/smpplib/client.py @@ -299,7 +299,7 @@ def message_sent_handler(pdu, **kwargs): logger.warning('Message sent handler (Override me)') @staticmethod - def unbind_received_handlerpdu, **kwargs): + def unbind_received_handler(pdu, **kwargs): """Called when SMPP server sends undbind. May be overridden""" logger.warning('Ubind from SMPP server (Override me)') @@ -345,6 +345,9 @@ def read_once(self, ignore_error_codes=None): and e.args[1] in ignore_error_codes: logging.warning('(%d) %s. Ignored.' % (e.args[1], e.args[0])) + elif self.state == consts.SMPP_CLIENT_STATE_OPEN \ + or self.state == consts.SMPP_CLIENT_STATE_CLOSED: + raise exceptions.UnbindFromServer('Server unbind complete') else: raise From 1da993694da94d00916a69e09041dd7e8aecc078 Mon Sep 17 00:00:00 2001 From: Martin Harari Thuresson Date: Tue, 1 May 2018 07:56:31 +0000 Subject: [PATCH 29/30] Added support for missing socket-data --- smpplib/client.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/smpplib/client.py b/smpplib/client.py index 3d7f603..81010c2 100644 --- a/smpplib/client.py +++ b/smpplib/client.py @@ -194,8 +194,13 @@ def read_pdu(self): raw_len = '' try: while len(raw_len) < 4: - raw_len += self._socket.recv(4 - len(raw_len)) + logger.debug('Waiting for more header data') + new_data = self._socket.recv(4 - len(raw_len)) + raw_len += new_data + if new_data == '': + raise exceptions.ConnectionError() except socket.timeout: + logger.debug('Socket timeout') raise except socket.error as e: logger.warning(e) @@ -212,7 +217,10 @@ def read_pdu(self): logger.debug('Reading PDU of %s bytes', length) raw_pdu = raw_len while len(raw_pdu) < length: - raw_pdu += self._socket.recv(length - len(raw_pdu)) + new_data = self._socket.recv(length - len(raw_pdu)) + raw_pdu += new_data + if new_data == '': + raise exceptions.ConnectionError() logger.debug('<<%s (%d bytes)', binascii.b2a_hex(raw_pdu), len(raw_pdu)) From 16110d4ab9edf618af705c1d54d0e99cffe44d7d Mon Sep 17 00:00:00 2001 From: Martin Harari Thuresson Date: Fri, 4 May 2018 14:26:05 +0000 Subject: [PATCH 30/30] For for generic_unbind read and reply --- smpplib/client.py | 4 ++-- smpplib/command.py | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/smpplib/client.py b/smpplib/client.py index 81010c2..16dd693 100644 --- a/smpplib/client.py +++ b/smpplib/client.py @@ -323,14 +323,14 @@ def read_once(self, ignore_error_codes=None): self.send_pdu(p) return - if p.is_error() and not p.command =='submit_sm_resp': + if p.is_error() and not p.command =='submit_sm_resp' and not 'generic_nack': raise exceptions.PDUError( '({}) {}: {}'.format(p.status, p.command, consts.DESCRIPTIONS.get(p.status, 'Unknown status')), int(p.status)) if p.command == 'unbind': self._unbind_received(p) - elif p.command == 'submit_sm_resp': + elif p.command in ['submit_sm_resp', 'generic_nack']: self.message_sent_handler(pdu=p) elif p.command == 'deliver_sm': self._message_received(p) diff --git a/smpplib/command.py b/smpplib/command.py index 0a35455..a054c4b 100644 --- a/smpplib/command.py +++ b/smpplib/command.py @@ -572,7 +572,8 @@ def __init__(self, command, **kwargs): class GenericNAck(Command): """General Negative Acknowledgement class""" - _defs = [] + params_order = tuple() + parms = {} def __init__(self, command, **kwargs): """Initialize"""