def setUp(self):
     self.router = MockRouter()
     self.backend = Backend(self.router)
     self.connection = Connection(self.backend, "12345")
     self.person = Person()
     self.person.add_connection(self.connection)
     self.router.add_backend(self.backend)
    def responder_loop(self, seconds=10):
        self.info("Starting responder...")
        while True:
            # look for any new handled messages
            # in the database, and send the responses
            for msg_in_waiting in MessageInWaiting.objects.filter(status="H"):
                self.info("Responding to %s.", msg_in_waiting)
                for response in msg_in_waiting.responses.all():
                    self.info("Response: %s.", response)
                    # only send confirmed or added responses
                    if response.type != "O":
                        db_connection = msg_in_waiting.get_connection()
                        if db_connection is not None:
		                      db_backend = db_connection.backend
		                      # we need to get the real backend from the router 
		                      # to properly send it 
		                      real_backend = self.router.get_backend(db_backend.slug)
		                      if real_backend:
		                          connection = Connection(real_backend, db_connection.identity)
		                          response_msg = Message(connection, response.text)
		                          self.router.outgoing(response_msg)
		                      else:
		                          # TODO: should we fail harder here?  This will permanently
		                          # disable responses to this message which is bad.  
		                          self.error("Can't find backend %s.  Messages will not be sent")
                # mark the original message as responded to
                msg_in_waiting.status="R"
                msg_in_waiting.save()
            # wait until it's time to check again
            time.sleep(seconds)
Пример #3
0
 def privmsg(self, connection, event):
     self.debug("%s -> %s: %r", event.source(), event.target(),
                event.arguments())
     if event.target() == self.nick:
         self.info("routing private message from %s", event.source())
         c = Connection(self, event.source().split("!")[0])
         msg = self.message(c.identity, event.arguments()[0])
         msg.irc_channel = c.identity
         self.route(msg)
 def __callback(self, source, message_text):
     # drop the "sms://" protocol from the source
     phone_number = re.compile("[a-z]+://").sub("", source)
     
     # create connection and message objects, and
     # pass it off to the router
     c = Connection(self, phone_number)
     m = Message(c, message_text)
     self.router.send(m)
Пример #5
0
    def recv_handler(self, **args):
        p = args['pdu']
        self.debug("%s >> %s : %s", p.source_addr, p.destination_addr,
                   p.short_message)

        self.info("injecting message into router")
        con = Connection(self, p.source_addr)
        msg = self.message(con.identity, p.short_message)
        msg.return_addr = p.destination_addr
        self.route(msg)
Пример #6
0
 def pubmsg(self, connection, event):
     self.debug("%s -> %s: %r", event.source(), event.target(),
                event.arguments())
     try:
         nick, txt = map(str.strip, event.arguments()[0].split(":"))
     except ValueError:
         return  # not for me
     nick = nick.split("!")[0]
     if nick == self.nick:
         self.info("routing public message from %s", event.source())
         c = Connection(self, event.source().split("!")[0])
         msg = self.message(c.identity, txt)
         msg.irc_channel = event.target()
         self.route(msg)
Пример #7
0
    def run(self):
        while self._running:
            # check for new messages
            msg = self.modem.next_message(True)

            if msg is not None:
                #                self.error("index: %s" % msg.index)
                #                self._log( self.modem, "index: %s" % msg.index, "info")

                # we got an sms! create RapidSMS Connection and
                # Message objects, and hand it off to the router
                c = Connection(self, msg.sender)

                # Try to use message sent date as timestamp
                # SOMETIMES this doesn't come over, in which
                # case use the current time
                try:
                    date = utils.to_naive_utc_dt(msg.sent)
                except:
                    date = datetime.utcnow()

                m = Message(connection=c, text=msg.text, date=date)
                self.router.send(m)

                # remove the message
                #if msg.index:
                #   self.modem.command("AT+CMGD=%s" % msg.index)

                self.modem.command('AT+CMGD="ALL",2')
            # process all outbound messages
            while True:
                try:
                    self.__send_sms(self._queue.get_nowait())
                except Queue.Empty:
                    # break out of while
                    break

            # poll for new messages
            # every POLL_INTERVAL seconds
            time.sleep(POLL_INTERVAL)
            self.modem.command("AT+CPMS?")
 def _initiate_tree_sequence(self, user, initiator=None):
     user_conn = user.connection()
     if user_conn:
         db_backend = user_conn.backend
         # we need to get the real backend from the router
         # to properly send it
         real_backend = self.router.get_backend(db_backend.slug)
         if real_backend:
             connection = Connection(real_backend, user_conn.identity)
             text = self._get_tree_sequence(user)
             if not text:
                 return _(strings["unknown_survey_location"],
                          get_language_code(
                              user.connection)) % ({
                                  "location": user.location,
                                  "alias": user.study_id
                              })
             else:
                 # first ask the tree app to end any sessions it has open
                 if self.tree_app:
                     self.tree_app.end_sessions(user_conn)
                 if initiator:
                     # if this was initiated by someone else
                     # create an entry for this so they can be
                     # notified upon completion, and also so
                     # we can ignore the data
                     TestSession.objects.create(initiator=initiator,
                                                tester=user,
                                                status="A")
                 start_msg = Message(connection, text)
                 self.router.incoming(start_msg)
                 return
         else:
             error = "Can't find backend %s.  Messages will not be sent" % connection.backend.slug
             self.error(error)
             return error
     else:
         error = "Can't find connection %s.  Messages will not be sent" % user_conn
         self.error(error)
         return error
