Пример #1
0
Файл: sms.py Проект: matt9j/rccn
 def determine_coding(self, unicode_str):
     if type(unicode_str) != unicode:
         raise SMSException('Input is not unicode')
     try:
         try:
             _test0338 = unicode_str.encode('gsm03.38')
             sms_log.debug('GSM03.38 OK "%s" -> "%s"' %
                           (unicode_str, _test0338.decode('gsm03.38')))
             return '0'
         except ValueError as ex:
             sms_log.debug(
                 'Encoding to GSM03.38 default alphabet not possible. %s' %
                 sys.exc_info()[1])
         _test0338s = gsm0338.Codec(single_shift_decode_map=gsm0338.
                                    SINGLE_SHIFT_CHARACTER_SET_SPANISH)
         _test = _test0338s.encode(unicode_str)[0]
         sms_log.debug('GSM03.38 Spanish Shift OK "%s" -> "%s"' %
                       (unicode_str, _test0338s.decode(_test)[0]))
         return '2'
     except Exception as ex:
         template = "exception of type {0}. Arguments:\n{1!r}"
         print template.format(type(ex).__name__, ex.args)
         sms_log.debug('Using GSM03.38 Spanish Shift not possible. %s' %
                       sys.exc_info()[1])
         return '2'
Пример #2
0
	def parseAddress(tpdu):
		'''Parse the TP-Address-Length, TP-Type-Of-Address and TP-Address
		from the start of the given TPDU and return the TOA, address and
		remaining TPDU.
		'''
		pl = tpdu.int()
		toa = tpdu.int()
		# XXX todo parse this
		if 0 and toa not in (0x91, 0x81):
			raise ValueError('expected toa of 81/91, not 0x%02x' % toa)
		address = tpdu.octets(pl / 2 + pl % 2)
		if (toa & 0x70) == 0x50:
			# GSM-coded address - decode to ASCII and strip any crap
			address = unpack7bit(address, 0)
			c = gsm0338.Codec()
			address = decode_ascii_safe(c.decode(address, 'replace')[0], False)
			address = address.encode('ascii')
 
			# some phones put bits in the lower nybble of the TOA when
			# sending alphanumeric addresses; this is wrong wrong wrongedy
			# wrong "for Type-of-number = 101 bits 3,2,1,0 are reserved and
			# shall be transmitted as 0000" from the spec.
			toa &= 0xF0
		else:
			address = unpackPhoneNumber(address)
		# prefix of "00" *usually* means "+" in eurospeak
		if address.startswith('00'):
		#if address.startswith(b'\x00'):
			address = address[2:]
		return pl, toa, address
Пример #3
0
def test_encode_spanish_single_shift():
    unicode_spanish_single_shift = u'ç\u000A^{}\[~]|ÁÍÓÚá€íóú'
    gsm_spanish_single_shift = b'\x1B\x09\x0A\x1B\x14\x1B\x28\x1B\x29' \
                               b'\x1B\x2F\x1B\x3C\x1B\x3D\x1B\x3E\x1B\x40' \
                               b'\x1B\x41\x1B\x49\x1B\x4F\x1B\x55\x1B\x61' \
                               b'\x1B\x65\x1B\x69\x1B\x6F\x1B\x75'

    codec = gsm0338.Codec(
        single_shift_decode_map=gsm0338.SINGLE_SHIFT_CHARACTER_SET_SPANISH)
    assert codec.encode(unicode_spanish_single_shift) == \
        (gsm_spanish_single_shift, len(unicode_spanish_single_shift))
Пример #4
0
Файл: sms.py Проект: matt9j/rccn
 def check_decode0338(self, text):
     try:
         return text.decode('gsm03.38')
     except Exception as ex:
         sms_log.error(str(ex))
         try:
             gsm_shift_codec = gsm0338.Codec(
                 single_shift_decode_map=gsm0338.
                 SINGLE_SHIFT_CHARACTER_SET_SPANISH)
             return gsm_shift_codec.decode(text)[0]
         except Exception as ex:
             sms_log.error(str(ex))
Пример #5
0
	def determineAddress(address):
		'''Determine the TP-Address-Length, TP-Type-of-Address and
		TP-(Originating|Destination)-Address values for the supplied
		address string.
		'''
		if re.match('^\d+$', address):
			# phone number
			# Type-of-Address == 91			(international number)
			tp_al = len(address)
			tp_toa = 0x91
			packed = packPhoneNumber(address)
		else:
			# Type-of-Address == D0			(alphanumeric)
			c = gsm0338.Codec()
			l, packed = pack7bit(c.encode(address, 'replace'))
			tp_al = len(packed) * 2
			tp_toa = 0xD0
		return tp_al, tp_toa, packed
