Example #1
0
File: mica.py Project: lynnUg/vumi
class DeliverShortMessageProcessor(default.DeliverShortMessageProcessor):

    CONFIG_CLASS = DeliverShortMessageProcessorConfig

    def __init__(self, transport, config):
        super(DeliverShortMessageProcessor, self).__init__(transport, config)
        self.transport = transport
        self.redis = transport.redis
        self.config = self.CONFIG_CLASS(config, static=True)
        self.session_manager = SessionManager(
            self.redis, max_session_length=self.config.max_session_length)

    @inlineCallbacks
    def handle_deliver_sm_ussd(self, pdu, pdu_params, pdu_opts):
        service_op = pdu_opts['ussd_service_op']
        mica_session_identifier = pdu_opts['user_message_reference']
        vumi_session_identifier = make_vumi_session_identifier(
            pdu_params['source_addr'], mica_session_identifier)

        session_event = 'close'
        if service_op == '01':
            # PSSR request. Let's assume it means a new session.
            session_event = 'new'
            ussd_code = pdu_params['short_message']
            content = None

            yield self.session_manager.create_session(vumi_session_identifier,
                                                      ussd_code=ussd_code)

        elif service_op == '17':
            # PSSR response. This means session end.
            session_event = 'close'

            session = yield self.session_manager.load_session(
                vumi_session_identifier)
            ussd_code = session['ussd_code']
            content = None

            yield self.session_manager.clear_session(vumi_session_identifier)

        else:
            session_event = 'continue'

            session = yield self.session_manager.load_session(
                vumi_session_identifier)
            ussd_code = session['ussd_code']
            content = pdu_params['short_message']

        # This is stashed on the message and available when replying
        # with a `submit_sm`
        session_info = {
            'session_identifier': mica_session_identifier,
        }

        decoded_msg = self.dcs_decode(content, pdu_params['data_coding'])

        result = yield self.handle_short_message_content(
            source_addr=pdu_params['source_addr'],
            destination_addr=ussd_code,
            short_message=decoded_msg,
            message_type='ussd',
            session_event=session_event,
            session_info=session_info)
        returnValue(result)
Example #2
0
File: mica.py Project: lynnUg/vumi
class SubmitShortMessageProcessor(default.SubmitShortMessageProcessor):

    CONFIG_CLASS = SubmitShortMessageProcessorConfig

    def __init__(self, transport, config):
        super(SubmitShortMessageProcessor, self).__init__(transport, config)
        self.transport = transport
        self.redis = transport.redis
        self.config = self.CONFIG_CLASS(config, static=True)
        self.session_manager = SessionManager(
            self.redis, max_session_length=self.config.max_session_length)

    @inlineCallbacks
    def handle_outbound_message(self, message, protocol):
        to_addr = message['to_addr']
        from_addr = message['from_addr']
        text = message['content']
        vumi_message_id = message['message_id']

        session_event = message['session_event']
        transport_type = message['transport_type']
        optional_parameters = {}

        if transport_type == 'ussd':
            continue_session = (session_event !=
                                TransportUserMessage.SESSION_CLOSE)
            session_info = message['transport_metadata'].get(
                'session_info', {})
            mica_session_identifier = session_info.get('session_identifier',
                                                       '')
            vumi_session_identifier = make_vumi_session_identifier(
                to_addr, mica_session_identifier)

            optional_parameters.update({
                'ussd_service_op': ('02' if continue_session else '17'),
                'user_message_reference':
                (str(mica_session_identifier).zfill(2)),
            })

            if not continue_session:
                yield self.session_manager.clear_session(
                    vumi_session_identifier)

        if self.config.send_long_messages:
            resp = yield protocol.submit_sm_long(
                vumi_message_id,
                to_addr.encode('ascii'),
                long_message=text.encode(self.config.submit_sm_encoding),
                data_coding=self.config.submit_sm_data_coding,
                source_addr=from_addr.encode('ascii'),
                optional_parameters=optional_parameters,
            )

        elif self.config.send_multipart_sar:
            resp = yield protocol.submit_csm_sar(
                vumi_message_id,
                to_addr.encode('ascii'),
                short_message=text.encode(self.config.submit_sm_encoding),
                data_coding=self.config.submit_sm_data_coding,
                source_addr=from_addr.encode('ascii'),
                optional_parameters=optional_parameters,
            )

        elif self.config.send_multipart_udh:
            resp = yield protocol.submit_csm_udh(
                vumi_message_id,
                to_addr.encode('ascii'),
                short_message=text.encode(self.config.submit_sm_encoding),
                data_coding=self.config.submit_sm_data_coding,
                source_addr=from_addr.encode('ascii'),
                optional_parameters=optional_parameters,
            )
        else:
            resp = yield protocol.submit_sm(
                vumi_message_id,
                to_addr.encode('ascii'),
                short_message=text.encode(self.config.submit_sm_encoding),
                data_coding=self.config.submit_sm_data_coding,
                source_addr=from_addr.encode('ascii'),
                optional_parameters=optional_parameters,
            )

        returnValue(resp)
Example #3
0
class SubmitShortMessageProcessor(default.SubmitShortMessageProcessor):

    CONFIG_CLASS = SubmitShortMessageProcessorConfig

    # NOTE: these values are hexidecimal because of python-smpp encoding
    #       quirkiness
    ussd_service_op_map = {
        'continue': '02',
        'close': '17',  # end
    }

    def __init__(self, transport, config):
        super(SubmitShortMessageProcessor, self).__init__(transport, config)
        self.transport = transport
        self.redis = transport.redis
        self.config = self.CONFIG_CLASS(config, static=True)
        self.session_manager = SessionManager(
            self.redis, max_session_length=self.config.max_session_length)

    @inlineCallbacks
    def handle_outbound_message(self, message, service):
        to_addr = message['to_addr']
        from_addr = message['from_addr']
        text = message['content']
        if text is None:
            text = u""
        vumi_message_id = message['message_id']

        session_event = message['session_event']
        transport_type = message['transport_type']
        optional_parameters = {}

        if transport_type == 'ussd':
            continue_session = (
                session_event != TransportUserMessage.SESSION_CLOSE)
            session_info = message['transport_metadata'].get(
                'session_info', {})
            mica_session_identifier = session_info.get(
                'session_identifier', '')
            vumi_session_identifier = make_vumi_session_identifier(
                to_addr, mica_session_identifier)

            service_op = self.ussd_service_op_map[('continue'
                                                   if continue_session
                                                   else 'close')]
            optional_parameters.update({
                'ussd_service_op': service_op,
                'user_message_reference': (
                    str(mica_session_identifier).zfill(2)),
            })

            if not continue_session:
                yield self.session_manager.clear_session(
                    vumi_session_identifier)

        resp = yield self.send_short_message(
            service,
            vumi_message_id,
            to_addr.encode('ascii'),
            text.encode(self.config.submit_sm_encoding),
            data_coding=self.config.submit_sm_data_coding,
            source_addr=from_addr.encode('ascii'),
            optional_parameters=optional_parameters)

        returnValue(resp)
Example #4
0
class DeliverShortMessageProcessor(default.DeliverShortMessageProcessor):

    CONFIG_CLASS = DeliverShortMessageProcessorConfig

    # NOTE: these keys are hexidecimal because of python-smpp encoding
    #       quirkiness
    ussd_service_op_map = {
        '01': 'new',
        '12': 'continue',
        '81': 'close',  # user abort
    }

    def __init__(self, transport, config):
        super(DeliverShortMessageProcessor, self).__init__(transport, config)
        self.transport = transport
        self.log = transport.log
        self.redis = transport.redis
        self.config = self.CONFIG_CLASS(config, static=True)
        self.session_manager = SessionManager(
            self.redis, max_session_length=self.config.max_session_length)

    @inlineCallbacks
    def handle_deliver_sm_ussd(self, pdu, pdu_params, pdu_opts):
        service_op = pdu_opts['ussd_service_op']
        mica_session_identifier = pdu_opts['user_message_reference']
        vumi_session_identifier = make_vumi_session_identifier(
            pdu_params['source_addr'], mica_session_identifier)

        session_event = self.ussd_service_op_map.get(service_op)

        if session_event == 'new':
            # PSSR request. Let's assume it means a new session.
            ussd_code = pdu_params['short_message']
            content = None

            yield self.session_manager.create_session(
                vumi_session_identifier, ussd_code=ussd_code)

        elif session_event == 'close':
            session = yield self.session_manager.load_session(
                vumi_session_identifier)
            ussd_code = session['ussd_code']
            content = None

            yield self.session_manager.clear_session(vumi_session_identifier)

        else:
            if session_event != 'continue':
                self.log.warning((
                    'Received unknown %r ussd_service_op, assuming continue.')
                    % (service_op,))
                session_event = 'continue'

            session = yield self.session_manager.load_session(
                vumi_session_identifier)
            ussd_code = session['ussd_code']
            content = self.dcs_decode(
                pdu_params['short_message'], pdu_params['data_coding'])

        # This is stashed on the message and available when replying
        # with a `submit_sm`
        session_info = {
            'ussd_service_op': service_op,
            'session_identifier': mica_session_identifier,
        }

        result = yield self.handle_short_message_content(
            source_addr=pdu_params['source_addr'],
            destination_addr=ussd_code,
            short_message=content,
            message_type='ussd',
            session_event=session_event,
            session_info=session_info)
        returnValue(result)