Пример #9
0
    def message_from_imap(self, imap_mail):
        """From an IMAP message object, get a rapidsms message object"""
        parsed = message_from_string(imap_mail)
        from_user = parsed["From"]
        # if the from format was something like:
        # "Bob User" <*****@*****.**>
        # just pull out the relevant address part from within the carats.
        # Note that we don't currently do anything smart parsing email
        # addresses to make sure they are valid, we either just take
        # what we get, or take what we get between <>.
        match = re.match(r"^.*<\s*(\S+)\s*>", from_user)
        if match:
            new_addr = match.groups()[0]
            self.debug("converting %s to %s" % (from_user, new_addr))
            from_user = new_addr

        subject = parsed["Subject"]
        date_string = parsed["Date"]
        # TODO: until we figure out how to generically parse dates, just use
        # the current time.  This appears to be the standard date format, but
        # currently timezone information is optional.
        # date = datetime.strptime(truncated_date, "%a, %d %b %Y %H:%M:%S")
        date = datetime.now()
        connection = Connection(self, from_user)
        message_body = get_message_body(parsed)
        if not message_body:
            self.error(
                "Got a poorly formed email.  Couldn't find any part with content-type text"
            )
            # TODO: not sure how to handle this.  For now still route it with empty body
            return EmailMessage(connection=connection,
                                text="",
                                date=date,
                                subject=subject)
        return EmailMessage(connection=connection,
                            text=message_body.get_payload(),
                            date=date,
                            subject=subject,
                            mime_type=message_body.get_content_type())
Пример #10
0
 def _send_question(self, session, msg=None):
     '''Sends the next question in the session, if there is one'''
     state = session.state
     if state and state.question:
         response = _(state.question.text,
                      get_language_code(session.connection))
         self.info("Sending: %s" % response)
         if msg:
             msg.respond(response)
         else:
             # we need to get the real backend from the router
             # to properly send it
             real_backend = self.router.get_backend(
                 session.connection.backend.slug)
             if real_backend:
                 connection = Connection(real_backend,
                                         session.connection.identity)
                 outgoing_msg = Message(connection, response)
                 self.router.outgoing(outgoing_msg)
             else:
                 # todo: do we want to fail more loudly than this?
                 error = "Can't find backend %s.  Messages will not be sent" % connection.backend.slug
                 self.error(error)
 def message(self, identity, text, date=None):
     c = Connection(self, identity)
     return Message(connection=c, text=text, date=date)