Пример #6
0
def generate_mwi_dcs(type, active, message):
	'''Given a MWI type, active flag and unicode message generate a DCS for
	an SMS PDU.
 
	Return the (possibly modified) message and the tp_dcs to use.
	'''
	dcs = dict(voicemail=0, fax=1, email=2, other=3)[type]
 
	if active == 'active':
		dcs |= 0x08
 
	if not message:
		return message, dcs | 0xC0
 
	message, x = attempt_encoding(message)
	try:
		gsm0338.Codec().encode(message)
		# code with GSM 0338
		return message, dcs | 0xD0
	except UnicodeError:
		# code with UCS2
		return message, dcs | 0xE0
Пример #7
0
def smpp_to_sms_data_coding(smpp_dcs, content):
	'''Attempt to convert the SMPP data coding scheme (SMPP v34) to a useful
	SMS PDU (GSM 03.38) data coding scheme.
 
	The top nybble of the data coding scheme is the same for both
	specifications; it's just the lower nybble that the fuckers couldn't
	agree on. Since the SMS PDU spec dictates what's actually transmitted
	to the handset it trumps the SMPP one.
 
	Fortunately for non-trivial messages (ie. top nybble != 0) the SMPP
	spec says "see the GSM spec" so we just pass those through.
 
	We currently cannot handle messages in JIS (0208 or 0212) or KS C 5601.
	'''
	top = smpp_dcs & 0xf0
	if top:
		return smpp_dcs, content
	bottom = smpp_dcs & 0xf
 
	# default alphabet or ASCII; pass on
	if bottom in (0, 1):
		return 0, content
 
	# raw binary - 0000 0100
	# note I've included "pictogram encoding" and "music codes" as "raw
	# data"
	if bottom == (2, 4, 9, 10):
		return 4, content
 
	# UCS2 - 0000 1000
	if bottom == 8:
		return 8, content
 
	# one of the ISO charsets (iso-8859-1, iso-8859-5, iso-8859-8) or just
	# give the hell up
	charset = SMPP_ISO_CHARSETS.get(bottom, 'ascii')
	content, b = attempt_encoding(content.decode(charset, 'ignore'))
	content = gsm0338.Codec().encode(content)
	return 0, content
Пример #8
0
def guess_dcs(message):
	'''Given a plain-text message try to guess an appropriate DCS.
	'''
	# figure encoding and add TP-DCS, TP-UDL and TP-UD (enforcing the 140
	# octet maximum length of TP-UD)
	c = gsm0338.Codec()
	try:
		# GSM-0338 (7-bit)
		length = len(c.encode(message))
 
		# TP-User-Data-Length -- number of septets (characters)
		if length > 160:
			raise ValueError('7-bit message too long (%d>160 chars)' %
				length)
 
		return 0
	except UnicodeError:
		# UCS2 (well, UTF-16) big-endian
		length = len(message.encode('utf_16_be'))
		if length > 140:
			raise ValueError('UCS-2 message too long (%d>140 chars)' %
				length)
		return 8
Пример #9
0
    def receive(self, request, source, destination, charset, coding, text,
                btext, dr, dcs):

        if btext == '':
            btext = text
        t = binascii.hexlify(btext)

        api_log.info(
            '%s - [POST] %s Data: source:"%s" destination:"%s" charset:"%s"' %
            (request.getHost().host, self.path, source, destination, charset))
        api_log.debug(
            'Data: source:"%s" destination:"%s" charset:"%s" coding: "%s" content: %s HexofBin: %s DR: %s DCS: %s'
            % (source, destination, charset, coding,
               text.decode(charset, 'replace'), t, dr, dcs))

        # Kannel sends us GSM0338 but sets charset param to UTF-8
        if coding == '0':
            try:
                gsm_shift_codec = gsm0338.Codec(
                    single_shift_decode_map=gsm0338.
                    SINGLE_SHIFT_CHARACTER_SET_SPANISH)
                text = gsm_shift_codec.decode(btext)[0]
                api_log.info('SMS Decoded from GSM 03.38')
                api_log.debug('Decoded text:"%s"' % text)
            except:  # Catch Everything, try to not actually LOSE messages!
                e = sys.exc_info()[0]
                api_log.debug('Caught Exception: %s %s' %
                              (e, sys.exc_info()[1]))
                data = {
                    'status': 'failed',
                    'error': str(e) + ' ' + str(sys.exc_info()[1])
                }
                text = btext
        # Kannel can have problems if we send back UTF-16BE, so let's standardise here:
        if coding == '2' and charset == 'UTF-16BE':
            try:
                text = btext.decode('utf-16be')
                api_log.info('SMS decoded as UTF-16BE')
                api_log.debug('Decoded text: "%s"' % text)
            except:  # Catch Everything, try to not actually LOSE messages!
                e = sys.exc_info()[0]
                api_log.debug('Caught Exception: %s %s' %
                              (e, sys.exc_info()[1]))
                # Some phones are sending multi part messages with different charsets.
                # Kannel concatenates and sends as UTF-16BE coding 2
                try:
                    api_log.info('Trying multi part trick')
                    a = btext[:134]
                    b = btext[134:]
                    text = a.decode('utf-16be') + b.decode('utf8')
                except:
                    api_log.debug('Caught Exception: %s %s' %
                                  (e, sys.exc_info()[1]))
                    text = btext
        try:
            sms = SMS()
            sms.receive(source, destination, text, charset, coding)
            data = {'status': 'success', 'error': ''}
        except SMSException as e:
            data = {'status': 'failed', 'error': str(e)}

        api_log.info(data)
        return data
Пример #10
0
def build_msgs(smsq):
    ret = []
    csms = {}
    for sms in smsq:
        charset = 'utf-8'
        utext = ''
        """
        
        0        id INTEGER PRIMARY KEY AUTOINCREMENT
        1        created TIMESTAMP NOT NULL
        2        sent TIMESTAMP
        3        deliver_attempts INTEGER NOT NULL DEFAULT 0
        4        valid_until TIMESTAMP
        5        reply_path_req INTEGER NOT NULL
        6        status_rep_req INTEGER NOT NULL
        (7       is_report INTEGER NOT NULL)
        (8       msg_ref INTEGER NOT NULL)
        7 9      protocol_id INTEGER NOT NULL
        8 10     data_coding_scheme INTEGER NOT NULL
        9 11     ud_hdr_ind INTEGER NOT NULL
        10 12    src_addr TEXT NOT NULL
        11 13    src_ton INTEGER NOT NULL
        12 14    src_npi INTEGER NOT NULL
        13 15    dest_addr TEXT NOT NULL
        14 16    dest_ton INTEGER NOT NULL
        15 17    dest_npi INTEGER NOT NULL
        16 18    user_data BLOB
        17 19    header BLOB
        18 20    text TEXT
        """
        if db_revision == '5':
            is_report = sms[7]
            coding = sms[10]
            udhdr = sms[11]
            src = sms[12]
            dest = sms[15]
            userdata = sms[18]
            header = sms[19]
            text = sms[20]
        elif db_revision == '4':
            is_report = 0
            coding = sms[8]
            udhdr = sms[9]
            src = sms[10]
            dest = sms[13]
            coding = sms[8]
            userdata = sms[16]
            header = sms[17]
            text = sms[18]
        else:
            print "Unknown DB Revision"
            exit()

        log.debug("Message ID: \033[93m" + str(sms[0]) + '\033[0m')
        log.debug("Valid Until: " + str(sms[4]))
        log.debug("Coding is \033[32m%s \033[0m" % str(coding))
        log.debug("UD HDR Indicator: " + str(sms[9]))
        log.debug("User Data: " + binascii.hexlify(userdata))

        dtext = _dbd_decode_bin(userdata)

        if udhdr == 64:
            h = dtext[:7]
            #for i in [0, 1, 2, 3, 4, 5, 6]:
            #    log.debug( ord(h[i]) )
            #udh=parse_udh(h)
            udhdr = 1

        if (udhdr == 1 and ord(dtext[0]) == 5):
            log.debug("UDH Detected")
            h = dtext[:6]
            msg = dtext[6:]
            udh = parse_udh(h)
            log.debug("CSMS Reference: " + str(udh['csms_ref']))
            log.debug("Part No #" + str(udh['part_num']) + " of " +
                      str(udh['parts']))
            log.debug("Part Coding:" + str(coding))
            not_decoded = 0
            if coding == 0:
                msg = str(
                    unpackSeptets(msg, None, 0,
                                  6).lstrip(chr(0)).rstrip(chr(0)))
                try:
                    msgpart = unicode(msg, 'gsm03.38')
                    charset = 'GSM03.38'
                except:
                    log.debug("Multipart decode failed for gsm03.38")
            else:
                try:
                    msgpart = unicode(msg, 'utf-8')
                    charset = 'UTF-8'
                except UnicodeDecodeError:
                    log.debug("Multipart decode failed for UTF-8")
                    try:
                        msgpart = unicode(msg, 'utf-16be')
                        charset = 'UTF-16BE'
                    except:
                        # Can't decode this segment on its own,
                        # probably because truncated utf16 data.
                        msgpart = msg
                        charset = 'utf-16be'
                        not_decoded = 1
                        if udh['part_num'] > 1 and csms[udh['csms_ref']][
                                'not_decoded'][udh['part_num'] - 1] == 1:
                            # try adding it to the last part..
                            csms[udh['csms_ref']]['text'][udh['part_num'] -
                                                          1] += msg
                            msgpart = ''

            if not_decoded == 1:
                log.debug("Message Part Not Decoded on its own")
            else:
                log.debug("Message Part:" + msgpart.encode('utf-8', 'replace'))
            try:
                if not udh['csms_ref'] in csms or csms[
                        udh['csms_ref']] == None:
                    csms[udh['csms_ref']] = {}
                    csms[udh['csms_ref']]['ids'] = {}
                    csms[udh['csms_ref']]['text'] = {}
                    csms[udh['csms_ref']]['not_decoded'] = {}
                    csms[udh['csms_ref']]['parts'] = udh['parts']
                csms[udh['csms_ref']]['ids'][udh['part_num']] = sms[0]
                csms[udh['csms_ref']]['text'][udh['part_num']] = msgpart
                csms[udh['csms_ref']]['not_decoded'][
                    udh['part_num']] = not_decoded

                if csms[udh['csms_ref']]['parts'] and udh['part_num'] == csms[
                        udh['csms_ref']]['parts']:
                    log.debug("Found Last Part of CSMS %s" %
                              str(udh['csms_ref']))
                    utext = ''
                    mid = ''
                    for i in range(0, csms[udh['csms_ref']]['parts']):
                        try:
                            if csms[udh['csms_ref']]['not_decoded'][i +
                                                                    1] == 1:
                                text += csms[udh['csms_ref']]['text'][i + 1]
                            else:
                                utext += csms[udh['csms_ref']]['text'][i + 1]
                            mid += str(
                                csms[udh['csms_ref']]['ids'][i + 1]) + ', '
                        except KeyError:
                            log.error(
                                "Missing part %s of Multipart SMS %s for id %s"
                                % ((i + 1), udh['csms_ref'], sms[0]))
                            pass
                    #if csms[udh['csms_ref']]['not_decoded'][i] == 1:
                    #    utext=utext+text.decode(charset)
                    mid = mid.rstrip(', ')
                    csms[udh['csms_ref']] = None
                    #utext = unicode(utext.encode('utf-8'))
                else:
                    continue
            except Exception as ex:
                print ex
        else:
            mid = str(sms[0])
            if coding == 0:
                # unpackSeptets returns bytearray
                text7 = unpackSeptets(dtext).rstrip(chr(0))
                log.debug("User Data Octets unpacked: " +
                          binascii.hexlify(text7))
                # gsm_codec_s = gsm0338.Codec()
                gsm_codec = gsm0338.Codec(single_shift_decode_map=gsm0338.
                                          SINGLE_SHIFT_CHARACTER_SET_SPANISH)
                utext = gsm_codec.decode(str(text7))[0]
                charset = 'gsm03.38'
            elif (coding == 8 or coding == 4) and is_report < 1:
                # I don't have any indicator of what the actual charset is.
                log.debug("Lost")
                try:
                    if re.match(r'[\x00-\x0f]', dtext):
                        utext = unicode(dtext, 'utf-16be')
                        charset = 'UTF-16BE'
                    else:
                        utext = unicode(dtext, 'utf-8')
                        charset = 'UTF-8'

                except UnicodeDecodeError as e:
                    try:
                        utext = unicode(dtext, 'utf-16be')
                    except Exception as e:
                        print e
                    charset = 'UTF-16BE'
                log.debug("Coding value is 4/8, Charset Determined %s",
                          charset)
            else:
                utext = unicode(dtext, charset, 'replace')
                charset = 'utf-8'

        log.debug("User Data dbd_decoded: " +
                  binascii.hexlify(utext.encode(charset, 'replace')))

        if header:
            log.debug("Header field: " + binascii.hexlify(header))

        log.debug("DB text field '%s' (Length:%s)" %
                  (binascii.hexlify(text), str(len(text))))

        r = {}
        r['sms'] = sms
        r['mid'] = mid
        r['src'] = src
        r['dest'] = dest
        r['coding'] = coding
        r['charset'] = charset
        r['text'] = utext
        ret.append(r)
        if 'options' in globals() and options.debug_stop:
            cs(locals())

    return ret
Пример #11
0
def codec():
    return gsm0338.Codec()
Пример #12
0
	def determineUD(user_data, tp_dcs, user_data_headers):
		'''Figure the TP-User-Data content and generate the PDU
		parameters tp_udhi, tp_dcs, tp_udl and tp_ud.
		'''
		if user_data_headers:
			tp_udhi = 1
 
			h = ''
			for ie, val in user_data_headers:
				h += chr(ie) + chr(len(val)) + ''.join(map(chr, val))
			tp_ud = chr(len(h)) + h
 
		else:
			tp_udhi = 0
			tp_ud = ''
 
		top_nybble = tp_dcs & 0xF0
 
		if top_nybble == 0xC0:
			# Message Waiting Indication Group: Discard Message GSM
			codec = 'gsm'
		elif top_nybble == 0xD0:
			# Message Waiting Indication Group: Store Message GSM
			codec = 'gsm'
		elif top_nybble == 0xE0:
			# Message Waiting Indication Group: Store Message UCS2
			codec = 'ucs2'
		elif top_nybble == 0xF0:
			# Data coding / message class
			codec = ['gsm', None][(tp_dcs & 0x04) >> 2]
		else:
			# either General Data Coding indication (0x0X .. 0x3X)
			#	  or Automatic Deletion (0x4X .. 0xbX)
			# (note that the book says Automatic Deletion but the GSM spec
			# says Reserved ... either way I'll just pass through)
			try:
				codec = ['gsm', None, 'ucs2'][(tp_dcs & 0x0C) >> 2]
			except IndexError:
				raise ValueError('bad tp_dcs value (reserved alphabet)')
 
		if codec == 'gsm':
			# GSM-0338 default alphabet
			c = gsm0338.Codec()
 
			# play it safe and force encoding with replace
			encoded = c.encode(user_data, 'replace')
 
			# TP-User-Data 7bit packed GSM-0338 encoded funky sh!t
			l, user_data = pack7bit(encoded, len(tp_ud))
			tp_udl = l + len(tp_ud)
 
		elif codec == 'ucs2':
			# UCS2
			user_data = user_data.encode('utf_16_be', 'replace')
			length = len(user_data)
			if length > 140:
				raise ValueError('UCS-2 message too long (%d>140 chars)' %
					length)
			tp_udl = len(user_data) + len(tp_ud)
 
		else:
			# 8-bit data
			tp_udl = len(user_data) + len(tp_ud)
 
		tp_ud += user_data
		return tp_udhi, tp_dcs, tp_udl, tp_ud
Пример #13
0
	def parseUD(tp_dcs, tp_ud, tp_udhi, tp_udl):
		'''Parse user data (ie. the message) out of the tp_ud data
		string.
		'''
		# pull out user-data headers if any
		if tp_udhi:
			data, headerlen, user_data_headers = SMS_GENERIC.parseUDH(tp_ud)
		else:
			data = tp_ud
			headerlen = 0
			user_data_headers = []
 
		# GSM 03.38, section 4
		if (tp_dcs & 0xc0) == 0:
			if tp_dcs & 0x20:
				raise PDUDecodeError('compressed data not supported: '
					'tp_dcs 0x%02x (%s)' % (tp_dcs, describe_tp_dcs(tp_dcs)))
				data = decompress_user_data(data)
			try:
				charset = {0x00: '7bit', 0x04: '8bit',
					0x08: 'utf-16'}[tp_dcs & 0x0c]
			except KeyError:
				raise PDUDecodeError('invalid DCS : tp_dcs 0x%02x '
					'(specifies unknown charset)' % tp_dcs)
		elif (tp_dcs & 0xf0) in (0xc0, 0xd0):
			# MWI, Default Alphabet
			charset = '7bit'
		elif (tp_dcs & 0xf0) == 0xe0:
			# MWI, USC2
			charset = 'utf-16'
		elif (tp_dcs & 0xf0) == 0xf0:
			charset = {0x00: '7bit', 0x04: '8bit'}[tp_dcs & 0x04]
		else:
			raise PDUDecodeError('unhandled tp_dcs 0x%02x (%s)' % (tp_dcs,
				describe_tp_dcs(tp_dcs)))
 
		# figure the number of characters (or octets, for data) that are
		# expected based on the tp_udl minus however many header octets
		# we've seen
		actual_udl = tp_udl - headerlen
 
		# now decode the user data
		if charset == '7bit':  # basic 7 bit coding - 03.38 S6.2.1
			data = unpack7bit(data, headerlen)
			c = gsm0338.Codec()
			user_data, length = c.decode(data)
			user_data = user_data[:actual_udl]
		elif charset == '8bit':  # 8 bit coding is "user defined". S6.2.2
			user_data = unpack8bit(data)
			user_data = user_data[:actual_udl]
		elif charset == 'utf-16':  # UTF-16 aka UCS2, S6.2.3
			try:
				user_data = unpackUCS2(data)
				user_data = user_data[:actual_udl]
			except UnicodeDecodeError as e:
				raise PDUDecodeError('PDU corrupted: %s' % e)
		else:
			raise PDUDecodeError('tp_dcs of 0x%02x (%s), charset %s' % (tp_dcs,
				describe_tp_dcs(tp_dcs), charset))
 
		return user_data, user_data_headers