Example #5
0
class SubmitShortMessageProcessor(default.SubmitShortMessageProcessor):

    CONFIG_CLASS = SubmitShortMessageProcessorConfig

    # NOTE: these values are hexidecimal because of python-smpp encoding
    #       quirkiness
    ussd_service_op_map = {
        'continue': '02',
        'close': '17',  # end
    }

    def __init__(self, transport, config):
        super(SubmitShortMessageProcessor, self).__init__(transport, config)
        self.transport = transport
        self.redis = transport.redis
        self.config = self.CONFIG_CLASS(config, static=True)
        self.session_manager = SessionManager(
            self.redis, max_session_length=self.config.max_session_length)

    @inlineCallbacks
    def handle_outbound_message(self, message, protocol):
        to_addr = message['to_addr']
        from_addr = message['from_addr']
        text = message['content']
        if text is None:
            text = u""
        vumi_message_id = message['message_id']

        session_event = message['session_event']
        transport_type = message['transport_type']
        optional_parameters = {}

        if transport_type == 'ussd':
            continue_session = (session_event !=
                                TransportUserMessage.SESSION_CLOSE)
            session_info = message['transport_metadata'].get(
                'session_info', {})
            sixdee_session_identifier = session_info.get(
                'session_identifier', '')
            vumi_session_identifier = make_vumi_session_identifier(
                to_addr, sixdee_session_identifier)

            its_session_info = (int(sixdee_session_identifier, 16)
                                | int(not continue_session))

            service_op = self.ussd_service_op_map[(
                'continue' if continue_session else 'close')]
            optional_parameters.update({
                'ussd_service_op':
                service_op,
                'its_session_info':
                "%04x" % (its_session_info, )
            })

            if not continue_session:
                yield self.session_manager.clear_session(
                    vumi_session_identifier)

        if self.config.send_long_messages:
            resp = yield protocol.submit_sm_long(
                vumi_message_id,
                to_addr.encode('ascii'),
                long_message=text.encode(self.config.submit_sm_encoding),
                data_coding=self.config.submit_sm_data_coding,
                source_addr=from_addr.encode('ascii'),
                optional_parameters=optional_parameters,
            )

        elif self.config.send_multipart_sar:
            resp = yield protocol.submit_csm_sar(
                vumi_message_id,
                to_addr.encode('ascii'),
                short_message=text.encode(self.config.submit_sm_encoding),
                data_coding=self.config.submit_sm_data_coding,
                source_addr=from_addr.encode('ascii'),
                optional_parameters=optional_parameters,
            )

        elif self.config.send_multipart_udh:
            resp = yield protocol.submit_csm_udh(
                vumi_message_id,
                to_addr.encode('ascii'),
                short_message=text.encode(self.config.submit_sm_encoding),
                data_coding=self.config.submit_sm_data_coding,
                source_addr=from_addr.encode('ascii'),
                optional_parameters=optional_parameters,
            )
        else:
            resp = yield protocol.submit_sm(
                vumi_message_id,
                to_addr.encode('ascii'),
                short_message=text.encode(self.config.submit_sm_encoding),
                data_coding=self.config.submit_sm_data_coding,
                source_addr=from_addr.encode('ascii'),
                optional_parameters=optional_parameters,
            )

        returnValue(resp)
Example #6
0
class DeliverShortMessageProcessor(default.DeliverShortMessageProcessor):

    CONFIG_CLASS = DeliverShortMessageProcessorConfig

    # NOTE: these keys are hexidecimal because of python-smpp encoding
    #       quirkiness
    ussd_service_op_map = {
        '01': 'new',
        '12': 'continue',
        '81': 'close',  # user abort
    }

    def __init__(self, transport, config):
        super(DeliverShortMessageProcessor, self).__init__(transport, config)
        self.transport = transport
        self.redis = transport.redis
        self.config = self.CONFIG_CLASS(config, static=True)
        self.session_manager = SessionManager(
            self.redis, max_session_length=self.config.max_session_length)

    @inlineCallbacks
    def handle_deliver_sm_ussd(self, pdu, pdu_params, pdu_opts):
        service_op = pdu_opts['ussd_service_op']

        # 6D uses its_session_info as follows:
        #
        # * First 15 bit: dialog id (i.e. session id)
        # * Last bit: end session (1 to end, 0 to continue)

        its_session_number = int(pdu_opts['its_session_info'], 16)
        end_session = bool(its_session_number % 2)
        sixdee_session_identifier = "%04x" % (its_session_number & 0xfffe)
        vumi_session_identifier = make_vumi_session_identifier(
            pdu_params['source_addr'], sixdee_session_identifier)

        if end_session:
            session_event = 'close'
        else:
            session_event = self.ussd_service_op_map.get(service_op)

        if session_event == 'new':
            # PSSR request. Let's assume it means a new session.
            ussd_code = pdu_params['short_message']
            content = None

            yield self.session_manager.create_session(vumi_session_identifier,
                                                      ussd_code=ussd_code)

        elif session_event == 'close':
            session = yield self.session_manager.load_session(
                vumi_session_identifier)
            ussd_code = session['ussd_code']
            content = None

            yield self.session_manager.clear_session(vumi_session_identifier)

        else:
            if session_event != 'continue':
                log.warning(('Received unknown %r ussd_service_op, '
                             'assuming continue.') % (service_op, ))
                session_event = 'continue'

            session = yield self.session_manager.load_session(
                vumi_session_identifier)
            ussd_code = session['ussd_code']
            content = pdu_params['short_message']

        # This is stashed on the message and available when replying
        # with a `submit_sm`
        session_info = {
            'ussd_service_op': service_op,
            'session_identifier': sixdee_session_identifier,
        }

        decoded_msg = self.dcs_decode(content, pdu_params['data_coding'])

        result = yield self.handle_short_message_content(
            source_addr=pdu_params['source_addr'],
            destination_addr=ussd_code,
            short_message=decoded_msg,
            message_type='ussd',
            session_event=session_event,
            session_info=session_info)
        returnValue(result)
Example #7
0
class SubmitShortMessageProcessor(default.SubmitShortMessageProcessor):

    CONFIG_CLASS = SubmitShortMessageProcessorConfig

    # NOTE: these values are hexidecimal because of python-smpp encoding
    #       quirkiness
    ussd_service_op_map = {
        'continue': '02',
        'close': '17',  # end
    }

    def __init__(self, transport, config):
        super(SubmitShortMessageProcessor, self).__init__(transport, config)
        self.transport = transport
        self.redis = transport.redis
        self.config = self.CONFIG_CLASS(config, static=True)
        self.session_manager = SessionManager(
            self.redis, max_session_length=self.config.max_session_length)

    @inlineCallbacks
    def handle_outbound_message(self, message, protocol):
        to_addr = message['to_addr']
        from_addr = message['from_addr']
        text = message['content']
        if text is None:
            text = u""
        vumi_message_id = message['message_id']

        session_event = message['session_event']
        transport_type = message['transport_type']
        optional_parameters = {}

        if transport_type == 'ussd':
            continue_session = (
                session_event != TransportUserMessage.SESSION_CLOSE)
            session_info = message['transport_metadata'].get(
                'session_info', {})
            sixdee_session_identifier = session_info.get(
                'session_identifier', '')
            vumi_session_identifier = make_vumi_session_identifier(
                to_addr, sixdee_session_identifier)

            its_session_info = (
                int(sixdee_session_identifier, 16) |
                int(not continue_session))

            service_op = self.ussd_service_op_map[('continue'
                                                   if continue_session
                                                   else 'close')]
            optional_parameters.update({
                'ussd_service_op': service_op,
                'its_session_info': "%04x" % (its_session_info,)
            })

            if not continue_session:
                yield self.session_manager.clear_session(
                    vumi_session_identifier)

        if self.config.send_long_messages:
            resp = yield protocol.submit_sm_long(
                vumi_message_id,
                to_addr.encode('ascii'),
                long_message=text.encode(self.config.submit_sm_encoding),
                data_coding=self.config.submit_sm_data_coding,
                source_addr=from_addr.encode('ascii'),
                optional_parameters=optional_parameters,
            )

        elif self.config.send_multipart_sar:
            resp = yield protocol.submit_csm_sar(
                vumi_message_id,
                to_addr.encode('ascii'),
                short_message=text.encode(self.config.submit_sm_encoding),
                data_coding=self.config.submit_sm_data_coding,
                source_addr=from_addr.encode('ascii'),
                optional_parameters=optional_parameters,
            )

        elif self.config.send_multipart_udh:
            resp = yield protocol.submit_csm_udh(
                vumi_message_id,
                to_addr.encode('ascii'),
                short_message=text.encode(self.config.submit_sm_encoding),
                data_coding=self.config.submit_sm_data_coding,
                source_addr=from_addr.encode('ascii'),
                optional_parameters=optional_parameters,
            )
        else:
            resp = yield protocol.submit_sm(
                vumi_message_id,
                to_addr.encode('ascii'),
                short_message=text.encode(self.config.submit_sm_encoding),
                data_coding=self.config.submit_sm_data_coding,
                source_addr=from_addr.encode('ascii'),
                optional_parameters=optional_parameters,
            )

        returnValue(resp)
Example #8
0
class DeliverShortMessageProcessor(default.DeliverShortMessageProcessor):

    CONFIG_CLASS = DeliverShortMessageProcessorConfig

    # NOTE: these keys are hexidecimal because of python-smpp encoding
    #       quirkiness
    ussd_service_op_map = {
        '01': 'new',
        '12': 'continue',
        '81': 'close',  # user abort
    }

    def __init__(self, transport, config):
        super(DeliverShortMessageProcessor, self).__init__(transport, config)
        self.transport = transport
        self.redis = transport.redis
        self.config = self.CONFIG_CLASS(config, static=True)
        self.session_manager = SessionManager(
            self.redis, max_session_length=self.config.max_session_length)

    @inlineCallbacks
    def handle_deliver_sm_ussd(self, pdu, pdu_params, pdu_opts):
        service_op = pdu_opts['ussd_service_op']

        # 6D uses its_session_info as follows:
        #
        # * First 15 bit: dialog id (i.e. session id)
        # * Last bit: end session (1 to end, 0 to continue)

        its_session_number = int(pdu_opts['its_session_info'], 16)
        end_session = bool(its_session_number % 2)
        sixdee_session_identifier = "%04x" % (its_session_number & 0xfffe)
        vumi_session_identifier = make_vumi_session_identifier(
            pdu_params['source_addr'], sixdee_session_identifier)

        if end_session:
            session_event = 'close'
        else:
            session_event = self.ussd_service_op_map.get(service_op)

        if session_event == 'new':
            # PSSR request. Let's assume it means a new session.
            ussd_code = pdu_params['short_message']
            content = None

            yield self.session_manager.create_session(
                vumi_session_identifier, ussd_code=ussd_code)

        elif session_event == 'close':
            session = yield self.session_manager.load_session(
                vumi_session_identifier)
            ussd_code = session['ussd_code']
            content = None

            yield self.session_manager.clear_session(vumi_session_identifier)

        else:
            if session_event != 'continue':
                log.warning(('Received unknown %r ussd_service_op, '
                             'assuming continue.') % (service_op,))
                session_event = 'continue'

            session = yield self.session_manager.load_session(
                vumi_session_identifier)
            ussd_code = session['ussd_code']
            content = pdu_params['short_message']

        # This is stashed on the message and available when replying
        # with a `submit_sm`
        session_info = {
            'ussd_service_op': service_op,
            'session_identifier': sixdee_session_identifier,
        }

        decoded_msg = self.dcs_decode(content,
                                      pdu_params['data_coding'])

        result = yield self.handle_short_message_content(
            source_addr=pdu_params['source_addr'],
            destination_addr=ussd_code,
            short_message=decoded_msg,
            message_type='ussd',
            session_event=session_event,
            session_info=session_info)
        returnValue(result)
Example #9
0
class TwilioAPIWorker(ApplicationWorker):
    """Emulates the Twilio API to use vumi as if it was Twilio"""
    CONFIG_CLASS = TwilioAPIConfig

    @inlineCallbacks
    def setup_application(self):
        """Application specific setup"""
        self.app_config = self.get_static_config()
        self.server = TwilioAPIServer(self, self.app_config.api_version)
        path = os.path.join(
            self.app_config.web_path, self.app_config.api_version)
        self.webserver = self.start_web_resources([
            (self.server.app.resource(), path)],
            self.app_config.web_port)
        redis = yield TxRedisManager.from_config(self.app_config.redis_manager)
        self.session_manager = SessionManager(
            redis, self.app_config.redis_timeout)
        self.session_lookup = SessionIDLookup(
            redis, self.app_config.redis_timeout,
            self.app_config.session_lookup_namespace)

    @inlineCallbacks
    def teardown_application(self):
        """Clean-up of setup done in `setup_application`"""
        yield self.webserver.loseConnection()
        yield self.session_manager.stop()

    def _http_request(self, url='', method='GET', data={}):
        return treq.request(method, url, persistent=False, data=data)

    def _request_data_from_session(self, session):
        return {
            'CallSid': session['CallId'],
            'AccountSid': session['AccountSid'],
            'From': session['From'],
            'To': session['To'],
            'CallStatus': session['Status'],
            'ApiVersion': self.app_config.api_version,
            'Direction': session['Direction'],
        }

    @inlineCallbacks
    def _get_twiml_from_client(self, session, data=None):
        if data is None:
            data = self._request_data_from_session(session)
        twiml_raw = yield self._http_request(
            session['Url'], session['Method'], data)
        if twiml_raw.code < 200 or twiml_raw.code >= 300:
            twiml_raw = yield self._http_request(
                session['FallbackUrl'], session['FallbackMethod'], data)
        twiml_raw = yield twiml_raw.content()
        twiml_parser = TwiMLParser(session['Url'])
        returnValue(twiml_parser.parse(twiml_raw))

    @inlineCallbacks
    def _handle_connected_call(
            self, session_id, session, status='in-progress', twiml=None):
        # TODO: Support sending ForwardedFrom parameter
        # TODO: Support sending CallerName parameter
        # TODO: Support sending geographic data parameters
        session['Status'] = status
        self.session_manager.save_session(session_id, session)
        if twiml is None:
            twiml = yield self._get_twiml_from_client(session)
        for verb in twiml:
            if verb.name == "Play":
                # TODO: Support loop and digit attributes
                yield self._send_message(verb.nouns[0], session)
            elif verb.name == "Hangup":
                yield self._send_message(
                    None, session, TransportUserMessage.SESSION_CLOSE)
                yield self.session_manager.clear_session(session_id)
                break
            elif verb.name == "Gather":
                # TODO: Support timeout and numDigits attributes
                msgs = []
                for subverb in verb.nouns:
                    # TODO: Support Say and Pause subverbs
                    if subverb.name == "Play":
                        msgs.append({'speech_url': subverb.nouns[0]})
                session['Gather_Action'] = verb.attributes['action']
                session['Gather_Method'] = verb.attributes['method']
                yield self.session_manager.save_session(session_id, session)
                if len(msgs) == 0:
                    msgs.append({'speech_url': None})
                msgs[-1]['wait_for'] = verb.attributes['finishOnKey']
                for msg in msgs:
                    yield self._send_message(
                        msg['speech_url'], session,
                        wait_for=msg.get('wait_for'))
                break

    def _send_message(self, url, session, session_event=None, wait_for=None):
        helper_metadata = {'voice': {}}
        if url is not None:
            helper_metadata['voice']['speech_url'] = url
        if wait_for is not None:
            helper_metadata['voice']['wait_for'] = wait_for

        return self.send_to(
            session['To'], None,
            from_addr=session['From'],
            session_event=session_event,
            to_addr_type=TransportUserMessage.AT_MSISDN,
            from_addr_type=TransportUserMessage.AT_MSISDN,
            helper_metadata=helper_metadata)

    @inlineCallbacks
    def consume_user_message(self, message):
        # At the moment there is no way to determine whether or not a message
        # is the result of a wait_for or just a single digit, so if the Gather
        # data exists inside the current session data, then we assume that it
        # is the result of a Gather
        # TODO: Fix this
        session = yield self.session_manager.load_session(message['from_addr'])
        if session.get('Gather_Action') and session.get('Gather_Method'):
            data = self._request_data_from_session(session)
            data['Digits'] = message['content']
            twiml = yield self._get_twiml_from_client({
                'Url': session['Gather_Action'],
                'Method': session['Gather_Method'],
                'Fallback_Url': None,
                'Fallback_Method': None, },
                data=data)
            yield self._handle_connected_call(
                message['from_addr'], session, twiml=twiml)

    @inlineCallbacks
    def consume_ack(self, event):
        message_id = event['user_message_id']
        session_id = yield self.session_lookup.get_address(message_id)
        yield self.session_lookup.delete_id(message_id)
        session = yield self.session_manager.load_session(session_id)

        if session['Status'] == 'queued':
            yield self._handle_connected_call(session_id, session)

    @inlineCallbacks
    def consume_nack(self, event):
        message_id = event['user_message_id']
        session_id = yield self.session_lookup.get_address(message_id)
        yield self.session_lookup.delete_id(message_id)
        session = yield self.session_manager.load_session(session_id)

        if session['Status'] == 'queued':
            yield self._handle_connected_call(
                session_id, session, status='failed')

    @inlineCallbacks
    def new_session(self, message):
        yield self.session_lookup.set_id(
            message['message_id'], message['from_addr'])
        config = yield self.get_config(message)
        session = {
            'CallId': self.server._get_sid(),
            'AccountSid': self.server._get_sid(),
            'From': message['from_addr'],
            'To': message['to_addr'],
            'Status': 'in-progress',
            'Direction': 'inbound',
            'Url': config.client_path,
            'Method': config.client_method,
            'StatusCallback': config.status_callback_path,
            'StatusCallbackMethod': config.status_callback_method,
        }
        yield self.session_manager.create_session(
            message['from_addr'], **session)

        twiml = yield self._get_twiml_from_client(session)
        for verb in twiml:
            if verb.name == "Play":
                yield self.reply_to(message, None, helper_metadata={
                    'voice': {
                        'speech_url': verb.nouns[0],
                        }
                    })
            elif verb.name == "Hangup":
                yield self.reply_to(
                    message, None,
                    session_event=TransportUserMessage.SESSION_CLOSE)
                yield self.session_manager.clear_session(message['from_addr'])
                break
            elif verb.name == "Gather":
                # TODO: Support timeout and numDigits attributes
                msgs = []
                for subverb in verb.nouns:
                    # TODO: Support Say and Pause subverbs
                    if subverb.name == "Play":
                        msgs.append({'speech_url': subverb.nouns[0]})
                session['Gather_Action'] = verb.attributes['action']
                session['Gather_Method'] = verb.attributes['method']
                yield self.session_manager.save_session(
                    message['from_addr'], session)
                if len(msgs) == 0:
                    msgs.append({'speech_url': None})
                msgs[-1]['wait_for'] = verb.attributes['finishOnKey']
                for msg in msgs:
                    yield self.reply_to(message, None, helper_metadata={
                        'voice': {
                            'speech_url': msg.get('speech_url'),
                            'wait_for': msg.get('wait_for'),
                        }})
                break

    @inlineCallbacks
    def close_session(self, message):
        # TODO: Implement call duration parameters
        # TODO: Implement recording parameters
        session = yield self.session_manager.load_session(message['from_addr'])
        yield self.session_manager.clear_session(message['from_addr'])
        url = session.get('StatusCallback')

        if url and url != 'None':
            session['Status'] = 'completed'
            data = self._request_data_from_session(session)
            yield self._http_request(
                session['StatusCallback'], session['StatusCallbackMethod'],
                data)
Example #10
0
File: mica.py Project: komuW/vumi
class SubmitShortMessageProcessor(default.SubmitShortMessageProcessor):

    CONFIG_CLASS = SubmitShortMessageProcessorConfig

    def __init__(self, transport, config):
        super(SubmitShortMessageProcessor, self).__init__(transport, config)
        self.transport = transport
        self.redis = transport.redis
        self.config = self.CONFIG_CLASS(config, static=True)
        self.session_manager = SessionManager(
            self.redis, max_session_length=self.config.max_session_length)

    @inlineCallbacks
    def handle_outbound_message(self, message, protocol):
        to_addr = message['to_addr']
        from_addr = message['from_addr']
        text = message['content']
        vumi_message_id = message['message_id']

        session_event = message['session_event']
        transport_type = message['transport_type']
        optional_parameters = {}

        if transport_type == 'ussd':
            continue_session = (
                session_event != TransportUserMessage.SESSION_CLOSE)
            session_info = message['transport_metadata'].get(
                'session_info', {})
            mica_session_identifier = session_info.get(
                'session_identifier', '')
            vumi_session_identifier = make_vumi_session_identifier(
                to_addr, mica_session_identifier)

            optional_parameters.update({
                'ussd_service_op': ('02' if continue_session else '17'),
                'user_message_reference': (
                    str(mica_session_identifier).zfill(2)),
            })

            if not continue_session:
                yield self.session_manager.clear_session(
                    vumi_session_identifier)

        if self.config.send_long_messages:
            resp = yield protocol.submit_sm_long(
                vumi_message_id,
                to_addr.encode('ascii'),
                long_message=text.encode(self.config.submit_sm_encoding),
                data_coding=self.config.submit_sm_data_coding,
                source_addr=from_addr.encode('ascii'),
                optional_parameters=optional_parameters,
            )

        elif self.config.send_multipart_sar:
            resp = yield protocol.submit_csm_sar(
                vumi_message_id,
                to_addr.encode('ascii'),
                short_message=text.encode(self.config.submit_sm_encoding),
                data_coding=self.config.submit_sm_data_coding,
                source_addr=from_addr.encode('ascii'),
                optional_parameters=optional_parameters,
            )

        elif self.config.send_multipart_udh:
            resp = yield protocol.submit_csm_udh(
                vumi_message_id,
                to_addr.encode('ascii'),
                short_message=text.encode(self.config.submit_sm_encoding),
                data_coding=self.config.submit_sm_data_coding,
                source_addr=from_addr.encode('ascii'),
                optional_parameters=optional_parameters,
            )
        else:
            resp = yield protocol.submit_sm(
                vumi_message_id,
                to_addr.encode('ascii'),
                short_message=text.encode(self.config.submit_sm_encoding),
                data_coding=self.config.submit_sm_data_coding,
                source_addr=from_addr.encode('ascii'),
                optional_parameters=optional_parameters,
            )

        returnValue(resp)
Example #11
0
File: mica.py Project: komuW/vumi
class DeliverShortMessageProcessor(default.DeliverShortMessageProcessor):

    CONFIG_CLASS = DeliverShortMessageProcessorConfig

    def __init__(self, transport, config):
        super(DeliverShortMessageProcessor, self).__init__(transport, config)
        self.transport = transport
        self.redis = transport.redis
        self.config = self.CONFIG_CLASS(config, static=True)
        self.session_manager = SessionManager(
            self.redis, max_session_length=self.config.max_session_length)

    @inlineCallbacks
    def handle_deliver_sm_ussd(self, pdu, pdu_params, pdu_opts):
        service_op = pdu_opts['ussd_service_op']
        mica_session_identifier = pdu_opts['user_message_reference']
        vumi_session_identifier = make_vumi_session_identifier(
            pdu_params['source_addr'], mica_session_identifier)

        session_event = 'close'
        if service_op == '01':
            # PSSR request. Let's assume it means a new session.
            session_event = 'new'
            ussd_code = pdu_params['short_message']
            content = None

            yield self.session_manager.create_session(
                vumi_session_identifier, ussd_code=ussd_code)

        elif service_op == '17':
            # PSSR response. This means session end.
            session_event = 'close'

            session = yield self.session_manager.load_session(
                vumi_session_identifier)
            ussd_code = session['ussd_code']
            content = None

            yield self.session_manager.clear_session(vumi_session_identifier)

        else:
            session_event = 'continue'

            session = yield self.session_manager.load_session(
                vumi_session_identifier)
            ussd_code = session['ussd_code']
            content = pdu_params['short_message']

        # This is stashed on the message and available when replying
        # with a `submit_sm`
        session_info = {
            'session_identifier': mica_session_identifier,
        }

        decoded_msg = self.dcs_decode(content,
                                      pdu_params['data_coding'])

        result = yield self.handle_short_message_content(
            source_addr=pdu_params['source_addr'],
            destination_addr=ussd_code,
            short_message=decoded_msg,
            message_type='ussd',
            session_event=session_event,
            session_info=session_info)
        returnValue(result)
Example #12
0
class DeliverShortMessageProcessor(default.DeliverShortMessageProcessor):

    CONFIG_CLASS = DeliverShortMessageProcessorConfig

    # NOTE: these keys are hexidecimal because of python-smpp encoding
    #       quirkiness
    ussd_service_op_map = {
        '01': 'new',
        '12': 'continue',
        '81': 'close',  # user abort
    }

    def __init__(self, transport, config):
        super(DeliverShortMessageProcessor, self).__init__(transport, config)
        self.transport = transport
        self.log = transport.log
        self.redis = transport.redis
        self.config = self.CONFIG_CLASS(config, static=True)
        self.session_manager = SessionManager(
            self.redis, max_session_length=self.config.max_session_length)

    @inlineCallbacks
    def handle_deliver_sm_ussd(self, pdu, pdu_params, pdu_opts):
        service_op = pdu_opts['ussd_service_op']
        mica_session_identifier = pdu_opts['user_message_reference']
        vumi_session_identifier = make_vumi_session_identifier(
            pdu_params['source_addr'], mica_session_identifier)

        session_event = self.ussd_service_op_map.get(service_op)

        if session_event == 'new':
            # PSSR request. Let's assume it means a new session.
            ussd_code = pdu_params['short_message']
            content = None

            yield self.session_manager.create_session(vumi_session_identifier,
                                                      ussd_code=ussd_code)

        elif session_event == 'close':
            session = yield self.session_manager.load_session(
                vumi_session_identifier)
            ussd_code = session['ussd_code']
            content = None

            yield self.session_manager.clear_session(vumi_session_identifier)

        else:
            if session_event != 'continue':
                self.log.warning(
                    ('Received unknown %r ussd_service_op, assuming continue.')
                    % (service_op, ))
                session_event = 'continue'

            session = yield self.session_manager.load_session(
                vumi_session_identifier)
            ussd_code = session['ussd_code']
            content = self.dcs_decode(pdu_params['short_message'],
                                      pdu_params['data_coding'])

        # This is stashed on the message and available when replying
        # with a `submit_sm`
        session_info = {
            'ussd_service_op': service_op,
            'session_identifier': mica_session_identifier,
        }

        result = yield self.handle_short_message_content(
            source_addr=pdu_params['source_addr'],
            destination_addr=ussd_code,
            short_message=content,
            message_type='ussd',
            session_event=session_event,
            session_info=session_info)
        returnValue(result)
Example #13
0
class SubmitShortMessageProcessor(default.SubmitShortMessageProcessor):

    CONFIG_CLASS = SubmitShortMessageProcessorConfig

    # NOTE: these values are hexidecimal because of python-smpp encoding
    #       quirkiness
    ussd_service_op_map = {
        'continue': '02',
        'close': '17',  # end
    }

    def __init__(self, transport, config):
        super(SubmitShortMessageProcessor, self).__init__(transport, config)
        self.transport = transport
        self.redis = transport.redis
        self.config = self.CONFIG_CLASS(config, static=True)
        self.session_manager = SessionManager(
            self.redis, max_session_length=self.config.max_session_length)

    @inlineCallbacks
    def handle_outbound_message(self, message, service):
        to_addr = message['to_addr']
        from_addr = message['from_addr']
        text = message['content']
        if text is None:
            text = u""
        vumi_message_id = message['message_id']

        session_event = message['session_event']
        transport_type = message['transport_type']
        optional_parameters = {}

        if transport_type == 'ussd':
            continue_session = (session_event !=
                                TransportUserMessage.SESSION_CLOSE)
            session_info = message['transport_metadata'].get(
                'session_info', {})
            mica_session_identifier = session_info.get('session_identifier',
                                                       '')
            vumi_session_identifier = make_vumi_session_identifier(
                to_addr, mica_session_identifier)

            service_op = self.ussd_service_op_map[(
                'continue' if continue_session else 'close')]
            optional_parameters.update({
                'ussd_service_op':
                service_op,
                'user_message_reference':
                (str(mica_session_identifier).zfill(2)),
            })

            if not continue_session:
                yield self.session_manager.clear_session(
                    vumi_session_identifier)

        resp = yield self.send_short_message(
            service,
            vumi_message_id,
            to_addr.encode('ascii'),
            text.encode(self.config.submit_sm_encoding),
            data_coding=self.config.submit_sm_data_coding,
            source_addr=from_addr.encode('ascii'),
            optional_parameters=optional_parameters)

        returnValue(resp)