Пример #12
0
    def _handle_session(self, session, is_ending, klass):
        self.debug("%s session: %s" % (klass, session))

        # get the reporter object
        reporter = session.connection.reporter
        iavi_reporter = IaviReporter.objects.get(pk=reporter.pk)

        if not is_ending:
            # check if the reporter has an active test session
            # and if so, link it. Otherwise treat it normally
            try:
                test_session = TestSession.objects.get(tester=iavi_reporter,
                                                       status="A")
                test_session.tree_session = session
                test_session.save()
            except TestSession.DoesNotExist:
                # not an error, just means this wasn't a test
                # create a new report for this
                klass.objects.create(reporter=iavi_reporter,
                                     started=session.start_date,
                                     session=session,
                                     status="A")

        else:
            # if we have a test session mark the status and save
            try:
                test_session = TestSession.objects.get(tree_session=session)
                if session.canceled:
                    test_session.status = "F"
                    response = _(strings["test_fail"],
                                 get_language_code(test_session.initiator)) % (
                                     {
                                         "alias": iavi_reporter.study_id
                                     })
                else:
                    test_session.status = "P"
                    response = _(strings["test_pass"],
                                 get_language_code(test_session.initiator)) % (
                                     {
                                         "alias": iavi_reporter.study_id
                                     })

                test_session.save()

                # also have to initiate a callback to the
                # original person who initiated the test
                db_backend = test_session.initiator.backend
                real_backend = self.router.get_backend(db_backend.slug)
                if real_backend:
                    real_connection = Connection(
                        real_backend, test_session.initiator.identity)
                    response_msg = Message(real_connection, response)
                    self.router.outgoing(response_msg)
                else:
                    error = "Can't find backend %s.  Messages will not be sent" % connection.backend.slug
                    self.error(error)
            except TestSession.DoesNotExist:
                # not a big deal.  it wasn't a test.
                # if we have a report
                # update the data and save
                try:
                    report = klass.objects.get(session=session)
                    for entry in session.entry_set.all():
                        answer = entry.transition.answer
                        column = self._get_column(
                            entry.transition.current_state)
                        if column:
                            clean_answer = self._get_clean_answer(
                                answer, entry.text)
                            setattr(report, column, clean_answer)
                    report.completed = datetime.now()
                    if session.canceled:
                        report.status = "C"
                    else:
                        report.status = "F"
                    report.save()
                except klass.DoesNotExist:
                    # oops, not sure how this could happen, but we don't
                    # want to puke
                    self.error("No report found for session %s" % session)
Пример #13
0
    def do_GET(self):
        # if the path is just "/" then start a new session
        # and redirect to that session's URL
        if self.path == "/":
            session_id = random.randint(100000, 999999)
            self.send_response(301)
            self.send_header("Location", "/%d/" % session_id)
            self.end_headers()
            return

        # if the path is of the form /integer/blah
        # send a new message from integer with content blah
        send_regex = re.compile(r"^/(.*?)/(.*)")
        match = send_regex.match(self.path)
        if match:
            # parse the url
            parsed = urlparse(self.path)

            # use our default backend by default
            backend = self.server.backend

            # whether we are incoming or outgoing, be default we are incoming
            incoming = True

            # if there is a query string
            if parsed.query:
                # see if there is a different backend specified
                query_string = parse_qs(parsed.query)

                # if so, try to look it up
                if 'backend' in query_string:
                    backend = self.server.backend._router.get_backend(
                        query_string['backend'][0])
                    if not backend:
                        self.send_response(404)
                        self.send_header("Content-type", "text/html")
                        self.end_headers()
                        self.wfile.write("No backend with slug: %s found." %
                                         query_string['backend'][0])
                        return

                # is this actually an outgoing message?
                if 'direction' in query_string:
                    if query_string['direction'][0].lower() == 'out':
                        incoming = False

            # parse the groups out
            match = send_regex.match(parsed.path)

            # send the message
            session_id = urllib.unquote(str(match.group(1)))
            text = urllib.unquote(_str(match.group(2)))

            if text == "json_resp":
                self.send_response(200)
                self.send_header("Content-type", "text/html")
                self.end_headers()

                if HttpHandler.msg_store.has_key(session_id) and len(
                        HttpHandler.msg_store[session_id]):
                    resp = _str(
                        "{'phone':'%s', 'message':'%s'}" %
                        (session_id,
                         HttpHandler.msg_store[session_id].pop(0).replace(
                             "'", r"\'")))
                    self.wfile.write(resp)
                return

            # get time
            received = datetime.utcnow()
            # leave Naive!
            # received.replace(tzinfo=pytz.utc)
            c = Connection(backend, session_id)
            msg = Message(connection=c, text=text, date=received)

            # inny or outy?
            if incoming:
                backend.route(msg)
            else:
                backend._router.outgoing(msg)

            # respond with the number and text
            self.send_response(200)
            self.send_header("Content-type", "text/html")
            self.end_headers()
            self.wfile.write(
                _str("{'phone':'%s', 'message':'%s'}" %
                     (session_id, urllib.unquote(text).replace("'", r"\'"))))
            return

        return