Пример #14
0
def attempt_encoding(u, limit=160):
	'''Given the input unicode string attempt to encode it for SMS delivery.
 
	This means taking some arbitrary input text and fitting it, encoded,
	within the 160 septet limit (overridable) of an SMS packet. Some
	characters in the input may not be encodable at all, some may encode to
	multiple characters in the SMS packet.
 
	The rules for handling the input text are:
 
	1. attempt to encode with GSM-0338,
	2. remove typographical characters (eg, curly quotes),
	3. attempt to represent without accents,
	4. attempt to replace common characters that encode to double-width
	   characters, and
	5. give up and use UTF-16.
 
	Using UTF-16 is a last resort since it halves the message length.
 
	Returns two things: the potentially-translated and truncated string and
	the string containing any excess characters.
	'''
	# Attempt to encode with GSM-0338 + translations
	gsm = gsm0338.Codec()
	l = []
	e = []
	s = ''
	for c in u:
		# replace all control codes
		if ord(c) < 0x20 and c not in '\r\n':
			c = u'?'
		try:
			t = gsm.encode(c)
		except UnicodeError:
			translated = remove_typography(c)
			translated = remove_accent(translated)
			if c == translated:
				# no translation possible; can't encode in GSM
				break
			c = translated
			try:
				t = gsm.encode(c)
			except UnicodeError:
				# translated but we still can't GSM encode
				break
		s += t
		if len(s) > limit:
			e.append(c)
		else:
			l.append(c)
	else:
		if e:
			# one last thing to try....
			s = u''.join(l) + u''.join(e)
			s = replace_gsm_doubles(s)
			if len(s) <= 160:
				return (s, u'')
		return (u''.join(l), u''.join(e))
 
	# encode using UTF-16
	l = []
	e = list(u)
	while e:
		c = e.pop(0)
		t = u''.join(l) + c
		if len(t.encode('utf16')) > 140:
			break
		l.append(c)
	return (u''.join(l), u''.join(e))
Пример #15
0
def rx_deliver_sm(pdu):
    global smpp_messages
    if not isinstance(pdu, smpplib.command.DeliverSM):
        mid = pdu.sequence
        log.debug('PDU Seq. #%s is not a DeliverSM' % pdu.sequence)
        return
    _udhi = pdu.esm_class & smpplib.consts.SMPP_GSMFEAT_UDHI
    log.info("--> RX SMS ref(%s) DataCoding (%s), TON(%s), UHDI(%s)" %
        (pdu.user_message_reference, pdu.data_coding, pdu.dest_addr_ton, _udhi))

    gsm_shift_codec = gsm0338.Codec(single_shift_decode_map=gsm0338.SINGLE_SHIFT_CHARACTER_SET_SPANISH)
    code2charset = {1:'GSM03.38', 2:'UTF-8', 4:'UTF-8', 8:'UTF-16BE'}

    try:
        log_msg = pdu.short_message.decode(code2charset[pdu.data_coding])
    except UnicodeDecodeError as ex:
        print str(ex)
        log_msg = binascii.hexlify(pdu.short_message)

    log.debug("RX SMS: [ %s ]" % log_msg)

    if int(pdu.dest_addr_ton) == smpplib.consts.SMPP_TON_INTL:
        # We cannot deliver any SMS to SMPP_TON_INTL
        #return smpplib.consts.SMPP_ESME_RSYSERR
        log.error("Unable to handle SMS for %s: SMPP_TON_INTL" % (pdu.destination_addr))
        return smpplib.consts.SMPP_ESME_RINVDSTTON
    try:
        valid_src = num.is_number_known(pdu.source_addr)
        if (not num.is_number_internal(pdu.source_addr) and
            not sub.is_authorized(pdu.source_addr, 0)):
            log.error("Unable to handle SMS from %s: Unauthorised" % (pdu.source_addr))
            return smpplib.consts.SMPP_ESME_RINVSRCADR
    except SubscriberException as ex:
        log.error("Unable to handle SMS from %s: %s" % (pdu.source_addr, ex))
        return smpplib.consts.SMPP_ESME_RINVSRCADR

    try:
        ret = check_extensions(pdu, log_msg, _udhi)
        if ret is not -1:
            return ret
    except Exception as ex:
        log.error("Extension module raises Error[%s], refusing SMS", str(ex))
        return smpplib.consts.SMPP_ESME_RSYSERR
    except ExtensionExceptionOK as ex:
        log.error("Extension module raises Error[%s], but sending OK to MS", str(ex))
        return smpplib.consts.SMPP_ESME_ROK

    if pdu.user_message_reference is None:
        log.warning("PDU has no user_message_reference.")
        pdu.user_message_reference = 0

    try:
        pdu.destination_addr = num.fivetoeleven(pdu.source_addr, pdu.destination_addr, log)
        dest_ip = num.get_current_bts(pdu.destination_addr)
    except NumberingException as ex:
        log.error("Unable to handle SMS for %s: %s" % (pdu.destination_addr, ex))
        if no_unknown_delivery == 1:
            return smpplib.consts.SMPP_ESME_RINVDSTADR
        try:
            dest_ip = num.get_site_ip_hlr(pdu.destination_addr[:6])
            if config.config['local_ip'] == dest_ip:
                return smpplib.consts.SMPP_ESME_RINVDSTADR
            log.debug('Will attempt forward to %s', dest_ip)
        except Exception as ex:
            log.error("Unable to handle SMS for %s: %s" % (pdu.destination_addr[:6], ex))
            return smpplib.consts.SMPP_ESME_RINVDSTADR

    log.debug('Registered Delivery: %s' % pdu.registered_delivery)
    log.debug('ESM Class %s' % pdu.esm_class)
    if int(pdu.esm_class) == 4:
        pdu.esm_class = 8
        log.info('--> RX Delivery Report for Uref(%s): %s ' %
                  (pdu.user_message_reference, pdu.short_message))
        pdu.short_message = ' '
    if config.config['local_ip'] == dest_ip:
        ret = local_pass_pdu(pdu)
        if pdu.esm_class != 8:
            sms.save(pdu.source_addr, pdu.destination_addr, 'SMS_LOCAL')
        return smpplib.consts.SMPP_ESME_ROK

    # SMS destination has a Webphone Prefix.
    if (hasattr(config, 'sip_central_ip_address') and
        isinstance(config.sip_central_ip_address, list) and
        config.sip_central_ip_address[0] == dest_ip):

        log.info('--> RX SMS(%s) for Webphone.', pdu.user_message_reference)

        if _udhi:
            try:
                ret = multipart(pdu)
                if not ret:
                    # We Have not got all the parts yet.
                    log.debug("Accepting Part: %s" % binascii.hexlify(pdu.short_message))
                    return smpplib.consts.SMPP_ESME_ROK
                else:
                    log.debug("Full SMS Message: %s" % ret.decode(code2charset[pdu.data_coding]))
                    pdu.short_message = ret
            except UDHError:
                # Just Accept and drop it.
                return smpplib.consts.SMPP_ESME_ROK

        if sms.webphone_sms(pdu.source_addr, pdu.destination_addr, pdu.short_message, pdu.data_coding):
            return smpplib.consts.SMPP_ESME_ROK
        else:
            return smpplib.consts.SMPP_ESME_RSYSERR

    else:
        # Pass it off to the Queue. what to do here? send it to the remote site?
        # via rapi?
        # Should we decode the entire message?
        # what if the remote site is down
        try:
            #tremote = threading.Thread(target=remote_pass_pdu)
            stat = remote_pass_pdu(pdu, dest_ip)
            if stat == smpplib.consts.SMPP_ESME_ROK and pdu.esm_class != 8:
                sms.save(pdu.source_addr, pdu.destination_addr, 'SMS_INTERNAL')
            return stat
        except Exception as e:
            log.error("exception from remote_pass_pdu %s", str(e))
            # Something bad happened
            return smpplib.consts.SMPP_ESME_RSYSERR
Пример #16
0
def rx_deliver_sm(pdu):
    global smpp_messages
    if not isinstance(pdu, smpplib.command.DeliverSM):
        mid = pdu.sequence
        log.debug('PDU Seq. #%s is not a DeliverSM' % pdu.sequence)
        return
    _udhi = pdu.esm_class & smpplib.consts.SMPP_GSMFEAT_UDHI
    log.info("--> RX SMS ref(%s) DataCoding (%s), TON(%s), UHDI(%s)" %
             (pdu.user_message_reference, pdu.data_coding, pdu.dest_addr_ton,
              _udhi))

    gsm_shift_codec = gsm0338.Codec(
        single_shift_decode_map=gsm0338.SINGLE_SHIFT_CHARACTER_SET_SPANISH)
    code2charset = {1: 'GSM03.38', 2: 'UTF-8', 4: 'UTF-8', 8: 'UTF-16BE'}

    _start = 0
    if _udhi:
        try:
            _udh_length = ord(pdu.short_message[:1])
            _start = _udh_length + 1
            udh = parse_udh(pdu.short_message[:_udh_length + 1])
            if udh is False:
                log.warning('Accept and drop message.. %s',
                            binascii.hexlify(pdu.short_message))
                return smpplib.consts.SMPP_ESME_ROK
            '''
            if udh['part_num'] == 1:
                smpp_messages[udh['csms_ref']]=[]
            log.debug('Part %s of %s' % (udh['part_num'], udh['parts']))
            smpp_messages[udh['csms_ref']].append(pdu.short_message[_start:])
            if udh['part_num'] == udh['parts']:
                _final = ''.join(smpp_messages[udh['csms_ref']])
                smpp_messages[udh['csms_ref']] = None
                log.debug("Full SMS Message: %s" % _final.decode(code2charset[pdu.data_coding]))
                #local_submit_one('LOCAL_TEST', pdu.destination_addr, _final.decode(code2charset[pdu.data_coding]))
            '''
        except Exception as ex:
            log.debug("UDHI: Other Exception: %s", str(ex))
            template = "An exception of type {0} occurred. Arguments:\n{1!r}"
            message = template.format(type(ex).__name__, ex.args)
            log.debug(message)
            return smpplib.consts.SMPP_ESME_RSYSERR

    try:
        log_msg = pdu.short_message[_start:].decode(
            code2charset[pdu.data_coding])
    except UnicodeDecodeError as ex:
        log_msg = binascii.hexlify(pdu.short_message[_start:])
        print str(ex)

    log.debug("RX SMS: [ %s ]" % log_msg)
    if int(pdu.dest_addr_ton) == smpplib.consts.SMPP_TON_INTL:
        # We cannot deliver any SMS to SMPP_TON_INTL
        #return smpplib.consts.SMPP_ESME_RSYSERR
        log.error("Unable to handle SMS for %s: SMPP_TON_INTL" %
                  (pdu.destination_addr))
        return smpplib.consts.SMPP_ESME_RINVDSTTON
    try:
        valid_src = num.is_number_known(pdu.source_addr)
        if (not num.is_number_internal(pdu.source_addr)
                and not sub.is_authorized(pdu.source_addr, 0)):
            log.error("Unable to handle SMS from %s: Unauthorised" %
                      (pdu.source_addr))
            return smpplib.consts.SMPP_ESME_RINVSRCADR
    except SubscriberException as ex:
        log.error("Unable to handle SMS from %s: %s" % (pdu.source_addr, ex))
        return smpplib.consts.SMPP_ESME_RINVSRCADR
    try:
        if check_extensions(pdu):
            return smpplib.consts.SMPP_ESME_ROK
    except Exception as ex:
        log.error(str(ex))
        return smpplib.consts.SMPP_ESME_RSYSERR
    if pdu.user_message_reference is None:
        log.warning("PDU has no user_message_reference.")
        pdu.user_message_reference = 0
    try:
        pdu.destination_addr = num.fivetoeleven(pdu.source_addr,
                                                pdu.destination_addr, log)
        dest_ip = num.get_current_bts(pdu.destination_addr)
    except NumberingException as ex:
        log.error("Unable to handle SMS for %s: %s" %
                  (pdu.destination_addr, ex))
        if no_unknown_delivery == 1:
            return smpplib.consts.SMPP_ESME_RINVDSTADR
        try:
            dest_ip = num.get_site_ip_hlr(pdu.destination_addr[:6])
            if config.config['local_ip'] == dest_ip:
                return smpplib.consts.SMPP_ESME_RINVDSTADR
            log.debug('Will attempt forward to %s', dest_ip)
        except Exception as ex:
            log.error("Unable to handle SMS for %s: %s" %
                      (pdu.destination_addr[:6], ex))
            return smpplib.consts.SMPP_ESME_RINVDSTADR

    log.debug('Registered Delivery: %s' % pdu.registered_delivery)
    log.debug('ESM Class %s' % pdu.esm_class)
    if int(pdu.esm_class) == 4:
        pdu.esm_class = 8
        log.info('--> RX Delivery Report for Uref(%s): %s ' %
                 (pdu.user_message_reference, pdu.short_message))
        pdu.short_message = ' '
    if config.config['local_ip'] == dest_ip:
        ret = local_pass_pdu(pdu)
        if pdu.esm_class != 8:
            sms.save(pdu.source_addr, pdu.destination_addr, 'SMS_LOCAL')
        return smpplib.consts.SMPP_ESME_ROK
    if (hasattr(config, 'sip_central_ip_address')
            and isinstance(config.sip_central_ip_address, list)
            and config.sip_central_ip_address[0] == dest_ip):
        log.info('--> RX SMS for Webphone(%s): %s ' %
                 (pdu.user_message_reference, pdu.short_message))
        if sms.webphone_sms(pdu.source_addr, pdu.destination_addr,
                            pdu.short_message, pdu.data_coding):
            return smpplib.consts.SMPP_ESME_ROK
        else:
            return smpplib.consts.SMPP_ESME_RSYSERR
    else:
        # Pass it off to the Queue. what to do here? send it to the remote site?
        # via rapi?
        # Should we decode the entire message?
        # what if the remote site is down
        try:
            #tremote = threading.Thread(target=remote_pass_pdu)
            stat = remote_pass_pdu(pdu, dest_ip)
            if stat == smpplib.consts.SMPP_ESME_ROK and pdu.esm_class != 8:
                sms.save(pdu.source_addr, pdu.destination_addr, 'SMS_INTERNAL')
            return stat
        except Exception as e:
            log.error("exception from remote_pass_pdu %s", str(e))
            # Something bad happened
            return smpplib.consts.SMPP_ESME_RSYSERR