PKb?xH[C8jjsmpp/clickatell.py clickatell_defaults = { 'interface_version': '34', 'dest_addr_ton': 1, 'dest_addr_npi': 1, } PK;xHsmpp/__init__.pyPKb?xH8RSS smpp/esme.pyimport socket from pdu_builder import * class ESME(object): def __init__(self): self.state = 'CLOSED' self.sequence_number = 1 self.conn = None self.defaults = { 'host': '127.0.0.1', 'port': 2775, 'dest_addr_ton': 0, 'dest_addr_npi': 0, } def loadDefaults(self, defaults): self.defaults = dict(self.defaults, **defaults) def connect(self): if self.state in ['CLOSED']: self.conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.conn.connect((self.defaults['host'], self.defaults['port'])) self.state = 'OPEN' def disconnect(self): if self.state in ['BOUND_TX', 'BOUND_RX', 'BOUND_TRX']: self.__unbind() if self.state in ['OPEN']: self.conn.close() self.state = 'CLOSED' def __recv(self): pdu = None length_bin = self.conn.recv(4) if not length_bin: return None else: # print 'length_bin', len(length_bin), length_bin if len(length_bin) == 4: length = int(binascii.b2a_hex(length_bin), 16) rest_bin = self.conn.recv(length-4) pdu = unpack_pdu(length_bin + rest_bin) print '...', pdu['header']['sequence_number'], print '>', pdu['header']['command_id'], print '...', pdu['header']['command_status'] return pdu def __is_ok(self, pdu, id_check=None): if (isinstance(pdu, dict) and pdu.get('header', {}).get('command_status') == 'ESME_ROK' and (id_check is None or id_check == pdu['header'].get('command_id'))): return True else: return False def bind_transmitter(self): if self.state in ['CLOSED']: self.connect() if self.state in ['OPEN']: pdu = BindTransmitter(self.sequence_number, **self.defaults) self.conn.send(pdu.get_bin()) self.sequence_number += 1 if self.__is_ok(self.__recv(), 'bind_transmitter_resp'): self.state = 'BOUND_TX' def __unbind(self): if self.state in ['BOUND_TX', 'BOUND_RX', 'BOUND_TRX']: pdu = Unbind(self.sequence_number) self.conn.send(pdu.get_bin()) self.sequence_number += 1 if self.__is_ok(self.__recv(), 'unbind_resp'): self.state = 'OPEN' # def unbind(self): # will probably be deprecated # self.__unbind() def submit_sm(self, **kwargs): if self.state in ['BOUND_TX', 'BOUND_TRX']: print dict(self.defaults, **kwargs) pdu = SubmitSM(self.sequence_number, **dict(self.defaults, **kwargs)) self.conn.send(pdu.get_bin()) self.sequence_number += 1 submit_sm_resp = self.__recv() # print self.__is_ok(submit_sm_resp, 'submit_sm_resp') def submit_multi(self, dest_address=[], **kwargs): if self.state in ['BOUND_TX', 'BOUND_TRX']: pdu = SubmitMulti(self.sequence_number, **dict(self.defaults, **kwargs)) for item in dest_address: if isinstance(item, str): # assume strings are addresses not lists pdu.addDestinationAddress( item, dest_addr_ton=self.defaults['dest_addr_ton'], dest_addr_npi=self.defaults['dest_addr_npi'], ) elif isinstance(item, dict): if item.get('dest_flag') == 1: pdu.addDestinationAddress( item.get('destination_addr', ''), dest_addr_ton=item.get('dest_addr_ton', self.defaults['dest_addr_ton']), dest_addr_npi=item.get('dest_addr_npi', self.defaults['dest_addr_npi']), ) elif item.get('dest_flag') == 2: pdu.addDistributionList(item.get('dl_name')) self.conn.send(pdu.get_bin()) self.sequence_number += 1 submit_multi_resp = self.__recv() # print self.__is_ok(submit_multi_resp, 'submit_multi_resp') PKb?xH,  smpp/smsc.pyimport socket from esme import * class SMSC(ESME): # this is a dummy SMSC, just for testing def __init__(self, port=2775, credentials={}): self.credentials = credentials self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.server.bind(('', port)) self.server.listen(1) self.conn, self.addr = self.server.accept() print 'Connected by', self.addr while 1: pdu = self._ESME__recv() if not pdu: break self.conn.send(pack_pdu(self.__response(pdu))) self.conn.close() def __response(self, pdu): pdu_resp = {} resp_header = {} pdu_resp['header'] = resp_header resp_header['command_length'] = 0 resp_header['command_id'] = 'generic_nack' resp_header['command_status'] = 'ESME_ROK' resp_header['sequence_number'] = pdu['header']['sequence_number'] if pdu['header']['command_id'] in [ 'bind_transmitter', 'bind_receiver', 'bind_transceiver', 'unbind', 'submit_sm', 'submit_multi', 'deliver_sm', 'data_sm', 'query_sm', 'cancel_sm', 'replace_sm', 'enquire_link', ]: resp_header['command_id'] = pdu['header']['command_id']+'_resp' if pdu['header']['command_id'] in [ 'bind_transmitter', 'bind_receiver', 'bind_transceiver', ]: resp_body = {} pdu_resp['body'] = resp_body resp_mandatory_parameters = {} resp_body['mandatory_parameters'] = resp_mandatory_parameters resp_mandatory_parameters['system_id'] = pdu['body']['mandatory_parameters']['system_id'] if pdu['header']['command_id'] in [ # 'submit_sm', # message_id is optional in submit_sm 'submit_multi', 'deliver_sm', 'data_sm', 'query_sm', ]: resp_body = {} pdu_resp['body'] = resp_body resp_mandatory_parameters = {} resp_body['mandatory_parameters'] = resp_mandatory_parameters resp_mandatory_parameters['message_id'] = '' if pdu['header']['command_id'] == 'submit_multi': resp_mandatory_parameters['no_unsuccess'] = 0 if pdu['header']['command_id'] == 'query_sm': resp_mandatory_parameters['final_date'] = '' resp_mandatory_parameters['message_state'] = 0 resp_mandatory_parameters['error_code'] = 0 return pdu_resp if __name__ == '__main__': smsc = SMSC(2777) PKb?xHHsmpp/pdu_inspector.pyfrom pdu import * def detect_multipart(pdu): to_msisdn = pdu['body']['mandatory_parameters']['destination_addr'] from_msisdn = pdu['body']['mandatory_parameters']['source_addr'] short_message = pdu['body']['mandatory_parameters']['short_message'] optional_parameters = {} for d in pdu['body'].get('optional_parameters', []): optional_parameters[d['tag']] = d['value'] # print repr(pdu) try: mdict = {'multipart_type': 'TLV'} mdict['to_msisdn'] = to_msisdn mdict['from_msisdn'] = from_msisdn mdict['reference_number'] = optional_parameters['sar_msg_ref_num'] mdict['total_number'] = optional_parameters['sar_total_segments'] mdict['part_number'] = optional_parameters['sar_segment_seqnum'] mdict['part_message'] = short_message return mdict except: pass # all other multipart types will fail on short_message == None if short_message is None: return None if short_message[0:1] == '\x00' and \ short_message[1:2] == '\x03' and \ len(short_message) >= 5: mdict = {'multipart_type': 'SAR'} mdict['to_msisdn'] = to_msisdn mdict['from_msisdn'] = from_msisdn mdict['reference_number'] = int(binascii.b2a_hex(short_message[2:3]), 16) mdict['total_number'] = int(binascii.b2a_hex(short_message[3:4]), 16) mdict['part_number'] = int(binascii.b2a_hex(short_message[4:5]), 16) mdict['part_message'] = short_message[5:] return mdict if short_message[0:1] == '\x05' and \ short_message[1:2] == '\x00' and \ short_message[2:3] == '\x03' and \ len(short_message) >= 6: mdict = {'multipart_type': 'CSM'} mdict['to_msisdn'] = to_msisdn mdict['from_msisdn'] = from_msisdn mdict['reference_number'] = int(binascii.b2a_hex(short_message[3:4]), 16) mdict['total_number'] = int(binascii.b2a_hex(short_message[4:5]), 16) mdict['part_number'] = int(binascii.b2a_hex(short_message[5:6]), 16) mdict['part_message'] = short_message[6:] return mdict if short_message[0:1] == '\x06' and \ short_message[1:2] == '\x00' and \ short_message[2:3] == '\x04' and \ len(short_message) >= 7: mdict = {'multipart_type': 'CSM16'} mdict['to_msisdn'] = to_msisdn mdict['from_msisdn'] = from_msisdn mdict['reference_number'] = int(binascii.b2a_hex(short_message[3:5]), 16) mdict['total_number'] = int(binascii.b2a_hex(short_message[5:6]), 16) mdict['part_number'] = int(binascii.b2a_hex(short_message[6:7]), 16) mdict['part_message'] = short_message[7:] return mdict return None def multipart_key(multipart, delimiter='_'): key_list = [] key_list.append(str(multipart.get('from_msisdn'))) key_list.append(str(multipart.get('to_msisdn'))) key_list.append(str(multipart.get('reference_number'))) key_list.append(str(multipart.get('total_number'))) return delimiter.join(key_list) class MultipartMessage: def __init__(self, array=None): self.array = {} for k, v in (array or {}).items(): self.array.update({int(k): v}) def add_pdu(self, pdu): part = detect_multipart(pdu) if part: self.array[part['part_number']] = part return True else: return False def get_partial(self): items = sorted(self.array.items()) message = ''.join([i[1]['part_message'] for i in items]) to_msisdn = from_msisdn = '' if len(items): to_msisdn = items[0][1].get('to_msisdn') from_msisdn = items[0][1].get('from_msisdn') return {'to_msisdn': to_msisdn, 'from_msisdn': from_msisdn, 'message': message} def get_completed(self): items = self.array.items() if len(items) and len(items) == items[0][1].get('total_number'): return self.get_partial() return None def get_key(self, delimiter='_'): items = self.array.items() if len(items): return multipart_key(items[0][1], delimiter) return None def get_array(self): return self.array PKb?xHJ 4 4 smpp/pdu.pyimport binascii import re try: import json except: import simplejson as json # Inserting certain referenced dicts in here means they can be declared in the same order as in the spec. maps = {} # SMPP PDU Definition - SMPP v3.4, section 4, page 45 mandatory_parameter_lists = { 'bind_transmitter': [ # SMPP v3.4, section 4.1.1, table 4-1, page 46 {'name': 'system_id', 'min': 1, 'max': 16, 'var': True, 'type': 'string', 'map': None}, {'name': 'password', 'min': 1, 'max': 9, 'var': True, 'type': 'string', 'map': None}, {'name': 'system_type', 'min': 1, 'max': 13, 'var': True, 'type': 'string', 'map': None}, {'name': 'interface_version', 'min': 1, 'max': 1, 'var': False, 'type': 'hex', 'map': None}, {'name': 'addr_ton', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': 'addr_ton'}, {'name': 'addr_npi', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': 'addr_npi'}, {'name': 'address_range', 'min': 1, 'max': 41, 'var': True, 'type': 'string', 'map': None} ], 'bind_transmitter_resp': [ # SMPP v3.4, section 4.1.2, table 4-2, page 47 {'name': 'system_id', 'min': 1, 'max': 16, 'var': True, 'type': 'string', 'map': None} ], 'bind_receiver': [ # SMPP v3.4, section 4.1.3, table 4-3, page 48 {'name': 'system_id', 'min': 1, 'max': 16, 'var': True, 'type': 'string', 'map': None}, {'name': 'password', 'min': 1, 'max': 9, 'var': True, 'type': 'string', 'map': None}, {'name': 'system_type', 'min': 1, 'max': 13, 'var': True, 'type': 'string', 'map': None}, {'name': 'interface_version', 'min': 1, 'max': 1, 'var': False, 'type': 'hex', 'map': None}, {'name': 'addr_ton', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': 'addr_ton'}, {'name': 'addr_npi', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': 'addr_npi'}, {'name': 'address_range', 'min': 1, 'max': 41, 'var': True, 'type': 'string', 'map': None} ], 'bind_receiver_resp': [ # SMPP v3.4, section 4.1.4, table 4-4, page 50 {'name': 'system_id', 'min': 1, 'max': 16, 'var': True, 'type': 'string', 'map': None} ], 'bind_transceiver': [ # SMPP v3.4, section 4.1.5, table 4-5, page 51 {'name': 'system_id', 'min': 1, 'max': 16, 'var': True, 'type': 'string', 'map': None}, {'name': 'password', 'min': 1, 'max': 9, 'var': True, 'type': 'string', 'map': None}, {'name': 'system_type', 'min': 1, 'max': 13, 'var': True, 'type': 'string', 'map': None}, {'name': 'interface_version', 'min': 1, 'max': 1, 'var': False, 'type': 'hex', 'map': None}, {'name': 'addr_ton', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': 'addr_ton'}, {'name': 'addr_npi', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': 'addr_npi'}, {'name': 'address_range', 'min': 1, 'max': 41, 'var': True, 'type': 'string', 'map': None} ], 'bind_transceiver_resp': [ # SMPP v3.4, section 4.1.6, table 4-6, page 52 {'name': 'system_id', 'min': 1, 'max': 16, 'var': True, 'type': 'string', 'map': None} ], 'outbind': [ # SMPP v3.4, section 4.1.7.1, page 54 {'name': 'system_id', 'min': 1, 'max': 16, 'var': True, 'type': 'string', 'map': None}, {'name': 'password', 'min': 1, 'max': 9, 'var': True, 'type': 'string', 'map': None} ], 'unbind': [ # SMPP v3.4, section 4.2.1, table 4-7, page 56 ], 'unbind_resp': [ # SMPP v3.4, section 4.2.2, table 4-8, page 56 ], 'generic_nack': [ # SMPP v3.4, section 4.3.1, table 4-9, page 57 ], 'submit_sm': [ # SMPP v3.4, section 4.4.1, table 4-10, page 59-61 {'name': 'service_type', 'min': 1, 'max': 6, 'var': True, 'type': 'string', 'map': None}, {'name': 'source_addr_ton', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': 'addr_ton'}, {'name': 'source_addr_npi', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': 'addr_npi'}, {'name': 'source_addr', 'min': 1, 'max': 21, 'var': True, 'type': 'string', 'map': None}, {'name': 'dest_addr_ton', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': 'addr_ton'}, {'name': 'dest_addr_npi', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': 'addr_npi'}, {'name': 'destination_addr', 'min': 1, 'max': 21, 'var': True, 'type': 'string', 'map': None}, {'name': 'esm_class', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None}, {'name': 'protocol_id', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None}, {'name': 'priority_flag', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None}, {'name': 'schedule_delivery_time', 'min': 1, 'max': 17, 'var': False, 'type': 'string', 'map': None}, {'name': 'validity_period', 'min': 1, 'max': 17, 'var': True, 'type': 'string', 'map': None}, {'name': 'registered_delivery', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None}, {'name': 'replace_if_present_flag', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None}, {'name': 'data_coding', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None}, {'name': 'sm_default_msg_id', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None}, {'name': 'sm_length', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None}, {'name': 'short_message', 'min': 0, 'max': 254, 'var': 'sm_length', 'type': 'xstring', 'map': None} ], 'submit_sm_resp': [ # SMPP v3.4, section 4.4.2, table 4-11, page 67 {'name': 'message_id', 'min': 0, 'max': 65, 'var': True, 'type': 'string', 'map': None} ], 'submit_multi': [ # SMPP v3.4, section 4.5.1, table 4-12, page 69-71 {'name': 'service_type', 'min': 1, 'max': 6, 'var': True, 'type': 'string', 'map': None}, {'name': 'source_addr_ton', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': 'addr_ton'}, {'name': 'source_addr_npi', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': 'addr_npi'}, {'name': 'source_addr', 'min': 1, 'max': 21, 'var': True, 'type': 'string', 'map': None}, {'name': 'number_of_dests', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None}, {'name': 'dest_address', 'min': 0, 'max': 0, 'var': 'number_of_dests', 'type': 'dest_address', 'map': None}, {'name': 'esm_class', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None}, {'name': 'protocol_id', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None}, {'name': 'priority_flag', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None}, {'name': 'schedule_delivery_time', 'min': 1, 'max': 17, 'var': False, 'type': 'string', 'map': None}, {'name': 'validity_period', 'min': 1, 'max': 17, 'var': False, 'type': 'string', 'map': None}, {'name': 'registered_delivery', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None}, {'name': 'replace_if_present_flag', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None}, {'name': 'data_coding', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None}, {'name': 'sm_default_msg_id', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None}, {'name': 'sm_length', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None}, {'name': 'short_message', 'min': 0, 'max': 254, 'var': 'sm_length', 'type': 'xstring', 'map': None} ], 'dest_address': [ # SMPP v3.4, section 4.5.1.1, table 4-13, page 75 {'name': 'dest_flag', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None} # 'sme_dest_address' or 'distribution_list' goes here ], 'sme_dest_address': [ # SMPP v3.4, section 4.5.1.1, table 4-14, page 75 {'name': 'dest_addr_ton', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': 'addr_ton'}, {'name': 'dest_addr_npi', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': 'addr_npi'}, {'name': 'destination_addr', 'min': 1, 'max': 21, 'var': True, 'type': 'string', 'map': None} ], 'distribution_list': [ # SMPP v3.4, section 4.5.1.2, table 4-15, page 75 {'name': 'dl_name', 'min': 1, 'max': 21, 'var': True, 'type': 'string', 'map': None} ], 'submit_multi_resp': [ # SMPP v3.4, section 4.5.2, table 4-16, page 76 {'name': 'message_id', 'min': 1, 'max': 65, 'var': True, 'type': 'string', 'map': None}, {'name': 'no_unsuccess', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None}, {'name': 'unsuccess_sme', 'min': 0, 'max': 0, 'var': 'no_unsuccess', 'type': 'unsuccess_sme', 'map': None} ], 'unsuccess_sme': [ # SMPP v3.4, section 4.5.2.1, table 4-17, page 77 {'name': 'dest_addr_ton', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': 'addr_ton'}, {'name': 'dest_addr_npi', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': 'addr_npi'}, {'name': 'destination_addr', 'min': 1, 'max': 21, 'var': True, 'type': 'string', 'map': None}, {'name': 'error_status_code', 'min': 4, 'max': 4, 'var': False, 'type': 'integer', 'map': None} ], 'deliver_sm': [ # SMPP v3.4, section 4.6.1, table 4-18, page 79-81 {'name': 'service_type', 'min': 1, 'max': 6, 'var': True, 'type': 'string', 'map': None}, {'name': 'source_addr_ton', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': 'addr_ton'}, {'name': 'source_addr_npi', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': 'addr_npi'}, {'name': 'source_addr', 'min': 1, 'max': 21, 'var': True, 'type': 'string', 'map': None}, {'name': 'dest_addr_ton', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': 'addr_ton'}, {'name': 'dest_addr_npi', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': 'addr_npi'}, {'name': 'destination_addr', 'min': 1, 'max': 21, 'var': True, 'type': 'string', 'map': None}, {'name': 'esm_class', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None}, {'name': 'protocol_id', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None}, {'name': 'priority_flag', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None}, {'name': 'schedule_delivery_time', 'min': 1, 'max': 1, 'var': False, 'type': 'string', 'map': None}, {'name': 'validity_period', 'min': 1, 'max': 1, 'var': False, 'type': 'string', 'map': None}, {'name': 'registered_delivery', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None}, {'name': 'replace_if_present_flag', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None}, {'name': 'data_coding', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None}, {'name': 'sm_default_msg_id', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None}, {'name': 'sm_length', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None}, {'name': 'short_message', 'min': 0, 'max': 254, 'var': 'sm_length', 'type': 'xstring', 'map': None} ], 'deliver_sm_resp': [ # SMPP v3.4, section 4.6.2, table 4-19, page 85 {'name': 'message_id', 'min': 1, 'max': 1, 'var': False, 'type': 'string', 'map': None} ], 'data_sm': [ # SMPP v3.4, section 4.7.1, table 4-20, page 87-88 {'name': 'service_type', 'min': 1, 'max': 6, 'var': True, 'type': 'string', 'map': None}, {'name': 'source_addr_ton', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': 'addr_ton'}, {'name': 'source_addr_npi', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': 'addr_npi'}, {'name': 'source_addr', 'min': 1, 'max': 65, 'var': True, 'type': 'string', 'map': None}, {'name': 'dest_addr_ton', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': 'addr_ton'}, {'name': 'dest_addr_npi', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': 'addr_npi'}, {'name': 'destination_addr', 'min': 1, 'max': 65, 'var': True, 'type': 'string', 'map': None}, {'name': 'esm_class', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None}, {'name': 'registered_delivery', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None}, {'name': 'data_coding', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None} ], 'data_sm_resp': [ # SMPP v3.4, section 4.7.2, table 4-21, page 93 {'name': 'message_id', 'min': 1, 'max': 65, 'var': True, 'type': 'string', 'map': None} ], 'query_sm': [ # SMPP v3.4, section 4.8.1, table 4-22, page 95 {'name': 'message_id', 'min': 1, 'max': 65, 'var': True, 'type': 'string', 'map': None}, {'name': 'source_addr_ton', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': 'addr_ton'}, {'name': 'source_addr_npi', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': 'addr_npi'}, {'name': 'source_addr', 'min': 1, 'max': 21, 'var': True, 'type': 'string', 'map': None} ], 'query_sm_resp': [ # SMPP v3.4, section 4.7.2, table 4-21, page 93 {'name': 'message_id', 'min': 1, 'max': 65, 'var': True, 'type': 'string', 'map': None}, {'name': 'final_date', 'min': 1, 'max': 17, 'var': False, 'type': 'string', 'map': None}, {'name': 'message_state', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None}, {'name': 'error_code', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None} ], 'cancel_sm': [ # SMPP v3.4, section 4.9.1, table 4-24, page 98-99 {'name': 'service_type', 'min': 1, 'max': 6, 'var': True, 'type': 'string', 'map': None}, {'name': 'message_id', 'min': 1, 'max': 65, 'var': True, 'type': 'string', 'map': None}, {'name': 'source_addr_ton', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': 'addr_ton'}, {'name': 'source_addr_npi', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': 'addr_npi'}, {'name': 'source_addr', 'min': 1, 'max': 21, 'var': True, 'type': 'string', 'map': None}, {'name': 'dest_addr_ton', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': 'addr_ton'}, {'name': 'dest_addr_npi', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': 'addr_npi'}, {'name': 'destination_addr', 'min': 1, 'max': 21, 'var': True, 'type': 'string', 'map': None} ], 'cancel_sm_resp': [ # SMPP v3.4, section 4.9.2, table 4-25, page 100 ], 'replace_sm': [ # SMPP v3.4, section 4.10.1, table 4-26, page 102-103 {'name': 'message_id', 'min': 1, 'max': 65, 'var': True, 'type': 'string', 'map': None}, {'name': 'source_addr_ton', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': 'addr_ton'}, {'name': 'source_addr_npi', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': 'addr_npi'}, {'name': 'source_addr', 'min': 1, 'max': 21, 'var': True, 'type': 'string', 'map': None}, {'name': 'schedule_delivery_time', 'min': 1, 'max': 17, 'var': False, 'type': 'string', 'map': None}, {'name': 'validity_period', 'min': 1, 'max': 17, 'var': False, 'type': 'string', 'map': None}, {'name': 'registered_delivery', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None}, {'name': 'replace_if_present_flag', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None}, {'name': 'data_coding', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None}, {'name': 'sm_default_msg_id', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None}, {'name': 'sm_length', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': None}, {'name': 'short_message', 'min': 0, 'max': 254, 'var': 'sm_length', 'type': 'xstring', 'map': None} ], 'replace_sm_resp': [ # SMPP v3.4, section 4.10.2, table 4-27, page 104 ], 'enquire_link': [ # SMPP v3.4, section 4.11.1, table 4-28, page 106 ], 'enquire_link_resp': [ # SMPP v3.4, section 4.11.2, table 4-29, page 106 ], 'alert_notification': [ # SMPP v3.4, section 4.12.1, table 4-30, page 108 {'name': 'source_addr_ton', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': 'addr_ton'}, {'name': 'source_addr_npi', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': 'addr_npi'}, {'name': 'source_addr', 'min': 1, 'max': 65, 'var': True, 'type': 'string', 'map': None}, {'name': 'esme_addr_ton', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': 'addr_ton'}, {'name': 'esme_addr_npi', 'min': 1, 'max': 1, 'var': False, 'type': 'integer', 'map': 'addr_npi'}, {'name': 'esme_addr', 'min': 1, 'max': 65, 'var': True, 'type': 'string', 'map': None}, ] } def mandatory_parameter_list_by_command_name(command_name): return mandatory_parameter_lists.get(command_name, []) # Command IDs - SMPP v3.4, section 5.1.2.1, table 5-1, page 110-111 command_id_by_hex = { '80000000': {'hex': '80000000', 'name': 'generic_nack'}, '00000001': {'hex': '00000001', 'name': 'bind_receiver'}, '80000001': {'hex': '80000001', 'name': 'bind_receiver_resp'}, '00000002': {'hex': '00000002', 'name': 'bind_transmitter'}, '80000002': {'hex': '80000002', 'name': 'bind_transmitter_resp'}, '00000003': {'hex': '00000003', 'name': 'query_sm'}, '80000003': {'hex': '80000003', 'name': 'query_sm_resp'}, '00000004': {'hex': '00000004', 'name': 'submit_sm'}, '80000004': {'hex': '80000004', 'name': 'submit_sm_resp'}, '00000005': {'hex': '00000005', 'name': 'deliver_sm'}, '80000005': {'hex': '80000005', 'name': 'deliver_sm_resp'}, '00000006': {'hex': '00000006', 'name': 'unbind'}, '80000006': {'hex': '80000006', 'name': 'unbind_resp'}, '00000007': {'hex': '00000007', 'name': 'replace_sm'}, '80000007': {'hex': '80000007', 'name': 'replace_sm_resp'}, '00000008': {'hex': '00000008', 'name': 'cancel_sm'}, '80000008': {'hex': '80000008', 'name': 'cancel_sm_resp'}, '00000009': {'hex': '00000009', 'name': 'bind_transceiver'}, '80000009': {'hex': '80000009', 'name': 'bind_transceiver_resp'}, '0000000b': {'hex': '0000000b', 'name': 'outbind'}, '00000015': {'hex': '00000015', 'name': 'enquire_link'}, '80000015': {'hex': '80000015', 'name': 'enquire_link_resp'}, '00000021': {'hex': '00000021', 'name': 'submit_multi'}, '80000021': {'hex': '80000021', 'name': 'submit_multi_resp'}, '00000102': {'hex': '00000102', 'name': 'alert_notification'}, '00000103': {'hex': '00000103', 'name': 'data_sm'}, '80000103': {'hex': '80000103', 'name': 'data_sm_resp'}, # v4 codes '80010000': {'hex': '80010000', 'name': 'generic_nack_v4'}, '00010001': {'hex': '00010001', 'name': 'bind_receiver_v4'}, '80010001': {'hex': '80010001', 'name': 'bind_receiver_resp_v4'}, '00010002': {'hex': '00010002', 'name': 'bind_transmitter_v4'}, '80010002': {'hex': '80010002', 'name': 'bind_transmitter_resp_v4'}, '00010003': {'hex': '00010003', 'name': 'query_sm_v4'}, '80010003': {'hex': '80010003', 'name': 'query_sm_resp_v4'}, '00010004': {'hex': '00010004', 'name': 'submit_sm_v4'}, '80010004': {'hex': '80010004', 'name': 'submit_sm_resp_v4'}, '00010005': {'hex': '00010005', 'name': 'deliver_sm_v4'}, '80010005': {'hex': '80010005', 'name': 'deliver_sm_resp_v4'}, '00010006': {'hex': '00010006', 'name': 'unbind_v4'}, '80010006': {'hex': '80010006', 'name': 'unbind_resp_v4'}, '00010007': {'hex': '00010007', 'name': 'replace_sm_v4'}, '80010007': {'hex': '80010007', 'name': 'replace_sm_resp_v4'}, '00010008': {'hex': '00010008', 'name': 'cancel_sm_v4'}, '80010008': {'hex': '80010008', 'name': 'cancel_sm_resp_v4'}, '00010009': {'hex': '00010009', 'name': 'delivery_receipt_v4'}, '80010009': {'hex': '80010009', 'name': 'delivery_receipt_resp_v4'}, '0001000a': {'hex': '0001000a', 'name': 'enquire_link_v4'}, '8001000a': {'hex': '8001000a', 'name': 'enquire_link_resp_v4'}, '0001000b': {'hex': '0001000b', 'name': 'outbind_v4'}, } def command_id_name_by_hex(x): return command_id_by_hex.get(x, {}).get('name') command_id_by_name = { 'generic_nack' :{ 'hex': '80000000', 'name': 'generic_nack'}, 'bind_receiver' :{ 'hex': '00000001', 'name': 'bind_receiver'}, 'bind_receiver_resp' :{ 'hex': '80000001', 'name': 'bind_receiver_resp'}, 'bind_transmitter' :{ 'hex': '00000002', 'name': 'bind_transmitter'}, 'bind_transmitter_resp' :{ 'hex': '80000002', 'name': 'bind_transmitter_resp'}, 'query_sm' :{ 'hex': '00000003', 'name': 'query_sm'}, 'query_sm_resp' :{ 'hex': '80000003', 'name': 'query_sm_resp'}, 'submit_sm' :{ 'hex': '00000004', 'name': 'submit_sm'}, 'submit_sm_resp' :{ 'hex': '80000004', 'name': 'submit_sm_resp'}, 'deliver_sm' :{ 'hex': '00000005', 'name': 'deliver_sm'}, 'deliver_sm_resp' :{ 'hex': '80000005', 'name': 'deliver_sm_resp'}, 'unbind' :{ 'hex': '00000006', 'name': 'unbind'}, 'unbind_resp' :{ 'hex': '80000006', 'name': 'unbind_resp'}, 'replace_sm' :{ 'hex': '00000007', 'name': 'replace_sm'}, 'replace_sm_resp' :{ 'hex': '80000007', 'name': 'replace_sm_resp'}, 'cancel_sm' :{ 'hex': '00000008', 'name': 'cancel_sm'}, 'cancel_sm_resp' :{ 'hex': '80000008', 'name': 'cancel_sm_resp'}, 'bind_transceiver' :{ 'hex': '00000009', 'name': 'bind_transceiver'}, 'bind_transceiver_resp' :{ 'hex': '80000009', 'name': 'bind_transceiver_resp'}, 'outbind' :{ 'hex': '0000000b', 'name': 'outbind'}, 'enquire_link' :{ 'hex': '00000015', 'name': 'enquire_link'}, 'enquire_link_resp' :{ 'hex': '80000015', 'name': 'enquire_link_resp'}, 'submit_multi' :{ 'hex': '00000021', 'name': 'submit_multi'}, 'submit_multi_resp' :{ 'hex': '80000021', 'name': 'submit_multi_resp'}, 'alert_notification' :{ 'hex': '00000102', 'name': 'alert_notification'}, 'data_sm' :{ 'hex': '00000103', 'name': 'data_sm'}, 'data_sm_resp' :{ 'hex': '80000103', 'name': 'data_sm_resp'}, # v4 codes 'generic_nack_v4' :{ 'hex': '80010000', 'name': 'generic_nack_v4'}, 'bind_receiver_v4' :{ 'hex': '00010001', 'name': 'bind_receiver_v4'}, 'bind_receiver_resp_v4' :{ 'hex': '80010001', 'name': 'bind_receiver_resp_v4'}, 'bind_transmitter_v4' :{ 'hex': '00010002', 'name': 'bind_transmitter_v4'}, 'bind_transmitter_resp_v4': {'hex': '80010002', 'name': 'bind_transmitter_resp_v4'}, 'query_sm_v4' :{ 'hex': '00010003', 'name': 'query_sm_v4'}, 'query_sm_resp_v4' :{ 'hex': '80010003', 'name': 'query_sm_resp_v4'}, 'submit_sm_v4' :{ 'hex': '00010004', 'name': 'submit_sm_v4'}, 'submit_sm_resp_v4' :{ 'hex': '80010004', 'name': 'submit_sm_resp_v4'}, 'deliver_sm_v4' :{ 'hex': '00010005', 'name': 'deliver_sm_v4'}, 'deliver_sm_resp_v4' :{ 'hex': '80010005', 'name': 'deliver_sm_resp_v4'}, 'unbind_v4' :{ 'hex': '00010006', 'name': 'unbind_v4'}, 'unbind_resp_v4' :{ 'hex': '80010006', 'name': 'unbind_resp_v4'}, 'replace_sm_v4' :{ 'hex': '00010007', 'name': 'replace_sm_v4'}, 'replace_sm_resp_v4' :{ 'hex': '80010007', 'name': 'replace_sm_resp_v4'}, 'cancel_sm_v4' :{ 'hex': '00010008', 'name': 'cancel_sm_v4'}, 'cancel_sm_resp_v4' :{ 'hex': '80010008', 'name': 'cancel_sm_resp_v4'}, 'delivery_receipt_v4' :{ 'hex': '00010009', 'name': 'delivery_receipt_v4'}, 'delivery_receipt_resp_v4':{ 'hex': '80010009', 'name': 'delivery_receipt_resp_v4'}, 'enquire_link_v4' :{ 'hex': '0001000a', 'name': 'enquire_link_v4'}, 'enquire_link_resp_v4' :{ 'hex': '8001000a', 'name': 'enquire_link_resp_v4'}, 'outbind_v4' :{ 'hex': '0001000b', 'name': 'outbind_v4'} } def command_id_hex_by_name(n): return command_id_by_name.get(n, {}).get('hex') # SMPP Error Codes (ESME) - SMPP v3.4, section 5.1.3, table 5-2, page 112-114 command_status_by_hex = { '00000000': {'hex': '00000000', 'name': 'ESME_ROK', 'description': 'No error'}, '00000001': {'hex': '00000001', 'name': 'ESME_RINVMSGLEN', 'description': 'Message Length is invalid'}, '00000002': {'hex': '00000002', 'name': 'ESME_RINVCMDLEN', 'description': 'Command Length is invalid'}, '00000003': {'hex': '00000003', 'name': 'ESME_RINVCMDID', 'description': 'Invalid Command ID'}, '00000004': {'hex': '00000004', 'name': 'ESME_RINVBNDSTS', 'description': 'Incorrect BIND Status for given command'}, '00000005': {'hex': '00000005', 'name': 'ESME_RALYBND', 'description': 'ESME Already in bound state'}, '00000006': {'hex': '00000006', 'name': 'ESME_RINVPRTFLG', 'description': 'Invalid priority flag'}, '00000007': {'hex': '00000007', 'name': 'ESME_RINVREGDLVFLG', 'description': 'Invalid registered delivery flag'}, '00000008': {'hex': '00000008', 'name': 'ESME_RSYSERR', 'description': 'System Error'}, '0000000a': {'hex': '0000000a', 'name': 'ESME_RINVSRCADR', 'description': 'Invalid source address'}, '0000000b': {'hex': '0000000b', 'name': 'ESME_RINVDSTADR', 'description': 'Invalid destination address'}, '0000000c': {'hex': '0000000c', 'name': 'ESME_RINVMSGID', 'description': 'Message ID is invalid'}, '0000000d': {'hex': '0000000d', 'name': 'ESME_RBINDFAIL', 'description': 'Bind failed'}, '0000000e': {'hex': '0000000e', 'name': 'ESME_RINVPASWD', 'description': 'Invalid password'}, '0000000f': {'hex': '0000000f', 'name': 'ESME_RINVSYSID', 'description': 'Invalid System ID'}, '00000011': {'hex': '00000011', 'name': 'ESME_RCANCELFAIL', 'description': 'Cancel SM Failed'}, '00000013': {'hex': '00000013', 'name': 'ESME_RREPLACEFAIL', 'description': 'Replace SM Failed'}, '00000014': {'hex': '00000014', 'name': 'ESME_RMSGQFUL', 'description': 'Message queue full'}, '00000015': {'hex': '00000015', 'name': 'ESME_RINVSERTYP', 'description': 'Invalid service type'}, '00000033': {'hex': '00000033', 'name': 'ESME_RINVNUMDESTS', 'description': 'Invalid number of destinations'}, '00000034': {'hex': '00000034', 'name': 'ESME_RINVDLNAME', 'description': 'Invalid distribution list name'}, '00000040': {'hex': '00000040', 'name': 'ESME_RINVDESTFLAG', 'description': 'Destination flag is invalid (submit_multi)'}, '00000042': {'hex': '00000042', 'name': 'ESME_RINVSUBREP', 'description': "Invalid `submit with replace' request (i.e. submit_sm with replace_if_present_flag set)"}, '00000043': {'hex': '00000043', 'name': 'ESME_RINVESMCLASS', 'description': 'Invalid esm_class field data'}, '00000044': {'hex': '00000044', 'name': 'ESME_RCNTSUBDL', 'description': 'Cannot submit to distribution list'}, '00000045': {'hex': '00000045', 'name': 'ESME_RSUBMITFAIL', 'description': 'submit_sm or submit_multi failed'}, '00000048': {'hex': '00000048', 'name': 'ESME_RINVSRCTON', 'description': 'Invalid source address TON'}, '00000049': {'hex': '00000049', 'name': 'ESME_RINVSRCNPI', 'description': 'Invalid source address NPI'}, '00000050': {'hex': '00000050', 'name': 'ESME_RINVDSTTON', 'description': 'Invalid destination address TON'}, '00000051': {'hex': '00000051', 'name': 'ESME_RINVDSTNPI', 'description': 'Invalid destination address NPI'}, '00000053': {'hex': '00000053', 'name': 'ESME_RINVSYSTYP', 'description': 'Invalid system_type field'}, '00000054': {'hex': '00000054', 'name': 'ESME_RINVREPFLAG', 'description': 'Invalid replace_if_present flag'}, '00000055': {'hex': '00000055', 'name': 'ESME_RINVNUMMSGS', 'description': 'Invalid number of messages'}, '00000058': {'hex': '00000058', 'name': 'ESME_RTHROTTLED', 'description': 'Throttling error (ESME has exceeded allowed message limits)'}, '00000061': {'hex': '00000061', 'name': 'ESME_RINVSCHED', 'description': 'Invalid scheduled delivery time'}, '00000062': {'hex': '00000062', 'name': 'ESME_RINVEXPIRY', 'description': 'Invalid message validity period (expiry time)'}, '00000063': {'hex': '00000063', 'name': 'ESME_RINVDFTMSGID', 'description': 'Predefined message invalid or not found'}, '00000064': {'hex': '00000064', 'name': 'ESME_RX_T_APPN', 'description': 'ESME Receiver Temporary App Error Code'}, '00000065': {'hex': '00000065', 'name': 'ESME_RX_P_APPN', 'description': 'ESME Receiver Permanent App Error Code'}, '00000066': {'hex': '00000066', 'name': 'ESME_RX_R_APPN', 'description': 'ESME Receiver Reject Message Error Code'}, '00000067': {'hex': '00000067', 'name': 'ESME_RQUERYFAIL', 'description': 'query_sm request failed'}, '000000c0': {'hex': '000000c0', 'name': 'ESME_RINVOPTPARSTREAM', 'description': 'Error in the optional part of the PDU Body'}, '000000c1': {'hex': '000000c1', 'name': 'ESME_ROPTPARNOTALLWD', 'description': 'Optional paramenter not allowed'}, '000000c2': {'hex': '000000c2', 'name': 'ESME_RINVPARLEN', 'description': 'Invalid parameter length'}, '000000c3': {'hex': '000000c3', 'name': 'ESME_RMISSINGOPTPARAM', 'description': 'Expected optional parameter missing'}, '000000c4': {'hex': '000000c4', 'name': 'ESME_RINVOPTPARAMVAL', 'description': 'Invalid optional parameter value'}, '000000fe': {'hex': '000000fe', 'name': 'ESME_RDELIVERYFAILURE', 'description': 'Delivery Failure (used for data_sm_resp)'}, '000000ff': {'hex': '000000ff', 'name': 'ESME_RUNKNOWNERR', 'description': 'Unknown error'} } def command_status_name_by_hex(x): return command_status_by_hex.get(x, {}).get('name') command_status_by_name = { 'ESME_ROK' :{ 'hex': '00000000', 'name': 'ESME_ROK', 'description': 'No error'}, 'ESME_RINVMSGLEN' :{ 'hex': '00000001', 'name': 'ESME_RINVMSGLEN', 'description': 'Message Length is invalid'}, 'ESME_RINVCMDLEN' :{ 'hex': '00000002', 'name': 'ESME_RINVCMDLEN', 'description': 'Command Length is invalid'}, 'ESME_RINVCMDID' :{ 'hex': '00000003', 'name': 'ESME_RINVCMDID', 'description': 'Invalid Command ID'}, 'ESME_RINVBNDSTS' :{ 'hex': '00000004', 'name': 'ESME_RINVBNDSTS', 'description': 'Incorrect BIND Status for given command'}, 'ESME_RALYBND' :{ 'hex': '00000005', 'name': 'ESME_RALYBND', 'description': 'ESME Already in bound state'}, 'ESME_RINVPRTFLG' :{ 'hex': '00000006', 'name': 'ESME_RINVPRTFLG', 'description': 'Invalid priority flag'}, 'ESME_RINVREGDLVFLG' :{ 'hex': '00000007', 'name': 'ESME_RINVREGDLVFLG', 'description': 'Invalid registered delivery flag'}, 'ESME_RSYSERR' :{ 'hex': '00000008', 'name': 'ESME_RSYSERR', 'description': 'System Error'}, 'ESME_RINVSRCADR' :{ 'hex': '0000000a', 'name': 'ESME_RINVSRCADR', 'description': 'Invalid source address'}, 'ESME_RINVDSTADR' :{ 'hex': '0000000b', 'name': 'ESME_RINVDSTADR', 'description': 'Invalid destination address'}, 'ESME_RINVMSGID' :{ 'hex': '0000000c', 'name': 'ESME_RINVMSGID', 'description': 'Message ID is invalid'}, 'ESME_RBINDFAIL' :{ 'hex': '0000000d', 'name': 'ESME_RBINDFAIL', 'description': 'Bind failed'}, 'ESME_RINVPASWD' :{ 'hex': '0000000e', 'name': 'ESME_RINVPASWD', 'description': 'Invalid password'}, 'ESME_RINVSYSID' :{ 'hex': '0000000f', 'name': 'ESME_RINVSYSID', 'description': 'Invalid System ID'}, 'ESME_RCANCELFAIL' :{ 'hex': '00000011', 'name': 'ESME_RCANCELFAIL', 'description': 'Cancel SM Failed'}, 'ESME_RREPLACEFAIL' :{ 'hex': '00000013', 'name': 'ESME_RREPLACEFAIL', 'description': 'Replace SM Failed'}, 'ESME_RMSGQFUL' :{ 'hex': '00000014', 'name': 'ESME_RMSGQFUL', 'description': 'Message queue full'}, 'ESME_RINVSERTYP' :{ 'hex': '00000015', 'name': 'ESME_RINVSERTYP', 'description': 'Invalid service type'}, 'ESME_RINVNUMDESTS' :{ 'hex': '00000033', 'name': 'ESME_RINVNUMDESTS', 'description': 'Invalid number of destinations'}, 'ESME_RINVDLNAME' :{ 'hex': '00000034', 'name': 'ESME_RINVDLNAME', 'description': 'Invalid distribution list name'}, 'ESME_RINVDESTFLAG' :{ 'hex': '00000040', 'name': 'ESME_RINVDESTFLAG', 'description': 'Destination flag is invalid (submit_multi)'}, 'ESME_RINVSUBREP' :{ 'hex': '00000042', 'name': 'ESME_RINVSUBREP', 'description': "Invalid `submit with replace' request (i.e. submit_sm with replace_if_present_flag set)"}, 'ESME_RINVESMCLASS' :{ 'hex': '00000043', 'name': 'ESME_RINVESMCLASS', 'description': 'Invalid esm_class field data'}, 'ESME_RCNTSUBDL' :{ 'hex': '00000044', 'name': 'ESME_RCNTSUBDL', 'description': 'Cannot submit to distribution list'}, 'ESME_RSUBMITFAIL' :{ 'hex': '00000045', 'name': 'ESME_RSUBMITFAIL', 'description': 'submit_sm or submit_multi failed'}, 'ESME_RINVSRCTON' :{ 'hex': '00000048', 'name': 'ESME_RINVSRCTON', 'description': 'Invalid source address TON'}, 'ESME_RINVSRCNPI' :{ 'hex': '00000049', 'name': 'ESME_RINVSRCNPI', 'description': 'Invalid source address NPI'}, 'ESME_RINVDSTTON' :{ 'hex': '00000050', 'name': 'ESME_RINVDSTTON', 'description': 'Invalid destination address TON'}, 'ESME_RINVDSTNPI' :{ 'hex': '00000051', 'name': 'ESME_RINVDSTNPI', 'description': 'Invalid destination address NPI'}, 'ESME_RINVSYSTYP' :{ 'hex': '00000053', 'name': 'ESME_RINVSYSTYP', 'description': 'Invalid system_type field'}, 'ESME_RINVREPFLAG' :{ 'hex': '00000054', 'name': 'ESME_RINVREPFLAG', 'description': 'Invalid replace_if_present flag'}, 'ESME_RINVNUMMSGS' :{ 'hex': '00000055', 'name': 'ESME_RINVNUMMSGS', 'description': 'Invalid number of messages'}, 'ESME_RTHROTTLED' :{ 'hex': '00000058', 'name': 'ESME_RTHROTTLED', 'description': 'Throttling error (ESME has exceeded allowed message limits)'}, 'ESME_RINVSCHED' :{ 'hex': '00000061', 'name': 'ESME_RINVSCHED', 'description': 'Invalid scheduled delivery time'}, 'ESME_RINVEXPIRY' :{ 'hex': '00000062', 'name': 'ESME_RINVEXPIRY', 'description': 'Invalid message validity period (expiry time)'}, 'ESME_RINVDFTMSGID' :{ 'hex': '00000063', 'name': 'ESME_RINVDFTMSGID', 'description': 'Predefined message invalid or not found'}, 'ESME_RX_T_APPN' :{ 'hex': '00000064', 'name': 'ESME_RX_T_APPN', 'description': 'ESME Receiver Temporary App Error Code'}, 'ESME_RX_P_APPN' :{ 'hex': '00000065', 'name': 'ESME_RX_P_APPN', 'description': 'ESME Receiver Permanent App Error Code'}, 'ESME_RX_R_APPN' :{ 'hex': '00000066', 'name': 'ESME_RX_R_APPN', 'description': 'ESME Receiver Reject Message Error Code'}, 'ESME_RQUERYFAIL' :{ 'hex': '00000067', 'name': 'ESME_RQUERYFAIL', 'description': 'query_sm request failed'}, 'ESME_RINVOPTPARSTREAM': {'hex': '000000c0', 'name': 'ESME_RINVOPTPARSTREAM', 'description': 'Error in the optional part of the PDU Body'}, 'ESME_ROPTPARNOTALLWD' :{ 'hex': '000000c1', 'name': 'ESME_ROPTPARNOTALLWD', 'description': 'Optional paramenter not allowed'}, 'ESME_RINVPARLEN' :{ 'hex': '000000c2', 'name': 'ESME_RINVPARLEN', 'description': 'Invalid parameter length'}, 'ESME_RMISSINGOPTPARAM': {'hex': '000000c3', 'name': 'ESME_RMISSINGOPTPARAM', 'description': 'Expected optional parameter missing'}, 'ESME_RINVOPTPARAMVAL' :{ 'hex': '000000c4', 'name': 'ESME_RINVOPTPARAMVAL', 'description': 'Invalid optional parameter value'}, 'ESME_RDELIVERYFAILURE': {'hex': '000000fe', 'name': 'ESME_RDELIVERYFAILURE', 'description': 'Delivery Failure (used for data_sm_resp)'}, 'ESME_RUNKNOWNERR' :{ 'hex': '000000ff', 'name': 'ESME_RUNKNOWNERR', 'description': 'Unknown error'} } def command_status_hex_by_name(n): return command_status_by_name.get(n, {}).get('hex') # Type of Number (TON) - SMPP v3.4, section 5.2.5, table 5-3, page 117 maps['addr_ton_by_name'] = { 'unknown' : '00', 'international' : '01', 'national' : '02', 'network_specific' : '03', 'subscriber_number': '04', 'alphanumeric' : '05', 'abbreviated' : '06' } maps['addr_ton_by_hex'] = { '00': 'unknown', '01': 'international', '02': 'national', '03': 'network_specific', '04': 'subscriber_number', '05': 'alphanumeric', '06': 'abbreviated' } # Numberic Plan Indicator (NPI) - SMPP v3.4, section 5.2.6, table 5-4, page 118 maps['addr_npi_by_name'] = { 'unknown' : '00', 'ISDN' : '01', 'data' : '03', 'telex' : '04', 'land_mobile': '06', 'national' : '08', 'private' : '09', 'ERMES' : '0a', 'internet' : '0e', 'WAP' : '12' } maps['addr_npi_by_hex'] = { '00': 'unknown', '01': 'ISDN', '03': 'data', '04': 'telex', '06': 'land_mobile', '08': 'national', '09': 'private', '0a': 'ERMES', '0e': 'internet', '12': 'WAP' } # ESM Class bits - SMPP v3.4, section 5.2.12, page 121 maps['esm_class_bits'] = { 'mode_mask' : '03', 'type_mask' : '3c', 'feature_mask' : 'c0', 'mode_default' : '00', 'mode_datagram' : '01', 'mode_forward' : '02', 'mode_store_and_forward' : '03', 'type_default' : '00', 'type_delivery_receipt' : '04', 'type_delivery_ack' : '08', 'type_0011' : '0a', 'type_user_ack' : '10', 'type_0101' : '14', 'type_conversation_abort' : '18', 'type_0111' : '1a', 'type_intermed_deliv_notif' : '20', 'type_1001' : '24', 'type_1010' : '28', 'type_1011' : '2a', 'type_1100' : '30', 'type_1101' : '34', 'type_1110' : '38', 'type_1111' : '3a', 'feature_none' : '00', 'feature_UDHI' : '40', 'feature_reply_path' : '80', 'feature_UDHI_and_reply_path': 'c0' } # Registered Delivery bits - SMPP v3.4, section 5.2.17, page 124 maps['registered_delivery_bits'] = { 'receipt_mask' : '03', 'ack_mask' : '0c', 'intermed_notif_mask' : '80', 'receipt_none' : '00', 'receipt_always' : '01', 'receipt_on_fail' : '02', 'receipt_res' : '03', 'ack_none' : '00', 'ack_delivery' : '04', 'ack_user' : '08', 'ack_delivery_and_user': '0c', 'intermed_notif_none' : '00', 'intermed_notif' : '10' } # submit_multi dest_flag constants - SMPP v3.4, section 5.2.25, page 129 # maps['dest_flag_by_name'] = { # 'SME Address' :1, # 'Distribution List Name': 2 # } # Message State codes returned in query_sm_resp PDUs - SMPP v3.4, section 5.2.28, table 5-6, page 130 maps['message_state_by_name'] = { 'ENROUTE' : 1, 'DELIVERED' : 2, 'EXPIRED' : 3, 'DELETED' : 4, 'UNDELIVERABLE': 5, 'ACCEPTED' : 6, 'UNKNOWN' : 7, 'REJECTED' : 8 } # Facility Code bits for SMPP v4 maps['facility_code_bits'] = { 'GF_PVCY' : '00000001', 'GF_SUBADDR': '00000002', 'NF_CC' : '00080000', 'NF_PDC' : '00010000', 'NF_IS136' : '00020000', 'NF_IS95A' : '00040000' } # Optional Parameter Tags - SMPP v3.4, section 5.3.2, Table 5-7, page 132-133 optional_parameter_tag_by_hex = { '0005': {'hex': '0005', 'name': 'dest_addr_subunit', 'type': 'integer', 'tech': 'GSM'}, # SMPP v3.4, section 5.3.2.1, page 134 '0006': {'hex': '0006', 'name': 'dest_network_type', 'type': 'integer', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.3, page 135 '0007': {'hex': '0007', 'name': 'dest_bearer_type', 'type': 'integer', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.5, page 136 '0008': {'hex': '0008', 'name': 'dest_telematics_id', 'type': 'integer', 'tech': 'GSM', 'min': 2}, # SMPP v3.4, section 5.3.2.7, page 137 '000d': {'hex': '000d', 'name': 'source_addr_subunit', 'type': 'integer', 'tech': 'GSM'}, # SMPP v3.4, section 5.3.2.2, page 134 '000e': {'hex': '000e', 'name': 'source_network_type', 'type': 'integer', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.4, page 135 '000f': {'hex': '000f', 'name': 'source_bearer_type', 'type': 'integer', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.6, page 136 '0010': {'hex': '0010', 'name': 'source_telematics_id', 'type': 'integer', 'tech': 'GSM'}, # SMPP v3.4, section 5.3.2.8, page 137 '0017': {'hex': '0017', 'name': 'qos_time_to_live', 'type': 'integer', 'tech': 'Generic', 'min': 4}, # SMPP v3.4, section 5.3.2.9, page 138 '0019': {'hex': '0019', 'name': 'payload_type', 'type': 'integer', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.10, page 138 '001d': {'hex': '001d', 'name': 'additional_status_info_text', 'type': 'string', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.11, page 139 '001e': {'hex': '001e', 'name': 'receipted_message_id', 'type': 'string', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.12, page 139 '0030': {'hex': '0030', 'name': 'ms_msg_wait_facilities', 'type': 'bitmask', 'tech': 'GSM'}, # SMPP v3.4, section 5.3.2.13, page 140 '0101': {'hex': '0101', 'name': 'PVCY_AuthenticationStr', 'type': None, 'tech': '? (J-Phone)'}, # v4 page 58-62 '0201': {'hex': '0201', 'name': 'privacy_indicator', 'type': 'integer', 'tech': 'CDMA, TDMA'}, # SMPP v3.4, section 5.3.2.14, page 141 '0202': {'hex': '0202', 'name': 'source_subaddress', 'type': 'hex', 'tech': 'CDMA, TDMA', 'min': 2}, # SMPP v3.4, section 5.3.2.15, page 142 '0203': {'hex': '0203', 'name': 'dest_subaddress', 'type': 'hex', 'tech': 'CDMA, TDMA', 'min': 2}, # SMPP v3.4, section 5.3.2.16, page 143 '0204': {'hex': '0204', 'name': 'user_message_reference', 'type': 'integer', 'tech': 'Generic', 'min': 2}, # SMPP v3.4, section 5.3.2.17, page 143 '0205': {'hex': '0205', 'name': 'user_response_code', 'type': 'integer', 'tech': 'CDMA, TDMA'}, # SMPP v3.4, section 5.3.2.18, page 144 '020a': {'hex': '020a', 'name': 'source_port', 'type': 'integer', 'tech': 'Generic', 'min': 2}, # SMPP v3.4, section 5.3.2.20, page 145 '020b': {'hex': '020b', 'name': 'destination_port', 'type': 'integer', 'tech': 'Generic', 'min': 2}, # SMPP v3.4, section 5.3.2.21, page 145 '020c': {'hex': '020c', 'name': 'sar_msg_ref_num', 'type': 'integer', 'tech': 'Generic', 'min': 2}, # SMPP v3.4, section 5.3.2.22, page 146 '020d': {'hex': '020d', 'name': 'language_indicator', 'type': 'integer', 'tech': 'CDMA, TDMA'}, # SMPP v3.4, section 5.3.2.19, page 144 '020e': {'hex': '020e', 'name': 'sar_total_segments', 'type': 'integer', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.23, page 147 '020f': {'hex': '020f', 'name': 'sar_segment_seqnum', 'type': 'integer', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.24, page 147 '0210': {'hex': '0210', 'name': 'sc_interface_version', 'type': 'integer', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.25, page 148 '0301': {'hex': '0301', 'name': 'CC_CBN', 'type': None, 'tech': 'V4'}, # v4 page 70 '0302': {'hex': '0302', 'name': 'callback_num_pres_ind', 'type': 'bitmask', 'tech': 'TDMA'}, # SMPP v3.4, section 5.3.2.37, page 156 '0303': {'hex': '0303', 'name': 'callback_num_atag', 'type': 'hex', 'tech': 'TDMA'}, # SMPP v3.4, section 5.3.2.38, page 157 '0304': {'hex': '0304', 'name': 'number_of_messages', 'type': 'integer', 'tech': 'CDMA'}, # SMPP v3.4, section 5.3.2.39, page 158 '0381': {'hex': '0381', 'name': 'callback_num', 'type': 'hex', 'tech': 'CDMA, TDMA, GSM, iDEN', 'min': 4}, # SMPP v3.4, section 5.3.2.36, page 155 '0420': {'hex': '0420', 'name': 'dpf_result', 'type': 'integer', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.28, page 149 '0421': {'hex': '0421', 'name': 'set_dpf', 'type': 'integer', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.29, page 150 '0422': {'hex': '0422', 'name': 'ms_availability_status', 'type': 'integer', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.30, page 151 '0423': {'hex': '0423', 'name': 'network_error_code', 'type': 'hex', 'tech': 'Generic', 'min': 3}, # SMPP v3.4, section 5.3.2.31, page 152 '0424': {'hex': '0424', 'name': 'message_payload', 'type': 'hex', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.32, page 153 '0425': {'hex': '0425', 'name': 'delivery_failure_reason', 'type': 'integer', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.33, page 153 '0426': {'hex': '0426', 'name': 'more_messages_to_send', 'type': 'integer', 'tech': 'GSM'}, # SMPP v3.4, section 5.3.2.34, page 154 '0427': {'hex': '0427', 'name': 'message_state', 'type': 'integer', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.35, page 154 '0428': {'hex': '0428', 'name': 'congestion_state', 'type': None, 'tech': 'Generic'}, '0501': {'hex': '0501', 'name': 'ussd_service_op', 'type': 'hex', 'tech': 'GSM (USSD)'}, # SMPP v3.4, section 5.3.2.44, page 161 '0600': {'hex': '0600', 'name': 'broadcast_channel_indicator', 'type': None, 'tech': 'GSM'}, '0601': {'hex': '0601', 'name': 'broadcast_content_type', 'type': None, 'tech': 'CDMA, TDMA, GSM'}, '0602': {'hex': '0602', 'name': 'broadcast_content_type_info', 'type': None, 'tech': 'CDMA, TDMA'}, '0603': {'hex': '0603', 'name': 'broadcast_message_class', 'type': None, 'tech': 'GSM'}, '0604': {'hex': '0604', 'name': 'broadcast_rep_num', 'type': None, 'tech': 'GSM'}, '0605': {'hex': '0605', 'name': 'broadcast_frequency_interval', 'type': None, 'tech': 'CDMA, TDMA, GSM'}, '0606': {'hex': '0606', 'name': 'broadcast_area_identifier', 'type': None, 'tech': 'CDMA, TDMA, GSM'}, '0607': {'hex': '0607', 'name': 'broadcast_error_status', 'type': None, 'tech': 'CDMA, TDMA, GSM'}, '0608': {'hex': '0608', 'name': 'broadcast_area_success', 'type': None, 'tech': 'GSM'}, '0609': {'hex': '0609', 'name': 'broadcast_end_time', 'type': None, 'tech': 'CDMA, TDMA, GSM'}, '060a': {'hex': '060a', 'name': 'broadcast_service_group', 'type': None, 'tech': 'CDMA, TDMA'}, '060b': {'hex': '060b', 'name': 'billing_identification', 'type': None, 'tech': 'Generic'}, '060d': {'hex': '060d', 'name': 'source_network_id', 'type': None, 'tech': 'Generic'}, '060e': {'hex': '060e', 'name': 'dest_network_id', 'type': None, 'tech': 'Generic'}, '060f': {'hex': '060f', 'name': 'source_node_id', 'type': None, 'tech': 'Generic'}, '0610': {'hex': '0610', 'name': 'dest_node_id', 'type': None, 'tech': 'Generic'}, '0611': {'hex': '0611', 'name': 'dest_addr_np_resolution', 'type': None, 'tech': 'CDMA, TDMA (US Only)'}, '0612': {'hex': '0612', 'name': 'dest_addr_np_information', 'type': None, 'tech': 'CDMA, TDMA (US Only)'}, '0613': {'hex': '0613', 'name': 'dest_addr_np_country', 'type': None, 'tech': 'CDMA, TDMA (US Only)'}, '1101': {'hex': '1101', 'name': 'PDC_MessageClass', 'type': None, 'tech': '? (J-Phone)'}, # v4 page 75 '1102': {'hex': '1102', 'name': 'PDC_PresentationOption', 'type': None, 'tech': '? (J-Phone)'}, # v4 page 76 '1103': {'hex': '1103', 'name': 'PDC_AlertMechanism', 'type': None, 'tech': '? (J-Phone)'}, # v4 page 76 '1104': {'hex': '1104', 'name': 'PDC_Teleservice', 'type': None, 'tech': '? (J-Phone)'}, # v4 page 77 '1105': {'hex': '1105', 'name': 'PDC_MultiPartMessage', 'type': None, 'tech': '? (J-Phone)'}, # v4 page 77 '1106': {'hex': '1106', 'name': 'PDC_PredefinedMsg', 'type': None, 'tech': '? (J-Phone)'}, # v4 page 78 '1201': {'hex': '1201', 'name': 'display_time', 'type': 'integer', 'tech': 'CDMA, TDMA'}, # SMPP v3.4, section 5.3.2.26, page 148 '1203': {'hex': '1203', 'name': 'sms_signal', 'type': 'integer', 'tech': 'TDMA', 'min': 2}, # SMPP v3.4, section 5.3.2.40, page 158 '1204': {'hex': '1204', 'name': 'ms_validity', 'type': 'integer', 'tech': 'CDMA, TDMA'}, # SMPP v3.4, section 5.3.2.27, page 149 '1304': {'hex': '1304', 'name': 'IS95A_AlertOnDelivery', 'type': None, 'tech': 'CDMA'}, # v4 page 85 '1306': {'hex': '1306', 'name': 'IS95A_LanguageIndicator', 'type': None, 'tech': 'CDMA'}, # v4 page 86 '130c': {'hex': '130c', 'name': 'alert_on_message_delivery', 'type': None, 'tech': 'CDMA'}, # SMPP v3.4, section 5.3.2.41, page 159 '1380': {'hex': '1380', 'name': 'its_reply_type', 'type': 'integer', 'tech': 'CDMA'}, # SMPP v3.4, section 5.3.2.42, page 159 '1383': {'hex': '1383', 'name': 'its_session_info', 'type': 'hex', 'tech': 'CDMA', 'min': 2}, # SMPP v3.4, section 5.3.2.43, page 160 '1402': {'hex': '1402', 'name': 'operator_id', 'type': None, 'tech': 'vendor extension'}, '1403': {'hex': '1403', 'name': 'tariff', 'type': None, 'tech': 'Mobile Network Code vendor extension'}, '1450': {'hex': '1450', 'name': 'mcc', 'type': None, 'tech': 'Mobile Country Code vendor extension'}, '1451': {'hex': '1451', 'name': 'mnc', 'type': None, 'tech': 'Mobile Network Code vendor extension'} } def optional_parameter_tag_name_by_hex(x): return optional_parameter_tag_by_hex.get(x, {}).get('name') def optional_parameter_tag_type_by_hex(x): return optional_parameter_tag_by_hex.get(x, {}).get('type') def optional_parameter_tag_min_by_hex(x): return optional_parameter_tag_by_hex.get(x, {}).get('min', 0) optional_parameter_tag_by_name = { 'dest_addr_subunit' :{ 'hex': '0005', 'name': 'dest_addr_subunit', 'type': 'integer', 'tech': 'GSM'}, # SMPP v3.4, section 5.3.2.1, page 134 'dest_network_type' :{ 'hex': '0006', 'name': 'dest_network_type', 'type': 'integer', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.3, page 135 'dest_bearer_type' :{ 'hex': '0007', 'name': 'dest_bearer_type', 'type': 'integer', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.5, page 136 'dest_telematics_id' :{ 'hex': '0008', 'name': 'dest_telematics_id', 'type': 'integer', 'tech': 'GSM'}, # SMPP v3.4, section 5.3.2.7, page 137 'source_addr_subunit' :{ 'hex': '000d', 'name': 'source_addr_subunit', 'type': 'integer', 'tech': 'GSM'}, # SMPP v3.4, section 5.3.2.2, page 134 'source_network_type' :{ 'hex': '000e', 'name': 'source_network_type', 'type': 'integer', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.4, page 135 'source_bearer_type' :{ 'hex': '000f', 'name': 'source_bearer_type', 'type': 'integer', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.6, page 136 'source_telematics_id' :{ 'hex': '0010', 'name': 'source_telematics_id', 'type': 'integer', 'tech': 'GSM'}, # SMPP v3.4, section 5.3.2.8, page 137 'qos_time_to_live' :{ 'hex': '0017', 'name': 'qos_time_to_live', 'type': 'integer', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.9, page 138 'payload_type' :{ 'hex': '0019', 'name': 'payload_type', 'type': 'integer', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.10, page 138 'additional_status_info_text' :{ 'hex': '001d', 'name': 'additional_status_info_text', 'type': 'string', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.11, page 139 'receipted_message_id' :{ 'hex': '001e', 'name': 'receipted_message_id', 'type': 'string', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.12, page 139 'ms_msg_wait_facilities' :{ 'hex': '0030', 'name': 'ms_msg_wait_facilities', 'type': 'bitmask', 'tech': 'GSM'}, # SMPP v3.4, section 5.3.2.13, page 140 'PVCY_AuthenticationStr' :{ 'hex': '0101', 'name': 'PVCY_AuthenticationStr', 'type': None, 'tech': '? (J-Phone)'}, # v4 page 58-62 'privacy_indicator' :{ 'hex': '0201', 'name': 'privacy_indicator', 'type': 'integer', 'tech': 'CDMA, TDMA'}, # SMPP v3.4, section 5.3.2.14, page 141 'source_subaddress' :{ 'hex': '0202', 'name': 'source_subaddress', 'type': 'hex', 'tech': 'CDMA, TDMA'}, # SMPP v3.4, section 5.3.2.15, page 142 'dest_subaddress' :{ 'hex': '0203', 'name': 'dest_subaddress', 'type': 'hex', 'tech': 'CDMA, TDMA'}, # SMPP v3.4, section 5.3.2.16, page 143 'user_message_reference' :{ 'hex': '0204', 'name': 'user_message_reference', 'type': 'integer', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.17, page 143 'user_response_code' :{ 'hex': '0205', 'name': 'user_response_code', 'type': 'integer', 'tech': 'CDMA, TDMA'}, # SMPP v3.4, section 5.3.2.18, page 144 'source_port' :{ 'hex': '020a', 'name': 'source_port', 'type': 'integer', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.20, page 145 'destination_port' :{ 'hex': '020b', 'name': 'destination_port', 'type': 'integer', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.21, page 145 'sar_msg_ref_num' :{ 'hex': '020c', 'name': 'sar_msg_ref_num', 'type': 'integer', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.22, page 146 'language_indicator' :{ 'hex': '020d', 'name': 'language_indicator', 'type': 'integer', 'tech': 'CDMA, TDMA'}, # SMPP v3.4, section 5.3.2.19, page 144 'sar_total_segments' :{ 'hex': '020e', 'name': 'sar_total_segments', 'type': 'integer', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.23, page 147 'sar_segment_seqnum' :{ 'hex': '020f', 'name': 'sar_segment_seqnum', 'type': 'integer', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.24, page 147 'sc_interface_version' :{ 'hex': '0210', 'name': 'sc_interface_version', 'type': 'integer', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.25, page 148 'CC_CBN' :{ 'hex': '0301', 'name': 'CC_CBN', 'type': None, 'tech': 'V4'}, # v4 page 70 'callback_num_pres_ind' :{ 'hex': '0302', 'name': 'callback_num_pres_ind', 'type': 'bitmask', 'tech': 'TDMA'}, # SMPP v3.4, section 5.3.2.37, page 156 'callback_num_atag' :{ 'hex': '0303', 'name': 'callback_num_atag', 'type': 'hex', 'tech': 'TDMA'}, # SMPP v3.4, section 5.3.2.38, page 157 'number_of_messages' :{ 'hex': '0304', 'name': 'number_of_messages', 'type': 'integer', 'tech': 'CDMA'}, # SMPP v3.4, section 5.3.2.39, page 158 'callback_num' :{ 'hex': '0381', 'name': 'callback_num', 'type': 'hex', 'tech': 'CDMA, TDMA, GSM, iDEN'}, # SMPP v3.4, section 5.3.2.36, page 155 'dpf_result' :{ 'hex': '0420', 'name': 'dpf_result', 'type': 'integer', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.28, page 149 'set_dpf' :{ 'hex': '0421', 'name': 'set_dpf', 'type': 'integer', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.29, page 150 'ms_availability_status' :{ 'hex': '0422', 'name': 'ms_availability_status', 'type': 'integer', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.30, page 151 'network_error_code' :{ 'hex': '0423', 'name': 'network_error_code', 'type': 'hex', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.31, page 152 'message_payload' :{ 'hex': '0424', 'name': 'message_payload', 'type': 'hex', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.32, page 153 'delivery_failure_reason' :{ 'hex': '0425', 'name': 'delivery_failure_reason', 'type': 'integer', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.33, page 153 'more_messages_to_send' :{ 'hex': '0426', 'name': 'more_messages_to_send', 'type': 'integer', 'tech': 'GSM'}, # SMPP v3.4, section 5.3.2.34, page 154 'message_state' :{ 'hex': '0427', 'name': 'message_state', 'type': 'integer', 'tech': 'Generic'}, # SMPP v3.4, section 5.3.2.35, page 154 'congestion_state' :{ 'hex': '0428', 'name': 'congestion_state', 'type': None, 'tech': 'Generic'}, 'ussd_service_op' :{ 'hex': '0501', 'name': 'ussd_service_op', 'type': 'hex', 'tech': 'GSM (USSD)'}, # SMPP v3.4, section 5.3.2.44, page 161 'broadcast_channel_indicator' :{ 'hex': '0600', 'name': 'broadcast_channel_indicator', 'type': None, 'tech': 'GSM'}, 'broadcast_content_type' :{ 'hex': '0601', 'name': 'broadcast_content_type', 'type': None, 'tech': 'CDMA, TDMA, GSM'}, 'broadcast_content_type_info' :{ 'hex': '0602', 'name': 'broadcast_content_type_info', 'type': None, 'tech': 'CDMA, TDMA'}, 'broadcast_message_class' :{ 'hex': '0603', 'name': 'broadcast_message_class', 'type': None, 'tech': 'GSM'}, 'broadcast_rep_num' :{ 'hex': '0604', 'name': 'broadcast_rep_num', 'type': None, 'tech': 'GSM'}, 'broadcast_frequency_interval': {'hex': '0605', 'name': 'broadcast_frequency_interval', 'type': None, 'tech': 'CDMA, TDMA, GSM'}, 'broadcast_area_identifier' :{ 'hex': '0606', 'name': 'broadcast_area_identifier', 'type': None, 'tech': 'CDMA, TDMA, GSM'}, 'broadcast_error_status' :{ 'hex': '0607', 'name': 'broadcast_error_status', 'type': None, 'tech': 'CDMA, TDMA, GSM'}, 'broadcast_area_success' :{ 'hex': '0608', 'name': 'broadcast_area_success', 'type': None, 'tech': 'GSM'}, 'broadcast_end_time' :{ 'hex': '0609', 'name': 'broadcast_end_time', 'type': None, 'tech': 'CDMA, TDMA, GSM'}, 'broadcast_service_group' :{ 'hex': '060a', 'name': 'broadcast_service_group', 'type': None, 'tech': 'CDMA, TDMA'}, 'billing_identification' :{ 'hex': '060b', 'name': 'billing_identification', 'type': None, 'tech': 'Generic'}, 'source_network_id' :{ 'hex': '060d', 'name': 'source_network_id', 'type': None, 'tech': 'Generic'}, 'dest_network_id' :{ 'hex': '060e', 'name': 'dest_network_id', 'type': None, 'tech': 'Generic'}, 'source_node_id' :{ 'hex': '060f', 'name': 'source_node_id', 'type': None, 'tech': 'Generic'}, 'dest_node_id' :{ 'hex': '0610', 'name': 'dest_node_id', 'type': None, 'tech': 'Generic'}, 'dest_addr_np_resolution' :{ 'hex': '0611', 'name': 'dest_addr_np_resolution', 'type': None, 'tech': 'CDMA, TDMA (US Only)'}, 'dest_addr_np_information' :{ 'hex': '0612', 'name': 'dest_addr_np_information', 'type': None, 'tech': 'CDMA, TDMA (US Only)'}, 'dest_addr_np_country' :{ 'hex': '0613', 'name': 'dest_addr_np_country', 'type': None, 'tech': 'CDMA, TDMA (US Only)'}, 'PDC_MessageClass' :{ 'hex': '1101', 'name': 'PDC_MessageClass', 'type': None, 'tech': '? (J-Phone)'}, # v4 page 75 'PDC_PresentationOption' :{ 'hex': '1102', 'name': 'PDC_PresentationOption', 'type': None, 'tech': '? (J-Phone)'}, # v4 page 76 'PDC_AlertMechanism' :{ 'hex': '1103', 'name': 'PDC_AlertMechanism', 'type': None, 'tech': '? (J-Phone)'}, # v4 page 76 'PDC_Teleservice' :{ 'hex': '1104', 'name': 'PDC_Teleservice', 'type': None, 'tech': '? (J-Phone)'}, # v4 page 77 'PDC_MultiPartMessage' :{ 'hex': '1105', 'name': 'PDC_MultiPartMessage', 'type': None, 'tech': '? (J-Phone)'}, # v4 page 77 'PDC_PredefinedMsg' :{ 'hex': '1106', 'name': 'PDC_PredefinedMsg', 'type': None, 'tech': '? (J-Phone)'}, # v4 page 78 'display_time' :{ 'hex': '1201', 'name': 'display_time', 'type': 'integer', 'tech': 'CDMA, TDMA'}, # SMPP v3.4, section 5.3.2.26, page 148 'sms_signal' :{ 'hex': '1203', 'name': 'sms_signal', 'type': 'integer', 'tech': 'TDMA'}, # SMPP v3.4, section 5.3.2.40, page 158 'ms_validity' :{ 'hex': '1204', 'name': 'ms_validity', 'type': 'integer', 'tech': 'CDMA, TDMA'}, # SMPP v3.4, section 5.3.2.27, page 149 'IS95A_AlertOnDelivery' :{ 'hex': '1304', 'name': 'IS95A_AlertOnDelivery', 'type': None, 'tech': 'CDMA'}, # v4 page 85 'IS95A_LanguageIndicator' :{ 'hex': '1306', 'name': 'IS95A_LanguageIndicator', 'type': None, 'tech': 'CDMA'}, # v4 page 86 'alert_on_message_delivery' :{ 'hex': '130c', 'name': 'alert_on_message_delivery', 'type': None, 'tech': 'CDMA'}, # SMPP v3.4, section 5.3.2.41, page 159 'its_reply_type' :{ 'hex': '1380', 'name': 'its_reply_type', 'type': 'integer', 'tech': 'CDMA'}, # SMPP v3.4, section 5.3.2.42, page 159 'its_session_info' :{ 'hex': '1383', 'name': 'its_session_info', 'type': 'hex', 'tech': 'CDMA'}, # SMPP v3.4, section 5.3.2.43, page 160 'operator_id' :{ 'hex': '1402', 'name': 'operator_id', 'type': None, 'tech': 'vendor extension'}, 'tariff' :{ 'hex': '1403', 'name': 'tariff', 'type': None, 'tech': 'Mobile Network Code vendor extension'}, 'mcc' :{ 'hex': '1450', 'name': 'mcc', 'type': None, 'tech': 'Mobile Country Code vendor extension'}, 'mnc' :{ 'hex': '1451', 'name': 'mnc', 'type': None, 'tech': 'Mobile Network Code vendor extension'} } def optional_parameter_tag_hex_by_name(n): return optional_parameter_tag_by_name.get(n, {}).get('hex') # Decoding functions ####################################################### def unpack_pdu(pdu_bin): return decode_pdu(binascii.b2a_hex(pdu_bin)) def decode_pdu(pdu_hex): hex_ref = [pdu_hex] pdu = {} pdu['header'] = decode_header(hex_ref) command = pdu['header'].get('command_id', None) if command is not None: body = decode_body(command, hex_ref) if len(body) > 0: pdu['body'] = body return pdu def decode_header(hex_ref): pdu_hex = hex_ref[0] header = {} (command_length, command_id, command_status, sequence_number, hex_ref[0]) = \ (pdu_hex[0:8], pdu_hex[8:16], pdu_hex[16:24], pdu_hex[24:32], pdu_hex[32:]) length = int(command_length, 16) command = command_id_name_by_hex(command_id) status = command_status_name_by_hex(command_status) sequence = int(sequence_number, 16) header = {} header['command_length'] = length header['command_id'] = command header['command_status'] = status header['sequence_number'] = sequence return header def decode_body(command, hex_ref): body = {} if command is not None: fields = mandatory_parameter_list_by_command_name(command) mandatory = decode_mandatory_parameters(fields, hex_ref) if len(mandatory) > 0: body['mandatory_parameters'] = mandatory optional = decode_optional_parameters(hex_ref) if len(optional) > 0: body['optional_parameters'] = optional return body def decode_mandatory_parameters(fields, hex_ref): mandatory_parameters = {} if len(hex_ref[0]) > 1: for field in fields: # old = len(hex_ref[0]) data = '' octet = '' count = 0 if field['var'] is True or field['var'] is False: while (len(hex_ref[0]) > 1 and (count < field['min'] or (field['var'] is True and count < field['max']+1 and octet != '00'))): octet = octpop(hex_ref) data += octet count += 1 elif field['type'] in ['string', 'xstring']: count = mandatory_parameters[field['var']] if count == 0: data = None else: for i in range(count): if len(hex_ref[0]) > 1: data += octpop(hex_ref) else: count = mandatory_parameters[field['var']] if field['map'] is not None: mandatory_parameters[field['name']] = maps[field['map']+'_by_hex'].get(data, None) if field['map'] is None or mandatory_parameters[field['name']] is None: mandatory_parameters[field['name']] = decode_hex_type(data, field['type'], count, hex_ref) # print field['type'], (old - len(hex_ref[0]))/2, repr(data), field['name'], mandatory_parameters[field['name']] return mandatory_parameters def decode_optional_parameters(hex_ref): optional_parameters = [] hex = hex_ref[0] while len(hex) > 0: if len(hex) < 8: # We don't have enough data here for this to be a valid param. # TODO: Something better than `print` here. print "Invalid optional param data, ignoring: %s" % (hex,) break (tag_hex, length_hex, rest) = (hex[0:4], hex[4:8], hex[8:]) tag = optional_parameter_tag_name_by_hex(tag_hex) if tag is None: tag = tag_hex length = int(length_hex, 16) (value_hex, tail) = (rest[0:length*2], rest[length*2:]) if len(value_hex) == 0: value = None else: value = decode_hex_type(value_hex, optional_parameter_tag_type_by_hex(tag_hex)) hex = tail optional_parameters.append({'tag': tag, 'length': length, 'value': value}) return optional_parameters def decode_hex_type(hex, type, count=0, hex_ref=['']): if hex is None: return hex elif type == 'integer': return int(hex, 16) elif type == 'string': return re.sub('00', '', hex).decode('hex') elif type == 'xstring': return hex.decode('hex') elif (type == 'dest_address' or type == 'unsuccess_sme'): list = [] fields = mandatory_parameter_list_by_command_name(type) for i in range(count): item = decode_mandatory_parameters(fields, hex_ref) if item.get('dest_flag', None) == 1: # 'dest_address' only subfields = mandatory_parameter_list_by_command_name('sme_dest_address') rest = decode_mandatory_parameters(subfields, hex_ref) item.update(rest) elif item.get('dest_flag', None) == 2: # 'dest_address' only subfields = mandatory_parameter_list_by_command_name('distribution_list') rest = decode_mandatory_parameters(subfields, hex_ref) item.update(rest) list.append(item) return list else: return hex def octpop(hex_ref): octet = None if len(hex_ref[0]) > 1: (octet, hex_ref[0]) = (hex_ref[0][0:2], hex_ref[0][2:]) return octet # Encoding functions def pack_pdu(pdu_obj): return binascii.a2b_hex(encode_pdu(pdu_obj)) def encode_pdu(pdu_obj): header = pdu_obj.get('header', {}) body = pdu_obj.get('body', {}) mandatory = body.get('mandatory_parameters', {}) optional = body.get('optional_parameters', []) body_hex = '' fields = mandatory_parameter_list_by_command_name(header['command_id']) body_hex += encode_mandatory_parameters(mandatory, fields) for opt in optional: body_hex += encode_optional_parameter(opt['tag'], opt['value']) actual_length = 16 + len(body_hex)/2 command_length = '%08x' % actual_length command_id = command_id_hex_by_name(header['command_id']) command_status = command_status_hex_by_name(header['command_status']) sequence_number = '%08x' % header['sequence_number'] pdu_hex = command_length + command_id + command_status + sequence_number + body_hex return pdu_hex def encode_mandatory_parameters(mandatory_obj, fields): mandatory_hex_array = [] index_names = {} index = 0 for field in fields: param = mandatory_obj.get(field['name'], None) param_length = None if param is not None or field['min'] > 0: map = None if field['map'] is not None: map = maps.get(field['map']+'_by_name', None) if isinstance(param, list): hex_list = [] for item in param: flagfields = mandatory_parameter_list_by_command_name(field['type']) plusfields = [] if item.get('dest_flag', None) == 1: plusfields = mandatory_parameter_list_by_command_name('sme_dest_address') elif item.get('dest_flag', None) == 2: plusfields = mandatory_parameter_list_by_command_name('distribution_list') hex_item = encode_mandatory_parameters(item, flagfields + plusfields) if isinstance(hex_item, str) and len(hex_item) > 0: hex_list.append(hex_item) param_length = len(hex_list) mandatory_hex_array.append(''.join(hex_list)) else: hex_param = encode_param_type( param, field['type'], field['min'], field['max'], map) param_length = len(hex_param)/2 mandatory_hex_array.append(hex_param) index_names[field['name']] = index length_index = index_names.get(field['var'], None) if length_index is not None and param_length is not None: mandatory_hex_array[length_index] = encode_param_type( param_length, 'integer', len(mandatory_hex_array[length_index])/2) index += 1 return ''.join(mandatory_hex_array) def encode_optional_parameter(tag, value): optional_hex_array = [] tag_hex = optional_parameter_tag_hex_by_name(tag) if tag_hex is not None: value_hex = encode_param_type( value, optional_parameter_tag_type_by_hex(tag_hex), optional_parameter_tag_min_by_hex(tag_hex), ) length_hex = '%04x' % (len(value_hex)/2) optional_hex_array.append(tag_hex + length_hex + value_hex) return ''.join(optional_hex_array) def encode_param_type(param, type, min=0, max=None, map=None): if param is None: hex = None elif map is not None: if type == 'integer' and isinstance(param, int): hex = ('%0'+str(min*2)+'x') % param else: hex = map.get(param, ('%0'+str(min*2)+'x') % 0) elif type == 'integer': hex = ('%0'+str(min*2)+'x') % int(param) elif type == 'string': hex = param.encode('hex') + '00' elif type == 'xstring': hex = param.encode('hex') elif type == 'bitmask': hex = param elif type == 'hex': hex = param else: hex = None if hex: if len(hex) % 2: # pad odd length hex strings hex = '0' + hex if None not in (max, hex) and len(hex) > 2 * max: raise ValueError("Value exceeds maximum size of %s." % (max,)) return hex PKb?xHJ++smpp/pdu_builder.pyfrom pdu import * class PDU(object): def __init__(self, command_id, command_status, sequence_number, **kwargs): super(PDU, self).__init__() self.obj = {} self.obj['header'] = {} self.obj['header']['command_length'] = 0 self.obj['header']['command_id'] = command_id self.obj['header']['command_status'] = command_status self.obj['header']['sequence_number'] = sequence_number def add_optional_parameter(self, tag, value): if self.obj.get('body') is None: self.obj['body'] = {} if self.obj['body'].get('optional_parameters') is None: self.obj['body']['optional_parameters'] = [] self.obj['body']['optional_parameters'].append({ 'tag': tag, 'length': 0, 'value': value, }) def __add_optional_parameter(self, tag, value): # This is deprecated, but not everything has been updated yet. return self.add_optional_parameter(tag, value) def set_sar_msg_ref_num(self, value): self.add_optional_parameter('sar_msg_ref_num', value) def set_sar_segment_seqnum(self, value): self.add_optional_parameter('sar_segment_seqnum', value) def set_sar_total_segments(self, value): self.add_optional_parameter('sar_total_segments', value) def get_obj(self): return self.obj def get_hex(self): return encode_pdu(self.obj) def get_bin(self): return pack_pdu(self.obj) class Bind(PDU): def __init__(self, command_id, sequence_number, system_id='', password='', system_type='', interface_version='34', addr_ton=0, addr_npi=0, address_range='', **kwargs): super(Bind, self).__init__(command_id, 'ESME_ROK', sequence_number) self.obj['body'] = {} self.obj['body']['mandatory_parameters'] = {} self.obj['body']['mandatory_parameters']['system_id'] = system_id self.obj['body']['mandatory_parameters']['password'] = password self.obj['body']['mandatory_parameters']['system_type'] = system_type self.obj['body']['mandatory_parameters']['interface_version'] = interface_version self.obj['body']['mandatory_parameters']['addr_ton'] = addr_ton self.obj['body']['mandatory_parameters']['addr_npi'] = addr_npi self.obj['body']['mandatory_parameters']['address_range'] = address_range class BindTransmitter(Bind): def __init__(self, sequence_number, **kwargs): super(BindTransmitter, self).__init__('bind_transmitter', sequence_number, **kwargs) class BindReceiver(Bind): def __init__(self, sequence_number, **kwargs): super(BindReceiver, self).__init__('bind_receiver', sequence_number, **kwargs) class BindTransceiver(Bind): def __init__(self, sequence_number, **kwargs): super(BindTransceiver, self).__init__('bind_transceiver', sequence_number, **kwargs) class BindResp(PDU): def __init__(self, command_id, command_status, sequence_number, system_id='', **kwargs): super(BindResp, self).__init__(command_id, command_status, sequence_number) self.obj['body'] = {} self.obj['body']['mandatory_parameters'] = {} self.obj['body']['mandatory_parameters']['system_id'] = system_id class BindTransmitterResp(BindResp): def __init__(self, sequence_number, command_status="ESME_ROK", **kwargs): super(BindTransmitterResp, self).__init__('bind_transmitter_resp', command_status, sequence_number, **kwargs) class BindReceiverResp(BindResp): def __init__(self, sequence_number, command_status="ESME_ROK", **kwargs): super(BindReceiverResp, self).__init__('bind_receiver_resp', command_status, sequence_number, **kwargs) class BindTransceiverResp(BindResp): def __init__(self, sequence_number, command_status="ESME_ROK", **kwargs): super(BindTransceiverResp, self).__init__('bind_transceiver_resp', command_status, sequence_number, **kwargs) class Unbind(PDU): def __init__(self, sequence_number, **kwargs): super(Unbind, self).__init__('unbind', 'ESME_ROK', sequence_number, **kwargs) class UnbindResp(PDU): def __init__(self, sequence_number, **kwargs): super(UnbindResp, self).__init__('unbind_resp', 'ESME_ROK', sequence_number, **kwargs) class SM1(PDU): def __init__(self, command_id, sequence_number, service_type='', source_addr_ton=0, source_addr_npi=0, source_addr='', esm_class=0, protocol_id=0, priority_flag=0, schedule_delivery_time='', validity_period='', registered_delivery=0, replace_if_present_flag=0, data_coding=0, sm_default_msg_id=0, sm_length=0, short_message=None, **kwargs): super(SM1, self).__init__(command_id, 'ESME_ROK', sequence_number) self.obj['body'] = {} self.obj['body']['mandatory_parameters'] = {} self.obj['body']['mandatory_parameters']['service_type'] = service_type self.obj['body']['mandatory_parameters']['source_addr_ton'] = source_addr_ton self.obj['body']['mandatory_parameters']['source_addr_npi'] = source_addr_npi self.obj['body']['mandatory_parameters']['source_addr'] = source_addr self.obj['body']['mandatory_parameters']['esm_class'] = esm_class self.obj['body']['mandatory_parameters']['protocol_id'] = protocol_id self.obj['body']['mandatory_parameters']['priority_flag'] = priority_flag self.obj['body']['mandatory_parameters']['schedule_delivery_time'] = schedule_delivery_time self.obj['body']['mandatory_parameters']['validity_period'] = validity_period self.obj['body']['mandatory_parameters']['registered_delivery'] = registered_delivery self.obj['body']['mandatory_parameters']['replace_if_present_flag'] = replace_if_present_flag self.obj['body']['mandatory_parameters']['data_coding'] = data_coding self.obj['body']['mandatory_parameters']['sm_default_msg_id'] = sm_default_msg_id self.obj['body']['mandatory_parameters']['sm_length'] = sm_length self.obj['body']['mandatory_parameters']['short_message'] = short_message def add_message_payload(self, value): self.obj['body']['mandatory_parameters']['sm_length'] = 0 self.obj['body']['mandatory_parameters']['short_message'] = None self.add_optional_parameter('message_payload', value) class SubmitMulti(SM1): def __init__(self, sequence_number, number_of_dests=0, dest_address=[], **kwargs): super(SubmitMulti, self).__init__('submit_multi', sequence_number, **kwargs) mandatory_parameters = self.obj['body']['mandatory_parameters'] mandatory_parameters['number_of_dests'] = number_of_dests mandatory_parameters['dest_address'] = [] + dest_address def addDestinationAddress(self, destination_addr, dest_addr_ton=0, dest_addr_npi=0): if isinstance(destination_addr, str) and len(destination_addr) > 0: new_entry = { 'dest_flag': 1, 'dest_addr_ton': dest_addr_ton, 'dest_addr_npi': dest_addr_npi, 'destination_addr': destination_addr, } mandatory_parameters = self.obj['body']['mandatory_parameters'] mandatory_parameters['dest_address'].append(new_entry) mandatory_parameters['number_of_dests'] = len( mandatory_parameters['dest_address']) return True else: return False def addDistributionList(self, dl_name): if isinstance(dl_name, str) and len(dl_name) > 0: new_entry = { 'dest_flag': 2, 'dl_name': dl_name, } mandatory_parameters = self.obj['body']['mandatory_parameters'] mandatory_parameters['dest_address'].append(new_entry) mandatory_parameters['number_of_dests'] = len( mandatory_parameters['dest_address']) return True else: return False class SM2(SM1): def __init__(self, command_id, sequence_number, dest_addr_ton=0, dest_addr_npi=0, destination_addr='', **kwargs): super(SM2, self).__init__(command_id, sequence_number, **kwargs) mandatory_parameters = self.obj['body']['mandatory_parameters'] mandatory_parameters['dest_addr_ton'] = dest_addr_ton mandatory_parameters['dest_addr_npi'] = dest_addr_npi mandatory_parameters['destination_addr'] = destination_addr class SubmitSM(SM2): def __init__(self, sequence_number, **kwargs): super(SubmitSM, self).__init__('submit_sm', sequence_number, **kwargs) class SubmitSMResp(PDU): def __init__(self, sequence_number, message_id, command_status='ESME_ROK', **kwargs): super(SubmitSMResp, self).__init__('submit_sm_resp', command_status, sequence_number, **kwargs) self.obj['body'] = {} self.obj['body']['mandatory_parameters'] = {} self.obj['body']['mandatory_parameters']['message_id'] = message_id class DeliverSM(SM2): def __init__(self, sequence_number, **kwargs): super(DeliverSM, self).__init__('deliver_sm', sequence_number, **kwargs) class DeliverSMResp(PDU): def __init__(self, sequence_number, message_id='', command_status='ESME_ROK', **kwargs): super(DeliverSMResp, self).__init__('deliver_sm_resp', command_status, sequence_number, **kwargs) self.obj['body'] = {} self.obj['body']['mandatory_parameters'] = {} self.obj['body']['mandatory_parameters']['message_id'] = '' class EnquireLink(PDU): def __init__(self, sequence_number, **kwargs): super(EnquireLink, self).__init__('enquire_link', 'ESME_ROK', sequence_number, **kwargs) class EnquireLinkResp(PDU): def __init__(self, sequence_number, **kwargs): super(EnquireLinkResp, self).__init__('enquire_link_resp', 'ESME_ROK', sequence_number, **kwargs) class QuerySM(PDU): def __init__(self, sequence_number, message_id, source_addr='', source_addr_ton=0, source_addr_npi=0, **kwargs): super(QuerySM, self).__init__('query_sm', 'ESME_ROK', sequence_number, **kwargs) self.obj['body'] = {} self.obj['body']['mandatory_parameters'] = {} self.obj['body']['mandatory_parameters']['message_id'] = message_id self.obj['body']['mandatory_parameters']['source_addr'] = source_addr self.obj['body']['mandatory_parameters']['source_addr_ton'] = source_addr_ton self.obj['body']['mandatory_parameters']['source_addr_npi'] = source_addr_npi # bind = BindTransmitter(system_id='test_id', password='abc123') # print bind.get_obj() # print bind.get_hex() # print bind.get_bin() # #print json.dumps(bind.get_obj(), indent=4, sort_keys=True) # #print json.dumps(decode_pdu(bind.get_hex()), indent=4, sort_keys=True) # print json.dumps(unpack_pdu(bind.get_bin()), indent=4, sort_keys=True) # sm = SubmitSM(short_message='testing testing') # print json.dumps(unpack_pdu(sm.get_bin()), indent=4, sort_keys=True) # sm.add_message_payload('616263646566676869') # print json.dumps(unpack_pdu(sm.get_bin()), indent=4, sort_keys=True) PKb?xH /9/9test/pdu_asserts.py ######################################## pdu_json_0000000001 = '''{ "body": { "mandatory_parameters": { "addr_npi": "ISDN", "addr_ton": "international", "address_range": "", "interface_version": "34", "password": "abc123", "system_id": "test_system", "system_type": "" } }, "header": { "command_id": "bind_transmitter", "command_length": 40, "command_status": "ESME_ROK", "sequence_number": 0 } }''' ######################################## pdu_json_0000000002 = '''{ "body": { "mandatory_parameters": { "system_id": "test_system" } }, "header": { "command_id": "bind_transmitter_resp", "command_length": 28, "command_status": "ESME_ROK", "sequence_number": 0 } }''' ######################################## pdu_json_0000000003 = '''{ "body": { "mandatory_parameters": { "addr_npi": "ISDN", "addr_ton": "international", "address_range": "", "interface_version": "34", "password": "abc123", "system_id": "test_system", "system_type": "" } }, "header": { "command_id": "bind_receiver", "command_length": 40, "command_status": "ESME_ROK", "sequence_number": 0 } }''' ######################################## pdu_json_0000000004 = '''{ "body": { "mandatory_parameters": { "system_id": "test_system" } }, "header": { "command_id": "bind_receiver_resp", "command_length": 28, "command_status": "ESME_ROK", "sequence_number": 0 } }''' ######################################## pdu_json_0000000005 = '''{ "body": { "mandatory_parameters": { "addr_npi": "ISDN", "addr_ton": "international", "address_range": "", "interface_version": "34", "password": "abc123", "system_id": "test_system", "system_type": "" } }, "header": { "command_id": "bind_transceiver", "command_length": 40, "command_status": "ESME_ROK", "sequence_number": 0 } }''' ######################################## pdu_json_0000000006 = '''{ "body": { "mandatory_parameters": { "system_id": "test_system" } }, "header": { "command_id": "bind_transceiver_resp", "command_length": 28, "command_status": "ESME_ROK", "sequence_number": 0 } }''' ######################################## pdu_json_0000000007 = '''{ "body": { "mandatory_parameters": { "password": "abc123", "system_id": "test_system" } }, "header": { "command_id": "outbind", "command_length": 35, "command_status": "ESME_ROK", "sequence_number": 0 } }''' ######################################## pdu_json_0000000008 = '''{ "header": { "command_id": "unbind", "command_length": 16, "command_status": "ESME_ROK", "sequence_number": 0 } }''' ######################################## pdu_json_0000000009 = '''{ "header": { "command_id": "unbind_resp", "command_length": 16, "command_status": "ESME_ROK", "sequence_number": 0 } }''' ######################################## pdu_json_0000000010 = '''{ "header": { "command_id": "generic_nack", "command_length": 16, "command_status": "ESME_ROK", "sequence_number": 0 } }''' ######################################## pdu_json_0000000011 = '''{ "body": { "mandatory_parameters": { "data_coding": 0, "dest_addr_npi": "ISDN", "dest_addr_ton": "international", "destination_addr": "", "esm_class": 0, "priority_flag": 0, "protocol_id": 0, "registered_delivery": 0, "replace_if_present_flag": 0, "schedule_delivery_time": "", "service_type": "", "short_message": "testing 123", "sm_default_msg_id": 0, "sm_length": 11, "source_addr": "", "source_addr_npi": "ISDN", "source_addr_ton": "international", "validity_period": "" } }, "header": { "command_id": "submit_sm", "command_length": 44, "command_status": "ESME_ROK", "sequence_number": 0 } }''' ######################################## pdu_json_0000000012 = '''{ "body": { "mandatory_parameters": { "data_coding": 0, "dest_addr_npi": "ISDN", "dest_addr_ton": "international", "destination_addr": "", "esm_class": 0, "priority_flag": 0, "protocol_id": 0, "registered_delivery": 0, "replace_if_present_flag": 0, "schedule_delivery_time": "", "service_type": "", "short_message": null, "sm_default_msg_id": 0, "sm_length": 0, "source_addr": "", "source_addr_npi": "ISDN", "source_addr_ton": "international", "validity_period": "" }, "optional_parameters": [ { "length": 2, "tag": "message_payload", "value": "5666" } ] }, "header": { "command_id": "submit_sm", "command_length": 39, "command_status": "ESME_ROK", "sequence_number": 0 } }''' ######################################## pdu_json_0000000013 = '''{ "body": { "mandatory_parameters": { "message_id": "" } }, "header": { "command_id": "submit_sm_resp", "command_length": 17, "command_status": "ESME_ROK", "sequence_number": 0 } }''' ######################################## pdu_json_0000000014 = '''{ "header": { "command_id": "submit_sm_resp", "command_length": 16, "command_status": "ESME_RSYSERR", "sequence_number": 0 } }''' ######################################## pdu_json_0000000015 = '''{ "body": { "mandatory_parameters": { "data_coding": 0, "dest_address": [ { "dest_addr_npi": "ISDN", "dest_addr_ton": "international", "dest_flag": 1, "destination_addr": "the address" }, { "dest_flag": 2, "dl_name": "the list" }, { "dest_flag": 2, "dl_name": "the other list" } ], "esm_class": 0, "number_of_dests": 3, "priority_flag": 0, "protocol_id": 0, "registered_delivery": 0, "replace_if_present_flag": 0, "schedule_delivery_time": "", "service_type": "", "short_message": "testing 123", "sm_default_msg_id": 0, "sm_length": 11, "source_addr": "", "source_addr_npi": "ISDN", "source_addr_ton": "international", "validity_period": "" } }, "header": { "command_id": "submit_multi", "command_length": 83, "command_status": "ESME_ROK", "sequence_number": 0 } }''' ######################################## pdu_json_0000000016 = '''{ "body": { "mandatory_parameters": { "message_id": "", "no_unsuccess": 2, "unsuccess_sme": [ { "dest_addr_npi": "ISDN", "dest_addr_ton": "international", "destination_addr": "", "error_status_code": 0 }, { "dest_addr_npi": "ISDN", "dest_addr_ton": "network_specific", "destination_addr": "555", "error_status_code": 0 } ] } }, "header": { "command_id": "submit_multi_resp", "command_length": 35, "command_status": "ESME_ROK", "sequence_number": 0 } }''' ######################################## pdu_json_0000000017 = '''{ "body": { "mandatory_parameters": { "data_coding": 0, "dest_addr_npi": "ISDN", "dest_addr_ton": "international", "destination_addr": "", "esm_class": 0, "priority_flag": 0, "protocol_id": 0, "registered_delivery": 0, "replace_if_present_flag": 0, "schedule_delivery_time": "", "service_type": "", "short_message": null, "sm_default_msg_id": 0, "sm_length": 0, "source_addr": "", "source_addr_npi": "ISDN", "source_addr_ton": "international", "validity_period": "" } }, "header": { "command_id": "deliver_sm", "command_length": 33, "command_status": "ESME_ROK", "sequence_number": 0 } }''' ######################################## pdu_json_0000000018 = '''{ "body": { "mandatory_parameters": { "message_id": "" } }, "header": { "command_id": "deliver_sm_resp", "command_length": 17, "command_status": "ESME_ROK", "sequence_number": 0 } }''' ######################################## pdu_json_0000000019 = '''{ "body": { "mandatory_parameters": { "data_coding": 0, "dest_addr_npi": "ISDN", "dest_addr_ton": "international", "destination_addr": "", "esm_class": 0, "registered_delivery": 0, "service_type": "", "source_addr": "", "source_addr_npi": "ISDN", "source_addr_ton": "international" }, "optional_parameters": [ { "length": 0, "tag": "message_payload", "value": null } ] }, "header": { "command_id": "data_sm", "command_length": 30, "command_status": "ESME_ROK", "sequence_number": 0 } }''' ######################################## pdu_json_0000000020 = '''{ "body": { "mandatory_parameters": { "message_id": "" } }, "header": { "command_id": "data_sm_resp", "command_length": 17, "command_status": "ESME_ROK", "sequence_number": 0 } }''' ######################################## pdu_json_0000000021 = '''{ "body": { "mandatory_parameters": { "message_id": "", "source_addr": "", "source_addr_npi": "ISDN", "source_addr_ton": "international" } }, "header": { "command_id": "query_sm", "command_length": 20, "command_status": "ESME_ROK", "sequence_number": 0 } }''' ######################################## pdu_json_0000000022 = '''{ "body": { "mandatory_parameters": { "error_code": 0, "final_date": "", "message_id": "", "message_state": 0 } }, "header": { "command_id": "query_sm_resp", "command_length": 20, "command_status": "ESME_ROK", "sequence_number": 0 } }''' ######################################## pdu_json_0000000023 = '''{ "body": { "mandatory_parameters": { "dest_addr_npi": "ISDN", "dest_addr_ton": "international", "destination_addr": "", "message_id": "", "service_type": "", "source_addr": "", "source_addr_npi": "ISDN", "source_addr_ton": "international" } }, "header": { "command_id": "cancel_sm", "command_length": 24, "command_status": "ESME_ROK", "sequence_number": 0 } }''' ######################################## pdu_json_0000000024 = '''{ "header": { "command_id": "cancel_sm_resp", "command_length": 16, "command_status": "ESME_ROK", "sequence_number": 0 } }''' ######################################## pdu_json_0000000025 = '''{ "body": { "mandatory_parameters": { "data_coding": 0, "message_id": "", "registered_delivery": 0, "replace_if_present_flag": 0, "schedule_delivery_time": "", "short_message": "is this an = sign?", "sm_default_msg_id": 0, "sm_length": 18, "source_addr": "", "source_addr_npi": "ISDN", "source_addr_ton": "international", "validity_period": "" } }, "header": { "command_id": "replace_sm", "command_length": 45, "command_status": "ESME_ROK", "sequence_number": 0 } }''' ######################################## pdu_json_0000000026 = '''{ "header": { "command_id": "replace_sm_resp", "command_length": 16, "command_status": "ESME_ROK", "sequence_number": 0 } }''' ######################################## pdu_json_0000000027 = '''{ "header": { "command_id": "enquire_link", "command_length": 16, "command_status": "ESME_ROK", "sequence_number": 0 } }''' ######################################## pdu_json_0000000028 = '''{ "header": { "command_id": "enquire_link_resp", "command_length": 16, "command_status": "ESME_ROK", "sequence_number": 0 } }''' ######################################## pdu_json_0000000029 = '''{ "body": { "mandatory_parameters": { "esme_addr": "", "esme_addr_npi": "unknown", "esme_addr_ton": 9, "source_addr": "", "source_addr_npi": "ISDN", "source_addr_ton": "international" } }, "header": { "command_id": "alert_notification", "command_length": 22, "command_status": "ESME_ROK", "sequence_number": 0 } }''' PKb?xHE((test/test_multipart.py import unittest from smpp.pdu_builder import * from smpp.pdu_inspector import * class MultipartTestCase(unittest.TestCase): def setUp(self): pass def tearDown(self): pass def test_formats(self): """ Testing TLV vs SAR vs CSM vs CSM16 """ tlv = DeliverSM(1, short_message='the first message part') tlv.set_sar_msg_ref_num(65017) tlv.set_sar_total_segments(2) tlv.set_sar_segment_seqnum(1) sar = DeliverSM(1, short_message='\x00\x03\xff\x02\x01the first message part') csm = DeliverSM(1, short_message='\x05\x00\x03\xff\x02\x01the first message part') csm16 = DeliverSM(1, short_message='\x06\x00\x04\xff\xff\x02\x01the first message part') non_multi = DeliverSM(1, short_message='whatever') none_short_message = DeliverSM(1, short_message=None) self.assertEquals(detect_multipart(unpack_pdu(tlv.get_bin()))['multipart_type'], 'TLV') self.assertEquals(detect_multipart(unpack_pdu(sar.get_bin()))['multipart_type'], 'SAR') self.assertEquals(detect_multipart(unpack_pdu(csm.get_bin()))['multipart_type'], 'CSM') self.assertEquals(detect_multipart(unpack_pdu(csm16.get_bin()))['multipart_type'], 'CSM16') self.assertEquals(detect_multipart(unpack_pdu(none_short_message.get_bin())), None) def test_ordering(self): """ Out of order pieces must be re-assembled in-order """ sar_1 = DeliverSM(1, short_message='\x00\x03\xff\x04\x01There she was just a') sar_2 = DeliverSM(1, short_message='\x00\x03\xff\x04\x02 walking down the street,') sar_3 = DeliverSM(1, short_message='\x00\x03\xff\x04\x03 singing doo wa diddy') sar_4 = DeliverSM(1, short_message='\x00\x03\xff\x04\x04 diddy dum diddy do') multi = MultipartMessage() multi.add_pdu(sar_3.get_obj()) multi.add_pdu(sar_4.get_obj()) multi.add_pdu(sar_2.get_obj()) multi.add_pdu(sar_1.get_obj()) self.assertEquals(multi.get_completed()['message'], 'There she was just a walking down the street, singing doo wa diddy diddy dum diddy do') def test_real_csm_data(self): """ Test with real-world data which uses the CSM format. """ asif_1 = {'body': {'mandatory_parameters': {'priority_flag': 0, 'source_addr': '261xxx720371', 'protocol_id': 0, 'replace_if_present_flag': 0, 'registered_delivery': 0, 'dest_addr_ton': 'international', 'source_addr_npi': 'ISDN', 'schedule_delivery_time': '', 'dest_addr_npi': 'ISDN', 'sm_length': 159, 'esm_class': 64, 'data_coding': 0, 'service_type': '', 'source_addr_ton': 'international', 'sm_default_msg_id': 0, 'validity_period': '', 'destination_addr': '261xxx782943', 'short_message': '\x05\x00\x03\x1a\x02\x01I try to send sms testing vumi sms sms sms sms msm sms sms sms sms sms sms sms sms sms ssms sms smS sms sms sms sms sms sms sms sns sns sms sms sms sms s'}, 'optional_parameters': [{'length': 2, 'tag': 'user_message_reference', 'value': 91}, {'length': 16, 'tag': 'dest_subaddress', 'value': 'a0000410020601030303070802090403'}]}, 'header': {'command_status': 'ESME_ROK', 'command_length': 242, 'sequence_number': 23, 'command_id': 'deliver_sm'}} asif_2 = {'body': {'mandatory_parameters': {'priority_flag': 1, 'source_addr': '261xxx720371', 'protocol_id': 0, 'replace_if_present_flag': 0, 'registered_delivery': 0, 'dest_addr_ton': 'international', 'source_addr_npi': 'ISDN', 'schedule_delivery_time': '', 'dest_addr_npi': 'ISDN', 'sm_length': 78, 'esm_class': 64, 'data_coding': 0, 'service_type': '', 'source_addr_ton': 'international', 'sm_default_msg_id': 0, 'validity_period': '', 'destination_addr': '261xxx782943', 'short_message': '\x05\x00\x03\x1a\x02\x02mns again again again again again again again again sms sms sms sms sms '}, 'optional_parameters': [{'length': 2, 'tag': 'user_message_reference', 'value': 92}, {'length': 16, 'tag': 'dest_subaddress', 'value': 'a0000410020601030303070802090403'}]}, 'header': {'command_status': 'ESME_ROK', 'command_length': 161, 'sequence_number': 24, 'command_id': 'deliver_sm'}} multi = MultipartMessage() self.assertEquals(multi.get_partial(), {'to_msisdn': '', 'from_msisdn': '', 'message': ''}) self.assertEquals(multi.get_completed(), None) self.assertEquals(multi.get_key(), None) multi.add_pdu(asif_2) self.assertEquals(multi.get_partial(), {'to_msisdn': '261xxx782943', 'from_msisdn': '261xxx720371', 'message': 'mns again again again again again again again again sms sms sms sms sms '}) self.assertEquals(multi.get_completed(), None) self.assertEquals(multi.get_key(), '261xxx720371_261xxx782943_26_2') multi.add_pdu(asif_1) self.assertEquals(multi.get_completed()['message'], 'I try to send sms testing vumi sms sms sms sms msm sms sms sms sms sms sms sms sms sms ssms sms smS sms sms sms sms sms sms sms sns sns sms sms sms sms smns again again again again again again again again sms sms sms sms sms ') self.assertEquals(multi.get_key(), '261xxx720371_261xxx782943_26_2') PK;xHtest/__init__.pyPKb?xH^}  test/pdu_hex.py pdu_hex_strings = [ ''' 0000003C # command_length 00000004 # command_id 00000000 # command_status 00000005 # sequence_number 00 02 08 35353500 01 01 35353535353535353500 00 00 00 00 00 00 00 00 00 0F 48656C6C6F2077696B697065646961 00000000 001d00026566 ''', ''' 00000000 # command_length 00000021 # command_id 00000000 # command_status 00000000 # sequence_number 00 00 00 00 02 01 01 01 6500 02 6600 00 00 00 00 00 00 00 00 00 00 0005 0002 0000 0000 0004 00000000 ''', ''' 00000000 80000021 00000000 00000000 00 02 01016565650000000000 01016666660000000000 ''', ] PKb?xH)088 test/pdu.py pdu_objects = [ { 'header': { 'command_length': 0, 'command_id': 'bind_transmitter', 'command_status': 'ESME_ROK', 'sequence_number': 0, }, 'body': { 'mandatory_parameters': { 'system_id': 'test_system', 'password': 'abc123', 'system_type': '', 'interface_version': '34', 'addr_ton': 1, 'addr_npi': 1, 'address_range': '', }, }, }, { 'header': { 'command_length': 0, 'command_id': 'bind_transmitter_resp', 'command_status': 'ESME_ROK', 'sequence_number': 0, }, 'body': { 'mandatory_parameters': { 'system_id': 'test_system', }, }, }, { 'header': { 'command_length': 0, 'command_id': 'bind_receiver', 'command_status': 'ESME_ROK', 'sequence_number': 0, }, 'body': { 'mandatory_parameters': { 'system_id': 'test_system', 'password': 'abc123', 'system_type': '', 'interface_version': '34', 'addr_ton': 1, 'addr_npi': 1, 'address_range': '', }, }, }, { 'header': { 'command_length': 0, 'command_id': 'bind_receiver_resp', 'command_status': 'ESME_ROK', 'sequence_number': 0, }, 'body': { 'mandatory_parameters': { 'system_id': 'test_system', }, }, }, { 'header': { 'command_length': 0, 'command_id': 'bind_transceiver', 'command_status': 'ESME_ROK', 'sequence_number': 0, }, 'body': { 'mandatory_parameters': { 'system_id': 'test_system', 'password': 'abc123', 'system_type': '', 'interface_version': '34', 'addr_ton': 1, 'addr_npi': 1, 'address_range': '', }, }, }, { 'header': { 'command_length': 0, 'command_id': 'bind_transceiver_resp', 'command_status': 'ESME_ROK', 'sequence_number': 0, }, 'body': { 'mandatory_parameters': { 'system_id': 'test_system', }, }, }, { 'header': { 'command_length': 0, 'command_id': 'outbind', 'command_status': 'ESME_ROK', 'sequence_number': 0, }, 'body': { 'mandatory_parameters': { 'system_id': 'test_system', 'password': 'abc123', }, }, }, { 'header': { 'command_length': 0, 'command_id': 'unbind', 'command_status': 'ESME_ROK', 'sequence_number': 0, }, }, { 'header': { 'command_length': 0, 'command_id': 'unbind_resp', 'command_status': 'ESME_ROK', 'sequence_number': 0, }, }, { 'header': { 'command_length': 0, 'command_id': 'generic_nack', 'command_status': 'ESME_ROK', 'sequence_number': 0, }, }, { 'header': { 'command_length': 0, 'command_id': 'submit_sm', 'command_status': 'ESME_ROK', 'sequence_number': 0, }, 'body': { 'mandatory_parameters': { 'service_type': '', 'source_addr_ton': 1, 'source_addr_npi': 1, 'source_addr': '', 'dest_addr_ton': 1, 'dest_addr_npi': 1, 'destination_addr': '', 'esm_class': 0, 'protocol_id': 0, 'priority_flag': 0, 'schedule_delivery_time': '', 'validity_period': '', 'registered_delivery': 0, 'replace_if_present_flag': 0, 'data_coding': 0, 'sm_default_msg_id': 0, 'sm_length': 1, 'short_message': 'testing 123', }, }, }, { 'header': { 'command_length': 0, 'command_id': 'submit_sm', 'command_status': 'ESME_ROK', 'sequence_number': 0, }, 'body': { 'mandatory_parameters': { 'service_type': '', 'source_addr_ton': 1, 'source_addr_npi': 1, 'source_addr': '', 'dest_addr_ton': 1, 'dest_addr_npi': 1, 'destination_addr': '', 'esm_class': 0, 'protocol_id': 0, 'priority_flag': 0, 'schedule_delivery_time': '', 'validity_period': '', 'registered_delivery': 0, 'replace_if_present_flag': 0, 'data_coding': 0, 'sm_default_msg_id': 0, 'sm_length': 0, 'short_message': None, # 'short_message' can be of zero length }, 'optional_parameters': [ { 'tag': 'message_payload', 'length': 0, 'value': '5666', }, ], }, }, # ] # breaker = [ { 'header': { 'command_length': 0, 'command_id': 'submit_sm_resp', 'command_status': 'ESME_ROK', 'sequence_number': 0, }, 'body': { 'mandatory_parameters': { 'message_id': '', }, }, }, { 'header': { 'command_length': 0, 'command_id': 'submit_sm_resp', 'command_status': 'ESME_RSYSERR', 'sequence_number': 0, }, # submit_sm_resp can have no body for failures }, { 'header': { 'command_length': 0, 'command_id': 'submit_multi', 'command_status': 'ESME_ROK', 'sequence_number': 0, }, 'body': { 'mandatory_parameters': { 'service_type': '', 'source_addr_ton': 1, 'source_addr_npi': 1, 'source_addr': '', 'number_of_dests': 0, 'dest_address': [ { 'dest_flag': 1, 'dest_addr_ton': 1, 'dest_addr_npi': 1, 'destination_addr': 'the address' }, { 'dest_flag': 2, 'dl_name': 'the list', }, { 'dest_flag': 2, 'dl_name': 'the other list', }, # {} ], 'esm_class': 0, 'protocol_id': 0, 'priority_flag': 0, 'schedule_delivery_time': '', 'validity_period': '', 'registered_delivery': 0, 'replace_if_present_flag': 0, 'data_coding': 0, 'sm_default_msg_id': 0, 'sm_length': 1, 'short_message': 'testing 123', }, }, }, { 'header': { 'command_length': 0, 'command_id': 'submit_multi_resp', 'command_status': 'ESME_ROK', 'sequence_number': 0, }, 'body': { 'mandatory_parameters': { 'message_id': '', 'no_unsuccess': 5, 'unsuccess_sme': [ { 'dest_addr_ton': 1, 'dest_addr_npi': 1, 'destination_addr': '', 'error_status_code': 0, }, { 'dest_addr_ton': 3, 'dest_addr_npi': 1, 'destination_addr': '555', 'error_status_code': 0, }, ], }, }, }, # ] # breaker = [ { 'header': { 'command_length': 0, 'command_id': 'deliver_sm', 'command_status': 'ESME_ROK', 'sequence_number': 0, }, 'body': { 'mandatory_parameters': { 'service_type': '', 'source_addr_ton': 1, 'source_addr_npi': 1, 'source_addr': '', 'dest_addr_ton': 1, 'dest_addr_npi': 1, 'destination_addr': '', 'esm_class': 0, 'protocol_id': 0, 'priority_flag': 0, 'schedule_delivery_time': '', 'validity_period': '', 'registered_delivery': 0, 'replace_if_present_flag': 0, 'data_coding': 0, 'sm_default_msg_id': 0, 'sm_length': 1, 'short_message': '', }, }, }, { 'header': { 'command_length': 0, 'command_id': 'deliver_sm_resp', 'command_status': 'ESME_ROK', 'sequence_number': 0, }, 'body': { 'mandatory_parameters': { 'message_id': '', }, }, }, { 'header': { 'command_length': 0, 'command_id': 'data_sm', 'command_status': 'ESME_ROK', 'sequence_number': 0, }, 'body': { 'mandatory_parameters': { 'service_type': '', 'source_addr_ton': 1, 'source_addr_npi': 1, 'source_addr': '', 'dest_addr_ton': 1, 'dest_addr_npi': 1, 'destination_addr': '', 'esm_class': 0, 'registered_delivery': 0, 'data_coding': 0, }, 'optional_parameters': [ { 'tag': 'message_payload', 'length': 0, 'value': '', }, ], }, }, { 'header': { 'command_length': 0, 'command_id': 'data_sm_resp', 'command_status': 'ESME_ROK', 'sequence_number': 0, }, 'body': { 'mandatory_parameters': { 'message_id': '', }, }, }, { 'header': { 'command_length': 0, 'command_id': 'query_sm', 'command_status': 'ESME_ROK', 'sequence_number': 0, }, 'body': { 'mandatory_parameters': { 'message_id': '', 'source_addr_ton': 1, 'source_addr_npi': 1, 'source_addr': '', }, }, }, { 'header': { 'command_length': 0, 'command_id': 'query_sm_resp', 'command_status': 'ESME_ROK', 'sequence_number': 0, }, 'body': { 'mandatory_parameters': { 'message_id': '', 'final_date': '', 'message_state': 0, 'error_code': 0, }, }, }, { 'header': { 'command_length': 0, 'command_id': 'cancel_sm', 'command_status': 'ESME_ROK', 'sequence_number': 0, }, 'body': { 'mandatory_parameters': { 'service_type': '', 'message_id': '', 'source_addr_ton': 1, 'source_addr_npi': 1, 'source_addr': '', 'dest_addr_ton': 1, 'dest_addr_npi': 1, 'destination_addr': '', }, }, }, { 'header': { 'command_length': 0, 'command_id': 'cancel_sm_resp', 'command_status': 'ESME_ROK', 'sequence_number': 0, }, }, { 'header': { 'command_length': 0, 'command_id': 'replace_sm', 'command_status': 'ESME_ROK', 'sequence_number': 0, }, 'body': { 'mandatory_parameters': { 'message_id': '', 'source_addr_ton': 1, 'source_addr_npi': 1, 'source_addr': '', 'schedule_delivery_time': '', 'validity_period': '', 'registered_delivery': 0, 'replace_if_present_flag': 0, 'data_coding': 0, 'sm_default_msg_id': 0, 'sm_length': 1, 'short_message': 'is this an = sign?', }, }, }, { 'header': { 'command_length': 0, 'command_id': 'replace_sm_resp', 'command_status': 'ESME_ROK', 'sequence_number': 0, }, }, { 'header': { 'command_length': 0, 'command_id': 'enquire_link', 'command_status': 'ESME_ROK', 'sequence_number': 0, }, }, { 'header': { 'command_length': 0, 'command_id': 'enquire_link_resp', 'command_status': 'ESME_ROK', 'sequence_number': 0, }, }, { 'header': { 'command_length': 0, 'command_id': 'alert_notification', 'command_status': 'ESME_ROK', 'sequence_number': 0, }, 'body': { 'mandatory_parameters': { 'source_addr_ton': 'international', 'source_addr_npi': 1, 'source_addr': '', 'esme_addr_ton': 9, 'esme_addr_npi': '', 'esme_addr': '', }, }, }, ] PKb?xH2 77test/pdu_hex_asserts.py ######################################## pdu_json_0000000001 = '''{ "body": { "mandatory_parameters": { "data_coding": 0, "dest_addr_npi": "ISDN", "dest_addr_ton": "international", "destination_addr": "555555555", "esm_class": 0, "priority_flag": 0, "protocol_id": 0, "registered_delivery": 0, "replace_if_present_flag": 0, "schedule_delivery_time": "", "service_type": "", "short_message": "Hello wikipedia", "sm_default_msg_id": 0, "sm_length": 15, "source_addr": "555", "source_addr_npi": "national", "source_addr_ton": "national", "validity_period": "" }, "optional_parameters": [ { "length": 0, "tag": "0000", "value": null }, { "length": 2, "tag": "additional_status_info_text", "value": "ef" } ] }, "header": { "command_id": "submit_sm", "command_length": 60, "command_status": "ESME_ROK", "sequence_number": 5 } }''' ######################################## pdu_json_0000000002 = '''{ "body": { "mandatory_parameters": { "data_coding": 0, "dest_address": [ { "dest_addr_npi": "ISDN", "dest_addr_ton": "international", "dest_flag": 1, "destination_addr": "e" }, { "dest_flag": 2, "dl_name": "f" } ], "esm_class": 0, "number_of_dests": 2, "priority_flag": 0, "protocol_id": 0, "registered_delivery": 0, "replace_if_present_flag": 0, "schedule_delivery_time": "", "service_type": "", "short_message": null, "sm_default_msg_id": 0, "sm_length": 0, "source_addr": "", "source_addr_npi": "unknown", "source_addr_ton": "unknown", "validity_period": "" }, "optional_parameters": [ { "length": 2, "tag": "dest_addr_subunit", "value": 0 }, { "length": 4, "tag": "0000", "value": "00000000" } ] }, "header": { "command_id": "submit_multi", "command_length": 0, "command_status": "ESME_ROK", "sequence_number": 0 } }''' ######################################## pdu_json_0000000003 = '''{ "body": { "mandatory_parameters": { "message_id": "", "no_unsuccess": 2, "unsuccess_sme": [ { "dest_addr_npi": "ISDN", "dest_addr_ton": "international", "destination_addr": "eee", "error_status_code": 0 }, { "dest_addr_npi": "ISDN", "dest_addr_ton": "international", "destination_addr": "fff", "error_status_code": 0 } ] } }, "header": { "command_id": "submit_multi_resp", "command_length": 0, "command_status": "ESME_ROK", "sequence_number": 0 } }''' PKxHkpz+python_smpp-0.1.9.dist-info/DESCRIPTION.rstPython SMPP =========== An SMPP version 3.4 library written in Python, suitable for use in Twisted_. |travis|_ |coveralls|_ To get started with development:: $ virtualenv --no-site-packages ve/ $ source ve/bin/activate (ve)$ pip install -r requirements.pip (ve)$ python >>> import smpp >>> Run the tests with nose (ve)$ nosetests .. _Twisted: http://www.twistedmatrix.com .. |travis| image:: https://travis-ci.org/praekelt/python-smpp.png?branch=develop .. _travis: https://travis-ci.org/praekelt/python-smpp .. |coveralls| image:: https://coveralls.io/repos/praekelt/python-smpp/badge.png?branch=develop .. _coveralls: https://coveralls.io/r/praekelt/python-smpp PKxH"J)python_smpp-0.1.9.dist-info/metadata.json{"classifiers": ["Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Topic :: Software Development :: Libraries :: Python Modules"], "extensions": {"python.details": {"contacts": [{"email": "dev@praekeltfoundation.org", "name": "Praekelt Foundation", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "http://github.com/praekelt/python-smpp"}}}, "generator": "bdist_wheel (0.26.0)", "license": "BSD", "metadata_version": "2.0", "name": "python-smpp", "summary": "Python SMPP Library", "version": "0.1.9"}PKxHO )python_smpp-0.1.9.dist-info/top_level.txtsmpp test PKxH''\\!python_smpp-0.1.9.dist-info/WHEELWheel-Version: 1.0 Generator: bdist_wheel (0.26.0) Root-Is-Purelib: true Tag: py2-none-any PKxHk$python_smpp-0.1.9.dist-info/METADATAMetadata-Version: 2.0 Name: python-smpp Version: 0.1.9 Summary: Python SMPP Library Home-page: http://github.com/praekelt/python-smpp Author: Praekelt Foundation Author-email: dev@praekeltfoundation.org License: BSD Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Topic :: Software Development :: Libraries :: Python Modules Python SMPP =========== An SMPP version 3.4 library written in Python, suitable for use in Twisted_. |travis|_ |coveralls|_ To get started with development:: $ virtualenv --no-site-packages ve/ $ source ve/bin/activate (ve)$ pip install -r requirements.pip (ve)$ python >>> import smpp >>> Run the tests with nose (ve)$ nosetests .. _Twisted: http://www.twistedmatrix.com .. |travis| image:: https://travis-ci.org/praekelt/python-smpp.png?branch=develop .. _travis: https://travis-ci.org/praekelt/python-smpp .. |coveralls| image:: https://coveralls.io/repos/praekelt/python-smpp/badge.png?branch=develop .. _coveralls: https://coveralls.io/r/praekelt/python-smpp PKxH"python_smpp-0.1.9.dist-info/RECORDpython_smpp-0.1.9.dist-info/DESCRIPTION.rst,sha256=RdSkzIJA1EqkSjb6HuYKufwKEW3ahilczLo1S3rxzq8,703 python_smpp-0.1.9.dist-info/METADATA,sha256=ltEq1thg7WR001ebCK97j-FUSuKnF1PKxKE29OTNMCs,1239 python_smpp-0.1.9.dist-info/RECORD,, python_smpp-0.1.9.dist-info/WHEEL,sha256=JTb7YztR8fkPg6aSjc571Q4eiVHCwmUDlX8PhuuqIIE,92 python_smpp-0.1.9.dist-info/metadata.json,sha256=Bd4-DHdekRhRxHngXXZ-M1_-tnfgj6pcmqRrdV42-rM,685 python_smpp-0.1.9.dist-info/top_level.txt,sha256=6_REplq-pwlBPhrIt1ZsHZTCKjciGcYbFR1e6Hltvyc,10 smpp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 smpp/clickatell.py,sha256=gmjS6vI0UZvjlMrJ-l2l-FxF-z9T7ZqUFpwN_ySjBCY,106 smpp/esme.py,sha256=xwhkdUcpiK13fUmyjkYsJxm6NVKmi7cCe6PLCXQnL_Y,4435 smpp/pdu.py,sha256=JpKOWJMQBvv8M6D2MVyT-2VeJ6z0s0YDakJNbkXl258,78858 smpp/pdu_builder.py,sha256=lGLOyDo1Gl4Y-XNImHsP2LfUbjK__N6_1fKBGsfdHxw,11200 smpp/pdu_inspector.py,sha256=c17BkUCde31fFJphAvLh8aYylGVMcjHqnG3YVLq75Vo,4303 smpp/smsc.py,sha256=GRxSDyGo96VCp7ZJgGsc__Y7O9W25ETItKT86jDfLeQ,2838 test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 test/pdu.py,sha256=QI9e7AE9hS0v-WkHOecg113rcvdHyMrUjU8dJ17lu7U,14568 test/pdu_asserts.py,sha256=2Sw4qcbzR9zd3a0BXxF7sid40yceHQ1vDw6dKN9HLGE,14639 test/pdu_hex.py,sha256=DjK1XDnUjhGIDLlkR_z6EHZwKTA_GyE_q-YgvCJCTCU,1056 test/pdu_hex_asserts.py,sha256=yH9ENKYH8tmLdR037xo83yLYVFUtkLw4-uPtDvTxZNw,3639 test/test_multipart.py,sha256=7hrZVd4yD39wmNuFTHNPMPUkqZwkt06LGY7FCaXoQHY,5160 PKb?xH[C8jjsmpp/clickatell.pyPK;xHsmpp/__init__.pyPKb?xH8RSS smpp/esme.pyPKb?xH,  Esmpp/smsc.pyPKb?xHHsmpp/pdu_inspector.pyPKb?xHJ 4 4 .smpp/pdu.pyPKb?xHJ++bsmpp/pdu_builder.pyPKb?xH /9/9test/pdu_asserts.pyPKb?xHE(( test/test_multipart.pyPK;xHgtest/__init__.pyPKb?xH^}  test/pdu_hex.pyPKb?xH)088 test/pdu.pyPKb?xH2 77test/pdu_hex_asserts.pyPKxHkpz+_(python_smpp-0.1.9.dist-info/DESCRIPTION.rstPKxH"J)g+python_smpp-0.1.9.dist-info/metadata.jsonPKxHO )[.python_smpp-0.1.9.dist-info/top_level.txtPKxH''\\!.python_smpp-0.1.9.dist-info/WHEELPKxHk$G/python_smpp-0.1.9.dist-info/METADATAPKxH"`4python_smpp-0.1.9.dist-info/RECORDPK%j: