Exemplo n.º 1
0
def best_connection_for_phone_number(number, backends=None):
    """
    Return a RapidSMS Connection object to use for sending a message
    to the given phone number.

    If we already have Connection objects for the number, use the most
    recently modified one.

    Otherwise, see if we can guess based on looking at the number
    and any backends that have a 'number_regex' defined in settings.

    Fallback to returning a random connection using one of the
    backend names in `backends`, or any of the backends from settings.

    :param number: String containing the phone number in canonical form.
    :param backends: A list of backend names to choose from if we have
    to pick one at random.  Defaults to all backends in settings.
    :return: a rapidsms.models.Connection object
    """

    connection = Connection.objects.filter(identity=number).order_by('-modified_on').first()
    if connection:
        return connection

    for name, backend in settings.INSTALLED_BACKENDS.iteritems():
        if 'number_regex' in backend:
            if backend['number_regex'].match(number):
                return lookup_connections(backend=name, identities=[number])[0]

    # Use any old backend
    backend_names = backends or settings.INSTALLED_BACKENDS.keys()
    backend_name = random.choice(backend_names)
    return lookup_connections(backend_name, identities=[number])[0]
Exemplo n.º 2
0
def best_connection_for_phone_number(number, backends=None):
    """
    Return a RapidSMS Connection object to use for sending a message
    to the given phone number.

    If we already have Connection objects for the number, use the most
    recently modified one.

    Otherwise, see if we can guess based on looking at the number
    and any backends that have a 'number_regex' defined in settings.

    Fallback to returning a random connection using one of the
    backend names in `backends`, or any of the backends from settings.

    :param number: String containing the phone number in canonical form.
    :param backends: A list of backend names to choose from if we have
    to pick one at random.  Defaults to all backends in settings.
    :return: a rapidsms.models.Connection object
    """

    connection = Connection.objects.filter(
        identity=number).order_by('-modified_on').first()
    if connection:
        return connection

    for name, backend in settings.INSTALLED_BACKENDS.iteritems():
        if 'number_regex' in backend:
            if backend['number_regex'].match(number):
                return lookup_connections(backend=name, identities=[number])[0]

    # Use any old backend
    backend_names = backends or settings.INSTALLED_BACKENDS.keys()
    backend_name = random.choice(backend_names)
    return lookup_connections(backend_name, identities=[number])[0]
Exemplo n.º 3
0
	def form_valid(self,form):
		connection = lookup_connections('envaya',[form.cleaned_data['phone_number']])[0],
		text = form.cleaned_data['message']
		
		send(text,connection)
		
		return HttpResponse("<pre>%s</pre>"%(pprint.pformat(form.cleaned_data),))
Exemplo n.º 4
0
def message_resend(request, message_id):
    """
    Re-sends the given message
    """
    message = get_object_or_404(Message, pk=message_id)
    contact = message.contact

    if request.method == 'POST':
        form = ResendForm(request.POST)

        if form.is_valid():
            text = form.cleaned_data['text']
            number = contact.contactprofile.get_phone_number()

            connection = lookup_connections(settings.MODERATOR_BACKEND,
                                            [number])[0]
            receive(text, connection)

            messages.success(
                request,
                _("The message %(text)s was successfully resent") %
                {'text': unicode(text)})

            return HttpResponseRedirect(
                reverse("moderation.views.contact", args=(contact.pk, )))
    else:
        form = ResendForm(initial={'text': message.text})

    return render_to_response("message_resend.html", {
        'contact': contact,
        'message': message,
        'form': form,
    },
                              context_instance=RequestContext(request))
Exemplo n.º 5
0
	def handle_message(self):
		event_kwargs = self.get_model_kwargs('from','message','timestamp')
		#fix variables for model 
		event_kwargs['sender'] = event_kwargs.pop('from')
		connection = lookup_connections('envaya', [event_kwargs['sender']])[0]
		msg_in = receive(event_kwargs['message'],connection)		
		return EnvayaOutgoingResponse()
