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)
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)
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)
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)
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
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())
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)
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)
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