Exemplo n.º 6
0
def message_received(request, backend_name):
    """Handle HTTP requests from TextIt.
    """
    try:
        backend = settings.INSTALLED_BACKENDS[backend_name]
    except KeyError:
        logger.error('Name "{}" not found in settings INSTALLED_BACKENDS.'.format(backend_name))
        return HttpResponseBadRequest('Name "{}" not found in settings INSTALLED_BACKENDS.'.format(backend_name))
    try:
        if request.META['QUERY_STRING'] != backend['config']['query_key']:
            r = 'query_key "{}" does not match configured value from django settings "{}"'.format(
                    request.META['QUERY_STRING'], backend['config']['query_key'])
            logger.error(r)
            return HttpResponseBadRequest(r)
    except KeyError:
        logger.error("No query_key set up in settings INSTALLED_BACKENDS[backend_name]")
        return  HttpResponseBadRequest("No query_key set up in settings INSTALLED_BACKENDS[backend_name]")

    post = request.POST
    logger.debug("@@ request from TextIt - Decoded data: %r" % post)
    try:
        post_event = post['event']
    except KeyError:
        logger.error('No "Event" key in POST request')
        return HttpResponseBadRequest("No Event key in POST request")
    if post_event == 'mo_sms':
        # Must have received a message
        logger.debug("@@Got a text message")
        try:
            fa = post['phone']
            from_address = fa[1:] if fa.startswith('+') else fa  # strip off the plus sign
            text = post['text']
            logger.debug("@@Received message from %s: %s" % (from_address, text))
        except KeyError:
            logger.exception('Malformed POST message')
            return HttpResponseBadRequest("Malformed POST message")
        try:
            # get (or create) a connections object for this backend and from_address
            connections = lookup_connections(backend_name, [from_address])
        except Exception as e:
            r = "Error finding connection for backend_name={}, from={}, err={}".format(
                backend_name, from_address, e)
            logger.error(r)
            return HttpResponseServerError(r)
        try:
            # pass the message to RapidSMS
            receive(text, connections[0])
        except Exception as e:
            r = "Error receiving message. backend_name={}, from={}, err={}".format(
                backend_name, from_address, e)
            logger.error(r)
            return HttpResponseServerError(r)
        # Respond nicely to TextIt
        return HttpResponse("OK")
    # elif:
    if post_event in ['mt_sent', 'mt_dlvd']:
        return HttpResponse("thanks")  # confirmation messages are ignored
    # else:
    logger.error("@@No recognized command in request from TextIt")
    return HttpResponseBadRequest("Unexpected event code='{}'".format(post_event))
Exemplo n.º 7
0
def text_back(url, phone_number):
    try:
        connections = lookup_connections(backend="kannel-gsm-modem",
                                         identities=[phone_number])
        send(url, connections=connections)
    except Exception as ex:
        logger.warn(ex)
Exemplo n.º 8
0
    def test_outgoing(self):
        """Sent messages should call _queue_message with incoming=False"""

        with patch.object(CeleryRouter, '_queue_message') as mock_method:
            connections = lookup_connections("mockbackend",
                                             identities=['1112223333'])
            messages = send("test", connections)
        mock_method.assert_called_once_with(messages[0], incoming=False)
Exemplo n.º 9
0
    def test_incoming(self):
        """Received messages should call _queue_message with incoming=True"""

        with patch.object(CeleryRouter, '_queue_message') as mock_method:
            connections = lookup_connections("mockbackend",
                                             identities=['1112223333'])
            message = receive("test", connections[0])
        mock_method.assert_called_once_with(message, incoming=True)
Exemplo n.º 10
0
 def lookup_connections(self, identities, backend='mockbackend'):
     """Looks up a connection, creating both the connection and backend if either
     does not exist. For multitenancy, we also need to create a BackendLink.
     """
     if isinstance(backend, basestring):
         backend, _ = Backend.objects.get_or_create(name=backend)
     BackendLink.all_tenants.get_or_create(backend=backend)
     connections = lookup_connections(backend, identities)
     return connections
Exemplo n.º 11
0
def store_and_queue(identity, text):
    """Store a message in our log and send it into RapidSMS.

    :param identity: Phone number the message will appear to come from
    :param text: The message text
    """
    store_message(INCOMING, identity, text)
    connection = lookup_connections(BACKEND_NAME, [identity])[0]
    receive(text, connection)
Exemplo n.º 12
0
 def lookup_connections(self, identities, backend='mockbackend'):
     """Looks up a connection, creating both the connection and backend if either
     does not exist. For multitenancy, we also need to create a BackendLink.
     """
     if isinstance(backend, basestring):
         backend, _ = Backend.objects.get_or_create(name=backend)
     BackendLink.all_tenants.get_or_create(backend=backend)
     connections = lookup_connections(backend, identities)
     return connections
Exemplo n.º 13
0
    def test_outgoing(self):
        """Eager backends should call rapidsms_handle_message directly"""

        with patch(
            'rapidsms.router.celery.tasks.rapidsms_handle_message'
        ) as mock_method:
            connections = lookup_connections("mockbackend",
                                             identities=['1112223333'])
            receive("test", connections[0])
        mock_method.assert_called_once()
Exemplo n.º 14
0
def store_and_queue(identity, text, to_addr=None):
    """Store a message in our log and send it into RapidSMS.

    :param identity: Phone number the message will appear to come from
    :param text: The message text
    :param to_addr: Phone number that the message is sent to
    """
    store_message(INCOMING, identity, text)
    connection = lookup_connections(BACKEND_NAME, [identity])[0]
    receive(text, connection, fields={"to_addr": to_addr, "from_addr": identity})
Exemplo n.º 15
0
def send_message(request):
    form = forms.MessageForm(request.POST)

    if form.is_valid():
        cd = form.cleaned_data
        identity = cd["identity"]
        connection = lookup_connections("message_tester", [identity])[0]
        receive(cd["text"], connection)
        return {"success": True}
    else:
        return {"error": u"Parâmetros obrigatórios não encontrados"}
Exemplo n.º 16
0
def store_and_queue(backend_name, identity, text):
    """Store a message in our log and send it into RapidSMS.

    :param backend_name:
    :param identity: Phone number the message will appear to come from
    :param text: The message
    """
    from rapidsms.router import receive, lookup_connections
    store_message(HttpTesterMessage.INCOMING, identity, text)
    connection = lookup_connections(backend_name, [identity])[0]
    receive(text, connection)
Exemplo n.º 17
0
def send(message,i=0):
	connection = router.lookup_connections(BACKEND,[message['identity']])[0]
	msg_in = router.receive(message['message'],connection)
	msg_in.ccem_msg.created = message['date']
	msg_in.ccem_msg.save()
	
	msg_out = msg_in.connections[0].messages.all()[0]
	msg_out.created = message['date']+datetime.timedelta(seconds=10)
	msg_out.save()
	
	print 'Sent',i,':',message['message']
	return msg_in
Exemplo n.º 18
0
def notify_winners(prize=None):
    if prize:
        raffle_winners = RaffleWinner.objects.select_related().filter(prize__prize=prize)
    else:
        raffle_winners = RaffleWinner.objects.select_related().all()
    for winner in raffle_winners:
        try:
            connections = lookup_connections(backend="kannel-gsm-modem",
                                             identities=[winner.winner.phone_number])
            text = "You have won a {0}".format(winner.prize.get_prize_display())
            logger.info((text, winner.winner.phone_number))
            #send(text, connections=connections)
        except Exception as ex:
            logger.warn(ex)
Exemplo n.º 19
0
def handle(request):

    body = json.loads(request.body.decode())

    instance_id = int(body['instance_id'])
    message = str(body['message'])
    participant = ParticipantModel.objects.get(instance_id=instance_id)

    send(
        message,
        lookup_connections(backend='twilio-backend',
                           identities=[participant.phone_number]))

    return HttpResponse()
Exemplo n.º 20
0
def store_and_queue(identity, text, to_addr=None):
    """Store a message in our log and send it into RapidSMS.

    :param identity: Phone number the message will appear to come from
    :param text: The message text
    :param to_addr: Phone number that the message is sent to
    """
    store_message(INCOMING, identity, text)
    connection = lookup_connections(BACKEND_NAME, [identity])[0]
    receive(text,
            connection,
            fields={
                'to_addr': to_addr,
                'from_addr': identity
            })
Exemplo n.º 21
0
def notify_winners(prize=None):
    if prize:
        raffle_winners = RaffleWinner.objects.select_related().filter(
            prize__prize=prize)
    else:
        raffle_winners = RaffleWinner.objects.select_related().all()
    for winner in raffle_winners:
        try:
            connections = lookup_connections(
                backend="kannel-gsm-modem",
                identities=[winner.winner.phone_number])
            text = "You have won a {0}".format(
                winner.prize.get_prize_display())
            logger.info((text, winner.winner.phone_number))
            #send(text, connections=connections)
        except Exception as ex:
            logger.warn(ex)
Exemplo n.º 22
0
def submit_form(req, form_id):
    try:
        form = get_object_or_None(Form, pk=form_id)
        fields = []
        for field in form.fields.all():
            fields.append(req.POST[field.name])

        sms = IncomingMessage(text=form.separator.join(fields),
                              connection=lookup_connections("web", req.META["REMOTE_ADDR"].replace('.', ''))[0])
        answer, submission = form.process_submission(sms, Submission.TYPE_WEB, return_submission=True)

        req.session["last_submission"] = {"form": form, "answer": answer, "submission": submission}

        return redirect(reverse("web_process_submission"))
    except Exception as e:
        # TODO: Logar
        return redirect(reverse("web_answer_form", kwargs={"form_id": form.pk}))
Exemplo n.º 23
0
	def handle_message(self):
		event_kwargs = self.get_model_kwargs('from','message','timestamp')
		#fix variables for model 
		event_kwargs['sender'] = event_kwargs.pop('from')
		connection = lookup_connections('envaya', [event_kwargs['sender']])[0]
		msg_in = receive(event_kwargs['message'],connection)
		#send response via http call back
		events = [{'event':'send','messages':[],},]
		msgs_out = []
		for response in msg_in.responses:
			#msgs_out.append(send(**response)) #send is called when we process the msg, no need to call it again here
			events[0]['messages'].append({
				'to':response['connections'][0].identity,
				'message':response['text']
				})
		#models.SMS(**event_kwargs).save()
		logger.debug("Send Envaya:\n%s",json.dumps({'events':events}))
		return HttpResponse(json.dumps({'events':events}),mimetype='application/json')
Exemplo n.º 24
0
    def start_survey(plugin_id, owner_id, token, url, survey_id, instance_id):
        # make call to start survey
        print("Parameters::", plugin_id, owner_id, token, url, survey_id,
              instance_id)
        data = {'action': 'start'}

        a = owner_id + "-" + plugin_id + ":" + token
        b64 = base64.b64encode(a.encode()).decode()

        headers = {"Authorization": "Basic " + b64}

        requests.post(url + '/instances/' + str(instance_id),
                      json.dumps(data),
                      headers=headers)

        #get participant for survey
        params = "?survey_id=" + str(survey_id) + "&instance_id=" + str(
            instance_id)
        participant_request = requests.get(url + "/participants" + params,
                                           headers=headers)
        participant = json.loads(participant_request.text)
        participant_number = participant["participant"]

        p = ParticipantModel.objects.filter(
            phone_number=participant_number).first()

        if p is not None:
            p.delete()

        p = ParticipantModel(instance_id=instance_id,
                             phone_number=participant_number,
                             owner_id=int(owner_id))
        p.save()

        first_question = requests.get(url + '/instances/' + str(instance_id) +
                                      "/latest",
                                      headers=headers)
        question_text = json.loads(first_question.text)["question_text"]

        send(
            question_text,
            lookup_connections(backend="twilio-backend",
                               identities=[participant_number]))
Exemplo n.º 25
0
def send_message(req):
    if not "text" in req.POST or not "identities" in req.POST:
        messages.error(req, "Parâmetros obrigatórios faltando.")
        return redirect(reverse(view_form))

    message = req.POST["text"]

    if len(message) > Config.get("max_sms_length"):
        messages.error(req, "O tamanho da mensagem excede o limite permitido.")
        return redirect(reverse(view_form))

    if len(message) < 1 or len(req.POST["identities"]) < 10:
        messages.error(req,
                       "Você precisa informar ao menos 1 telefone no formato correto. Veja um exemplo após a caixa de texto de mensagem.")
        return redirect(reverse(view_form))

    identities = req.POST["identities"].split(",")

    try:
        backend = PurebrosBackend('envio_direto', 'envio_direto', **dj_settings.INSTALLED_BACKENDS['purebros'])

        for identity in identities:
            identity = '55' + re.sub(r'[^0-9]', '', identity.strip())
            resp = backend.send_message(identity, req.POST["carrier"], message)
            if resp == "0":
                Message.objects.create(
                    date=timezone.now(),
                    direction="O",
                    text=message,
                    contact=None,
                    connection=lookup_connections(backend='envio_direto', identities=[identity])[0],
                )
            else:
                messages.error(req,
                               u"Houve um erro ao enviar a mensagem ao numero %s. Código do erro: %s" % (
                                   identity, resp))
    except Exception as e:
        raven.captureException()
        messages.error(req,
                       "Não foi possível se conectar ao integrador. Por favor tente novamente mais tarde ou se persistir o problema contate o administrador do sistema.")

    return redirect(reverse(view_form))
Exemplo n.º 26
0
 def handle_message(self):
     event_kwargs = self.get_model_kwargs('from', 'message', 'timestamp')
     #fix variables for model
     event_kwargs['sender'] = event_kwargs.pop('from')
     connection = lookup_connections('envaya', [event_kwargs['sender']])[0]
     msg_in = receive(event_kwargs['message'], connection)
     #send response via http call back
     events = [
         {
             'event': 'send',
             'messages': [],
         },
     ]
     msgs_out = []
     for response in msg_in.responses:
         #msgs_out.append(send(**response)) #send is called when we process the msg, no need to call it again here
         events[0]['messages'].append({
             'to': response['connections'][0].identity,
             'message': response['text']
         })
     #models.SMS(**event_kwargs).save()
     logger.debug("Send Envaya:\n%s", json.dumps({'events': events}))
     return HttpResponse(json.dumps({'events': events}),
                         mimetype='application/json')
Exemplo n.º 27
0
 def lookup_connections(self, identities, backend='mockbackend'):
     """loopup_connections wrapper to use mockbackend by default"""
     return lookup_connections(backend, identities)
Exemplo n.º 28
0
 def lookup_connections(self, identities, backend='mockbackend'):
     """loopup_connections wrapper to use mockbackend by default"""
     return lookup_connections(backend, identities)
Exemplo n.º 29
0
 def lookup_connections(self, backend='mockbackend', identities=None):
     """loopup_connections wrapper to use mockbackend by default"""
     if not identities:
         identities = []
     return lookup_connections(backend, identities)
Exemplo n.º 30
0
def store_and_queue(backend_name, identity, text):
    from rapidsms.router import receive, lookup_connections
    store_message('in', identity, text)
    connection = lookup_connections(backend_name, [identity])[0]
    receive(text, connection)
Exemplo n.º 31
0
def store_and_queue(backend_name, identity, text):
    from rapidsms.router import receive, lookup_connections
    store_message('in', identity, text)
    connection = lookup_connections(backend_name, [identity])[0]
    receive(text, connection)
Exemplo n.º 32
0
def receive_multimodem_message(request, server_slug):
    """
    The view to handle requests from multimodem has to be custom because the server can post 1-* messages in a single
    request. The Rapid built-in class-based views only accept a single message per form/post.

    TODO:
    Add basic auth to validate against Rapid's user database. The iSMS modem only supports basic auth.

    :param request:
    :return:
    """
    xml_data = request.POST.get('XMLDATA', '')
    """
    The modem posts the data as it receives it formatted as an xml file. The xml is then URL encoded and posted as a
    form parameter called XML data.

    Decoded Example:
    <?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>
    <Response>
        <Msg_Count>2</Msg_Count>
        <MessageNotification>
            <Message_Index>1</Message_Index>
            <ModemNumber>2:111222333</ModemNumber>
            <SenderNumber>+222333333</SenderNumber>
            <Date>15/04/13</Date>
            <Time>10:55:58</Time>
            <EncodingFlag>ASCII</EncodingFlag>
            <Message>Testn2</Message>
        </MessageNotification>
            <MessageNotification>
            <Message_Index>2</Message_Index>
            <ModemNumber>2:111222333</ModemNumber>
            <SenderNumber>+222333333</SenderNumber>
            <Date>15/04/13</Date>
            <Time>10:58:39</Time>
            <EncodingFlag>Unicode</EncodingFlag>
            <Message>0429043D043F0437043D043C0433043C0436043D043C</Message>
        </MessageNotification>
    </Response>
    """

    try:
        root = ET.fromstring(xml_data)
    except ET.ParseError:
        logger.error("Failed to parse XML")
        logger.error(request)
        return HttpResponseBadRequest('Error parsing XML')

    for message in root.findall('MessageNotification'):
        raw_text = message.find('Message').text
        from_number = message.find('ModemNumber').text

        # ModemNumber is simply 1 for single-port modems and it's a string of
        # 'port_numer:phone_number' for multiport modems.
        if ':' in from_number:
            modem_number, phone_number = from_number.split(':')[0:2]
        else:
            # This is a single port modem
            modem_number = from_number

        # Search through backends looking for the single one with this
        # server_slug / modem combo
        possible_backends = getattr(settings, 'INSTALLED_BACKENDS', {}).items()
        backend_names = [name for name, config in possible_backends
                         if str(config.get('modem_port')) == str(modem_number)
                         and config.get('server_slug') == server_slug]
        if backend_names:
            if len(backend_names) > 1:
                logger.error("More than 1 backend with this server/port combo: %s / %s",
                             server_slug, modem_number)
                return HttpResponseBadRequest('Improper Configuration: multiple backends with same server / port')
            backend_name = backend_names[0]
            encoding = message.find('EncodingFlag').text
            if encoding.lower() == "unicode":
                msg_text = ismsformat_to_unicode(raw_text)
            else:
                msg_text = raw_text

            connections = lookup_connections(backend_name, [message.find('SenderNumber').text])
            data = {'text': msg_text,
                    'connection': connections[0]}
            receive(**data)
        else:
            logger.error("Can't find backend for this server/port combo: %s / %s",
                         server_slug, modem_number)
            return HttpResponseBadRequest('Unknown server or port.')

    return HttpResponse('OK')
Exemplo n.º 33
0
 def lookup_connections(self, identities):
     """Simple wrapper to ease connection lookup on child forms."""
     return lookup_connections(self.backend_name, identities)
Exemplo n.º 34
0
 def lookup_connections(self, backend, identities):
     """lookup_connections() API wrapper."""
     return lookup_connections(backend, identities)
Exemplo n.º 35
0
 def lookup_connections(self, identities):
     """Simple wrapper to ease connection lookup on child forms."""
     return lookup_connections(self.backend_name, identities)
Exemplo n.º 36
0
 def lookup_connections(self, backend='mockbackend', identities=None):
     """loopup_connections wrapper to use mockbackend by default"""
     if not identities:
         identities = []
     return lookup_connections(backend, identities)
Exemplo n.º 37
0
 def lookup_connections(self, backend, identities):
     """lookup_connections() API wrapper."""
     return lookup_connections(backend, identities)
Exemplo n.º 38
0
def receive_multimodem_message(request, server_slug):
    """
    The view to handle requests from multimodem has to be custom because the server can post 1-* messages in a single
    request. The Rapid built-in class-based views only accept a single message per form/post.

    TODO:
    Add basic auth to validate against Rapid's user database. The iSMS modem only supports basic auth.

    :param request:
    :return:
    """
    xml_data = request.POST.get('XMLDATA', '')
    """
    The modem posts the data as it receives it formatted as an xml file. The xml is then URL encoded and posted as a
    form parameter called XML data.

    Decoded Example:
    <?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>
    <Response>
        <Msg_Count>2</Msg_Count>
        <MessageNotification>
            <Message_Index>1</Message_Index>
            <ModemNumber>2:111222333</ModemNumber>
            <SenderNumber>+222333333</SenderNumber>
            <Date>15/04/13</Date>
            <Time>10:55:58</Time>
            <EncodingFlag>ASCII</EncodingFlag>
            <Message>Testn2</Message>
        </MessageNotification>
            <MessageNotification>
            <Message_Index>2</Message_Index>
            <ModemNumber>2:111222333</ModemNumber>
            <SenderNumber>+222333333</SenderNumber>
            <Date>15/04/13</Date>
            <Time>10:58:39</Time>
            <EncodingFlag>Unicode</EncodingFlag>
            <Message>0429043D043F0437043D043C0433043C0436043D043C</Message>
        </MessageNotification>
    </Response>
    """

    try:
        root = ET.fromstring(xml_data)
    except ET.ParseError:
        logger.error("Failed to parse XML")
        logger.error(request)
        return HttpResponseBadRequest('Error parsing XML')

    for message in root.findall('MessageNotification'):
        raw_text = message.find('Message').text
        from_number = message.find('ModemNumber').text

        # ModemNumber is simply 1 for single-port modems and it's a string of
        # 'port_numer:phone_number' for multiport modems.
        if ':' in from_number:
            modem_number, phone_number = from_number.split(':')[0:2]
        else:
            # This is a single port modem
            modem_number = from_number

        # Search through backends looking for the single one with this
        # server_slug / modem combo
        possible_backends = getattr(settings, 'INSTALLED_BACKENDS', {}).items()
        backend_names = [
            name for name, config in possible_backends
            if str(config.get('modem_port')) == str(modem_number)
            and config.get('server_slug') == server_slug
        ]
        if backend_names:
            if len(backend_names) > 1:
                logger.error(
                    "More than 1 backend with this server/port combo: %s / %s",
                    server_slug, modem_number)
                return HttpResponseBadRequest(
                    'Improper Configuration: multiple backends with same server / port'
                )
            backend_name = backend_names[0]
            encoding = message.find('EncodingFlag').text
            if encoding.lower() == "unicode":
                msg_text = ismsformat_to_unicode(raw_text)
            else:
                msg_text = raw_text

            connections = lookup_connections(
                backend_name, [message.find('SenderNumber').text])
            data = {'text': msg_text, 'connection': connections[0]}
            receive(**data)
        else:
            logger.error(
                "Can't find backend for this server/port combo: %s / %s",
                server_slug, modem_number)
            return HttpResponseBadRequest('Unknown server or port.')

    return HttpResponse('OK')