Example #1
0
    def serve_forever(self):
        self.connect_callback()  # notify that the connection occured
        try:
            while True:
                log.debug('waiting on queue')
                stanza_type, entry = self.incoming_stanza_queue.get()
                log.debug('message received')
                if entry == QUIT_MESSAGE:
                    log.info("Stop magic message received, quitting...")
                    break
                if stanza_type is STZ_MSG:
                    msg = Message(entry)
                    msg.frm = self.sender
                    msg.to = self.bot_identifier  # To me only

                    self.callback_message(msg)

                    # implements the mentions.
                    mentioned = [
                        self.build_identifier(word[1:])
                        for word in entry.split() if word.startswith('@')
                    ]
                    if mentioned:
                        self.callback_mention(msg, mentioned)

                elif stanza_type is STZ_PRE:
                    log.info("Presence stanza received.")
                    self.callback_presence(entry)
                elif stanza_type is STZ_IQ:
                    log.info("IQ stanza received.")
                else:
                    log.error("Unknown stanza type.")

        except EOFError:
            pass
        except KeyboardInterrupt:
            pass
        finally:
            log.debug("Trigger disconnect callback")
            self.disconnect_callback()
            log.debug("Trigger shutdown")
            self.shutdown()
Example #2
0
    def _handle_message(self, message):
        try:
            data = json.loads(message.data.decode('utf-8'))
        except Exception:
            log.warning('Received malformed message: {}'.format(message.data))
            message.ack()
            return

        if not data.get('message') or not data.get('message', {}).get('text'):
            message.ack()
            return
        sender_blob = data['message']['sender']
        sender = HangoutsChatUser(sender_blob['name'],
                                  sender_blob['displayName'],
                                  sender_blob['email'], sender_blob['type'])
        message_body = data['message']['text']
        message.ack()
        # message.ack() may fail silently, so we should ensure our messages are somewhat idempotent
        time = data.get('eventTime', 0)
        if time == 0:
            log.warning('Received 0 eventTime from message')

        send_name = sender_blob.get('name', '')
        thread_name = data.get('message', {}).get('thread', {}).get('name', '')
        body_length = len(message_body)
        message_id = "{}{}{}{}".format(time, send_name, thread_name,
                                       body_length)
        cached = self.message_cache.get(message_id)
        if cached is not None:
            return
        self.message_cache[message_id] = True

        context = {
            'space_id': data['space']['name'],
            'thread_id': data['message']['thread']['name']
        }
        msg = Message(body=message_body.strip(), frm=sender, extras=context)
        is_dm = data['message']['space']['type'] == 'DM'
        if is_dm:
            msg.to = self.bot_identifier
        self.callback_message(msg)
Example #3
0
    def serve_forever(self):
        if self.demo_mode:
            # disable the console logging once it is serving in demo mode.
            root = logging.getLogger()
            root.removeHandler(console_hdlr)
            root.addHandler(logging.NullHandler())
        self.connect_callback()  # notify that the connection occured
        self.callback_presence(Presence(identifier=self.user, status=ONLINE))
        try:
            while True:
                if ANSI or self.demo_mode:
                    entry = input('\n' + str(fg.cyan) + ' >>> ' +
                                  str(fx.reset))
                else:
                    entry = input('\n>>> ')
                msg = Message(entry)
                msg.frm = self.user
                msg.to = self.bot_identifier
                self.callback_message(msg)

                mentioned = [
                    self.build_identifier(word[1:])
                    for word in re.findall(r"@[\w']+", entry)
                    if word.startswith('@')
                ]
                if mentioned:
                    self.callback_mention(msg, mentioned)

                sleep(.5)
        except EOFError:
            pass
        except KeyboardInterrupt:
            pass
        finally:
            # simulate some real presence
            self.callback_presence(
                Presence(identifier=self.user, status=OFFLINE))
            log.debug("Trigger disconnect callback")
            self.disconnect_callback()
            log.debug("Trigger shutdown")
            self.shutdown()
Example #4
0
File: text.py Project: achew22/err
 def serve_forever(self):
     self.jid = 'Err@localhost'  # whatever
     self.connect()  # be sure we are "connected" before the first command
     self.connect_callback()  # notify that the connection occured
     try:
         while True:
             entry = raw_input("Talk to  me >>").decode(ENCODING_INPUT)
             msg = Message(entry)
             msg.setFrom(
                 config.BOT_ADMINS[0])  # assume this is the admin talking
             msg.setTo(self.jid)  # To me only
             self.callback_message(self.conn, msg)
     except EOFError as eof:
         pass
     except KeyboardInterrupt as ki:
         pass
     finally:
         logging.debug("Trigger disconnect callback")
         self.disconnect_callback()
         logging.debug("Trigger shutdown")
         self.shutdown()
Example #5
0
    def incoming_message(self, xmppmsg):
        """Callback for message events"""
        if xmppmsg['type'] == "error":
            log.warning("Received error message: %s", xmppmsg)
            return

        msg = Message(xmppmsg['body'])
        if 'html' in xmppmsg.keys():
            msg.html = xmppmsg['html']
        log.debug("incoming_message from: %s", msg.frm)
        if xmppmsg['type'] == 'groupchat':
            msg.frm = self._build_room_occupant(xmppmsg['from'].full)
            msg.to = msg.frm.room
        else:
            msg.frm = self._build_person(xmppmsg['from'].full)
            msg.to = self._build_person(xmppmsg['to'].full)

        msg.nick = xmppmsg['mucnick']
        msg.delayed = bool(xmppmsg['delay']._get_attr(
            'stamp'))  # this is a bug in sleekxmpp it should be ['from']
        self.callback_message(msg)
Example #6
0
    def incoming_message(self, xmppmsg):
        """Callback for message events"""
        if xmppmsg["type"] == "error":
            log.warning("Received error message: %s", xmppmsg)
            return

        msg = Message(xmppmsg["body"])
        if "html" in xmppmsg.keys():
            msg.html = xmppmsg["html"]
        log.debug("incoming_message from: %s", msg.frm)
        if xmppmsg["type"] == "groupchat":
            msg.frm = self._build_room_occupant(xmppmsg["from"].full)
            msg.to = msg.frm.room
        else:
            msg.frm = self._build_person(xmppmsg["from"].full)
            msg.to = self._build_person(xmppmsg["to"].full)

        msg.nick = xmppmsg["mucnick"]
        msg.delayed = bool(xmppmsg["delay"]._get_attr(
            "stamp"))  # this is a bug in slixmpp it should be ['from']
        self.callback_message(msg)
Example #7
0
 def _handle_message(self, message):
     data = json.loads(message.data.decode('utf-8'))
     if not data.get('message'):
         message.ack()
         return
     sender_blob = data['message']['sender']
     sender = HangoutsChatUser(sender_blob['name'], 
                               sender_blob['displayName'], 
                               sender_blob['email'],
                               sender_blob['type'])
     message_body = data['message']['text']
     message.ack()
     context = {
         'space_id': data['space']['name'],
         'thread_id': data['message']['thread']['name']
     }
     msg = Message(body=message_body.strip(), frm=sender, extras=context)
     is_dm = data['message']['space']['type'] == 'DM'
     if is_dm:
         msg.to = self.bot_identifier
     self.callback_message(msg)
Example #8
0
 def incoming_message(self, xmppmsg):
     """Callback for message events"""
     msg = Message(xmppmsg['body'])
     if 'html' in xmppmsg.keys():
         msg.html = xmppmsg['html']
     msg.frm = self.build_identifier(xmppmsg['from'].full)
     msg.to = self.build_identifier(xmppmsg['to'].full)
     log.debug("incoming_message frm : %s" % msg.frm)
     log.debug("incoming_message frm node: %s" % msg.frm.node)
     log.debug("incoming_message frm domain: %s" % msg.frm.domain)
     log.debug("incoming_message frm resource: %s" % msg.frm.resource)
     msg.type = xmppmsg['type']
     if msg.type == 'groupchat':
         # those are not simple identifiers, they are muc occupants.
         msg.frm = XMPPMUCOccupant(msg.frm.node, msg.frm.domain,
                                   msg.frm.resource)
         msg.to = XMPPMUCOccupant(msg.to.node, msg.to.domain,
                                  msg.to.resource)
     msg.nick = xmppmsg['mucnick']
     msg.delayed = bool(xmppmsg['delay']._get_attr(
         'stamp'))  # this is a bug in sleekxmpp it should be ['from']
     self.callback_message(msg)
Example #9
0
    def incoming_message(self, xmppmsg):
        """Callback for message events"""
        if xmppmsg['type'] == "error":
            log.warning("Received error message: %s", xmppmsg)
            return

        msg = Message(xmppmsg['body'])
        if 'html' in xmppmsg.keys():
            msg.html = xmppmsg['html']
        msg.frm = self.build_identifier(xmppmsg['from'].full)
        msg.to = self.build_identifier(xmppmsg['to'].full)
        log.debug("incoming_message from: %s", msg.frm)
        if xmppmsg['type'] == 'groupchat':
            room = self.room_factory(msg.frm.node + '@' + msg.frm.domain, self)
            msg.frm = self.roomoccupant_factory(msg.frm.node, msg.frm.domain,
                                                msg.frm.resource, room)
            msg.to = room

        msg.nick = xmppmsg['mucnick']
        msg.delayed = bool(xmppmsg['delay']._get_attr(
            'stamp'))  # this is a bug in sleekxmpp it should be ['from']
        self.callback_message(msg)
Example #10
0
    def incoming_message(self, xmppmsg: dict) -> None:
        """Callback for message events"""
        if xmppmsg["type"] == "error":
            log.warning("Received error message: %s", xmppmsg)
            return

        msg = Message(xmppmsg["body"])
        if "html" in xmppmsg.keys():
            msg.html = xmppmsg["html"]
        log.debug("incoming_message from: %s", msg.frm)
        if xmppmsg["type"] == "groupchat":
            msg.frm = self._build_room_occupant(xmppmsg["from"].full)
            msg.to = msg.frm.room
        else:
            msg.frm = self._build_person(xmppmsg["from"].full)
            msg.to = self._build_person(xmppmsg["to"].full)

        msg.nick = xmppmsg["mucnick"]
        now = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")
        delay = xmppmsg["delay"]._get_attr(
            "stamp")  # this is a bug in sleekxmpp it should be ['from']
        msg.delayed = bool(delay and delay != now)
        self.callback_message(msg)
Example #11
0
    def serve_forever(self):
        me = self.build_identifier(self.bot_config.BOT_ADMINS[0])
        self.connect_callback()  # notify that the connection occured
        self.callback_presence(Presence(identifier=me, status=ONLINE))
        try:
            while True:
                if ANSI:
                    entry = input('\n' + str(fg.cyan) + ' >>> ' +
                                  str(fx.reset))
                else:
                    entry = input('\n>>> ')
                msg = Message(entry)
                msg.frm = me
                msg.to = self.bot_identifier
                self.callback_message(msg)

                mentioned = [
                    self.build_identifier(word[1:])
                    for word in re.findall(r"@[\w']+", entry)
                    if word.startswith('@')
                ]
                if mentioned:
                    self.callback_mention(msg, mentioned)

                sleep(.5)
        except EOFError:
            pass
        except KeyboardInterrupt:
            pass
        finally:
            # simulate some real presence
            self.callback_presence(Presence(identifier=me, status=OFFLINE))
            log.debug("Trigger disconnect callback")
            self.disconnect_callback()
            log.debug("Trigger shutdown")
            self.shutdown()
Example #12
0
 def on_privmsg(self, _, e):
     msg = Message(e.arguments[0])
     msg.frm = IRCIdentifier(e.source.split('!')[0])
     msg.to = IRCIdentifier(e.target)
     self.callback.callback_message(msg)
Example #13
0
 def build_reply(self, msg, text=None, private=False, threaded=False):
     response = Message(body=text,
                        frm=msg.to,
                        to=msg.frm,
                        extras=msg.extras)
     return response
Example #14
0
File: irc.py Project: qznc/err
 def on_privmsg(self, _, e):
     msg = Message(e.arguments[0])
     msg.frm = e.source.split('!')[0]
     msg.to = e.target
     self.callback.callback_message(msg)
Example #15
0
 def build_message(self, text):
     return Message(text, typ='groupchat')  # it is always a groupchat in campfire
Example #16
0
 def build_message(self, text):
     text, html = self.build_text_html_message_pair(text)
     return Message(text, html=html)
Example #17
0
 def build_message(self, text):
     txt, node = build_text_html_message_pair(text)
     msg = Message(txt, html=node) if node else Message(txt)
     msg.frm = self.jid
     return msg  # rebuild a pure html snippet to include directly in the console html
Example #18
0
 def on_friend_message(self, friend_number, message):
     msg = Message(message)
     msg.frm = self.friend_to_idd(friend_number)
     logging.debug('TOX: %s: %s' % (msg.frm, message))
     msg.to = self.backend.jid
     self.backend.callback_message(msg)
Example #19
0
 def _privmsg(self, e, notice=False):
     msg = Message(e.arguments[0], extras={'notice': notice})
     msg.frm = IRCPerson(e.source)
     msg.to = IRCPerson(e.target)
     self.bot.callback_message(msg)
Example #20
0
File: text.py Project: achew22/err
 def build_message(self, text):
     return Message(self.build_text_html_message_pair(text)
                    [0])  # 0 = Only retain pure text
	def _message_event_handler(self, message):
		log.debug(message)
		data = message['data']

		# In some cases (direct messages) team_id is an empty string
		if data['team_id'] != '' and self.teamid != data['team_id']:
			log.info("Message came from another team ({}), ignoring...".format(data['team_id']))
			return

		broadcast = message['broadcast']

		if 'channel_id' in data:
			channelid = data['channel_id']
		elif 'channel_id' in broadcast:
			channelid = broadcast['channel_id']
		else:
			log.error("Couldn't find a channelid for event {}".format(message))
			return

		channel_type = data['channel_type']

		if channel_type != 'D':
			channel = data['channel_name']
		else:
			channel = channelid

		text = ''
		post_id = ''
		file_ids = None
		userid = None

		if 'post' in data:
			post = json.loads(data['post'])
			text = post['message']
			userid = post['user_id']
			if 'file_ids' in post:
				file_ids = post['file_ids']
			post_id = post['id']
			if 'type' in post and post['type'] == 'system_add_remove':
				log.info("Ignoring message from System")
				return

		if 'user_id' in data:
			userid = data['user_id']

		if not userid:
			log.error('No userid in event {}'.format(message))
			return

		mentions = []
		if 'mentions' in data:
			# TODO: Only user, not channel mentions are in here at the moment
			mentions = self.mentions_build_identifier(json.loads(data['mentions']))

		# Thread root post id
		root_id = post.get('root_id')
		if root_id is '':
			root_id = post_id

		msg = Message(
			text,
			extras={
				'id': post_id,
				'root_id': root_id,
				'mattermost_event': message,
				'url': '{scheme:s}://{domain:s}:{port:s}/{teamname:s}/pl/{postid:s}'.format(
					scheme=self.driver.options['scheme'],
					domain=self.driver.options['url'],
					port=str(self.driver.options['port']),
					teamname=self.team,
					postid=post_id
				)
			}
		)
		if file_ids:
			msg.extras['attachments'] = file_ids

		# TODO: Slack handles bots here, but I am not sure if bot users is a concept in mattermost
		if channel_type == 'D':
			msg.frm = MattermostPerson(self.driver, userid=userid, channelid=channelid, teamid=self.teamid)
			msg.to = MattermostPerson(
				self.driver, userid=self.bot_identifier.userid, channelid=channelid, teamid=self.teamid)
		elif channel_type == 'O' or channel_type == 'P':
			msg.frm = MattermostRoomOccupant(self.driver, userid=userid, channelid=channelid, teamid=self.teamid, bot=self)
			msg.to = MattermostRoom(channel, teamid=self.teamid, bot=self)
		else:
			log.warning('Unknown channel type \'{}\'! Unable to handle {}.'.format(
				channel_type,
				channel
			))
			return

		self.callback_message(msg)

		if mentions:
			self.callback_mention(msg, mentions)
Example #22
0
    def _message_event_handler(self, event):
        """Event handler for the 'message' event"""
        channel = event["channel"]
        if channel[0] not in "CGD":
            log.warning("Unknown message type! Unable to handle %s", channel)
            return

        subtype = event.get("subtype", None)

        if subtype in ("message_deleted", "channel_topic", "message_replied"):
            log.debug("Message of type %s, ignoring this event", subtype)
            return

        if subtype == "message_changed" and "attachments" in event["message"]:
            # If you paste a link into Slack, it does a call-out to grab details
            # from it so it can display this in the chatroom. These show up as
            # message_changed events with an 'attachments' key in the embedded
            # message. We should completely ignore these events otherwise we
            # could end up processing bot commands twice (user issues a command
            # containing a link, it gets processed, then Slack triggers the
            # message_changed event and we end up processing it again as a new
            # message. This is not what we want).
            log.debug(
                "Ignoring message_changed event with attachments, likely caused "
                "by Slack auto-expanding a link")
            return

        if "message" in event:
            text = event["message"].get("text", "")
            user = event["message"].get("user", event.get("bot_id"))
        else:
            text = event.get("text", "")
            user = event.get("user", event.get("bot_id"))

        text, mentioned = self.process_mentions(text)

        text = self.sanitize_uris(text)

        log.debug("Saw an event: %s", pprint.pformat(event))
        log.debug("Escaped IDs event text: %s", text)

        msg = Message(
            text,
            extras={
                "attachments": event.get("attachments"),
                "slack_event": event,
            },
        )

        if channel.startswith("D"):
            if subtype == "bot_message":
                msg.frm = SlackBot(
                    self.sc,
                    bot_id=event.get("bot_id"),
                    bot_username=event.get("username", ""),
                )
            else:
                msg.frm = SlackPerson(self.sc, user, event["channel"])
            msg.to = SlackPerson(
                self.sc,
                self.username_to_userid(self.sc.server.username),
                event["channel"],
            )
            channel_link_name = event["channel"]
        else:
            if subtype == "bot_message":
                msg.frm = SlackRoomBot(
                    self.sc,
                    bot_id=event.get("bot_id"),
                    bot_username=event.get("username", ""),
                    channelid=event["channel"],
                    bot=self,
                )
            else:
                msg.frm = SlackRoomOccupant(self.sc,
                                            user,
                                            event["channel"],
                                            bot=self)
            msg.to = SlackRoom(channelid=event["channel"], bot=self)
            channel_link_name = msg.to.name

        msg.extras["url"] = (
            f"https://{self.sc.server.domain}.slack.com/archives/"
            f'{channel_link_name}/p{self._ts_for_message(msg).replace(".", "")}'
        )

        self.callback_message(msg)

        if mentioned:
            self.callback_mention(msg, mentioned)
    def _message_event_handler(self, message):
        log.debug(message)
        data = message["data"]

        # In some cases (direct messages) team_id is an empty string
        if data["team_id"] != "" and self.teamid != data["team_id"]:
            log.info("Message came from another team ({}), ignoring...".format(
                data["team_id"]))
            return

        broadcast = message["broadcast"]

        if "channel_id" in data:
            channelid = data["channel_id"]
        elif "channel_id" in broadcast:
            channelid = broadcast["channel_id"]
        else:
            log.error("Couldn't find a channelid for event {}".format(message))
            return

        channel_type = data["channel_type"]

        if channel_type != "D":
            channel = data["channel_name"]
        else:
            channel = channelid

        text = ""
        post_id = ""
        file_ids = None
        userid = None

        if "post" in data:
            post = json.loads(data["post"])
            text = post["message"]
            userid = post["user_id"]
            if "file_ids" in post:
                file_ids = post["file_ids"]
            post_id = post["id"]
            if "type" in post and post["type"] == "system_add_remove":
                log.info("Ignoring message from System")
                return

        if "user_id" in data:
            userid = data["user_id"]

        if not userid:
            log.error("No userid in event {}".format(message))
            return

        mentions = []
        if "mentions" in data:
            # TODO: Only user, not channel mentions are in here at the moment
            mentions = self.mentions_build_identifier(
                json.loads(data["mentions"]))

        # Thread root post id
        root_id = post.get("root_id", "")
        if root_id == "":
            root_id = post_id

        msg = Message(
            text,
            extras={
                "id":
                post_id,
                "root_id":
                root_id,
                "mattermost_event":
                message,
                "url":
                "{scheme:s}://{domain:s}:{port:s}/{teamname:s}/pl/{postid:s}".
                format(
                    scheme=self.driver.options["scheme"],
                    domain=self.driver.options["url"],
                    port=str(self.driver.options["port"]),
                    teamname=self.team,
                    postid=post_id,
                ),
            },
        )
        if file_ids:
            msg.extras["attachments"] = file_ids

        # TODO: Slack handles bots here, but I am not sure if bot users is a concept in mattermost
        if channel_type == "D":
            msg.frm = MattermostPerson(self.driver,
                                       userid=userid,
                                       channelid=channelid,
                                       teamid=self.teamid)
            msg.to = MattermostPerson(
                self.driver,
                userid=self.bot_identifier.userid,
                channelid=channelid,
                teamid=self.teamid,
            )
        elif channel_type == "O" or channel_type == "P":
            msg.frm = MattermostRoomOccupant(
                self.driver,
                userid=userid,
                channelid=channelid,
                teamid=self.teamid,
                bot=self,
            )
            msg.to = MattermostRoom(channel, teamid=self.teamid, bot=self)
        else:
            log.warning(
                "Unknown channel type '{}'! Unable to handle {}.".format(
                    channel_type, channel))
            return

        self.callback_message(msg)

        if mentions:
            self.callback_mention(msg, mentions)
Example #24
0
 def on_privmsg(self, c, e):
     msg = Message(e.arguments[0])
     msg.setFrom(e.source.split('!')[0])
     msg.setTo(e.target)
     msg.setType('chat')
     self.callback.callback_message(self, msg)
Example #25
0
    def _message_event_handler(self, event):
        """Event handler for the 'message' event"""
        channel = event['channel']
        if channel.startswith('C'):
            log.debug("Handling message from a public channel")
            message_type = 'groupchat'
        elif channel.startswith('G'):
            log.debug("Handling message from a private group")
            message_type = 'groupchat'
        elif channel.startswith('D'):
            log.debug("Handling message from a user")
            message_type = 'chat'
        else:
            log.warning("Unknown message type! Unable to handle")
            return
        subtype = event.get('subtype', None)

        if subtype == "message_deleted":
            log.debug("Message of type message_deleted, ignoring this event")
            return
        if subtype == "message_changed" and 'attachments' in event['message']:
            # If you paste a link into Slack, it does a call-out to grab details
            # from it so it can display this in the chatroom. These show up as
            # message_changed events with an 'attachments' key in the embedded
            # message. We should completely ignore these events otherwise we
            # could end up processing bot commands twice (user issues a command
            # containing a link, it gets processed, then Slack triggers the
            # message_changed event and we end up processing it again as a new
            # message. This is not what we want).
            log.debug(
                "Ignoring message_changed event with attachments, likely caused "
                "by Slack auto-expanding a link")
            return

        if 'message' in event:
            text = event['message']['text']
            user = event['message'].get('user', event.get('bot_id'))
        else:
            text = event['text']
            user = event.get('user', event.get('bot_id'))

        text = re.sub("<[^>]*>", self.remove_angle_brackets_from_uris, text)

        log.debug("Saw an event: %s" % pprint.pformat(event))

        msg = Message(text,
                      type_=message_type,
                      extras={'attachments': event.get('attachments')})

        if message_type == 'chat':
            msg.frm = SlackIdentifier(self.sc, user, event['channel'])
            msg.to = SlackIdentifier(
                self.sc, self.username_to_userid(self.sc.server.username),
                event['channel'])
        else:
            msg.frm = SlackMUCOccupant(self.sc, user, event['channel'])
            msg.to = SlackMUCOccupant(
                self.sc, self.username_to_userid(self.sc.server.username),
                event['channel'])

        self.callback_message(msg)
Example #26
0
 def build_message(self, text):
     msg = Message(text)
     msg.frm = self.bot_identifier
     return msg  # rebuild a pure html snippet to include directly in the console html
Example #27
0
 def on_privmsg(self, _, e):
     msg = Message(e.arguments[0])
     msg.frm = IRCPerson(e.source)
     msg.to = IRCPerson(e.target)
     self.bot.callback_message(msg)
Example #28
0
    def _message_event_handler(self, event):
        """Event handler for the 'message' event"""
        channel = event['channel']
        if channel[0] not in 'CGD':
            log.warning("Unknown message type! Unable to handle %s", channel)
            return

        subtype = event.get('subtype', None)

        if subtype == "message_deleted":
            log.debug("Message of type message_deleted, ignoring this event")
            return
        if subtype == "message_changed" and 'attachments' in event['message']:
            # If you paste a link into Slack, it does a call-out to grab details
            # from it so it can display this in the chatroom. These show up as
            # message_changed events with an 'attachments' key in the embedded
            # message. We should completely ignore these events otherwise we
            # could end up processing bot commands twice (user issues a command
            # containing a link, it gets processed, then Slack triggers the
            # message_changed event and we end up processing it again as a new
            # message. This is not what we want).
            log.debug(
                "Ignoring message_changed event with attachments, likely caused "
                "by Slack auto-expanding a link")
            return

        if 'message' in event:
            text = event['message']['text']
            user = event['message'].get('user', event.get('bot_id'))
        else:
            text = event['text']
            user = event.get('user', event.get('bot_id'))

        mentioned = []

        for word in text.split():
            if word.startswith('<') or word.startswith('@') or word.startswith(
                    '#'):
                try:
                    identifier = self.build_identifier(word.replace(':', ''))
                except Exception as e:
                    log.debug(
                        "Tried to build an identifier from '%s' but got exception: %s",
                        word, e)
                    continue
                log.debug('Someone mentioned')
                mentioned.append(identifier)
                text = re.sub('<@[^>]*>:*', '@%s' % mentioned[-1].username,
                              text)

        text = self.sanitize_uris(text)

        log.debug("Saw an event: %s" % pprint.pformat(event))
        log.debug("Escaped IDs event text: %s" % text)

        msg = Message(text, extras={'attachments': event.get('attachments')})

        if channel.startswith('D'):
            msg.frm = SlackPerson(self.sc, user, event['channel'])
            msg.to = SlackPerson(
                self.sc, self.username_to_userid(self.sc.server.username),
                event['channel'])
        else:
            msg.frm = SlackRoomOccupant(self.sc,
                                        user,
                                        event['channel'],
                                        bot=self)
            msg.to = SlackRoom(channelid=event['channel'], bot=self)

        self.callback_message(msg)

        if mentioned:
            self.callback_mention(msg, mentioned)
Example #29
0
    def _message_event_handler(self, event):
        """Event handler for the 'message' event"""
        channel = event['channel']
        if channel[0] not in 'CGD':
            log.warning("Unknown message type! Unable to handle %s", channel)
            return

        subtype = event.get('subtype', None)

        if subtype in ("message_deleted", "channel_topic", "message_replied"):
            log.debug("Message of type %s, ignoring this event", subtype)
            return

        if subtype == "message_changed" and 'attachments' in event['message']:
            # If you paste a link into Slack, it does a call-out to grab details
            # from it so it can display this in the chatroom. These show up as
            # message_changed events with an 'attachments' key in the embedded
            # message. We should completely ignore these events otherwise we
            # could end up processing bot commands twice (user issues a command
            # containing a link, it gets processed, then Slack triggers the
            # message_changed event and we end up processing it again as a new
            # message. This is not what we want).
            log.debug(
                "Ignoring message_changed event with attachments, likely caused "
                "by Slack auto-expanding a link")
            return

        if 'message' in event:
            text = event['message'].get('text', '')
            user = event['message'].get('user', event.get('bot_id'))
        else:
            text = event.get('text', '')
            user = event.get('user', event.get('bot_id'))

        text, mentioned = self.process_mentions(text)

        text = self.sanitize_uris(text)

        log.debug("Saw an event: %s" % pprint.pformat(event))
        log.debug("Escaped IDs event text: %s" % text)

        msg = Message(
            text,
            extras={
                'attachments': event.get('attachments'),
                'slack_event': event,
            },
        )

        if channel.startswith('D'):
            if subtype == "bot_message":
                msg.frm = SlackBot(self.sc,
                                   bot_id=event['bot_id'],
                                   bot_username=event.get('username', ''))
            else:
                msg.frm = SlackPerson(self.sc, user, event['channel'])
            msg.to = SlackPerson(
                self.sc, self.username_to_userid(self.sc.server.username),
                event['channel'])
            channel_link_name = event['channel']
        else:
            if subtype == "bot_message":
                msg.frm = SlackRoomBot(self.sc,
                                       bot_id=event['bot_id'],
                                       bot_username=event.get('username', ''),
                                       channelid=event['channel'],
                                       bot=self)
            else:
                msg.frm = SlackRoomOccupant(self.sc,
                                            user,
                                            event['channel'],
                                            bot=self)
            msg.to = SlackRoom(channelid=event['channel'], bot=self)
            channel_link_name = msg.to.name

        msg.extras[
            'url'] = 'https://{domain}.slack.com/archives/{channelid}/p{ts}'.format(
                domain=self.sc.server.domain,
                channelid=channel_link_name,
                ts=self._ts_for_message(msg).replace('.', ''))

        self.callback_message(msg)

        if mentioned:
            self.callback_mention(msg, mentioned)
Example #30
0
    def serve_forever(self):
        self.readline_support()

        if not self._rooms:
            # artificially join a room if None were specified.
            self.query_room('#testroom').join()

        if self.demo_mode:
            # disable the console logging once it is serving in demo mode.
            root = logging.getLogger()
            root.removeHandler(console_hdlr)
            root.addHandler(logging.NullHandler())
        self.connect_callback()  # notify that the connection occured
        self.callback_presence(Presence(identifier=self.user, status=ONLINE))

        self.send_message(Message(INTRO))

        try:
            while True:

                if self._inroom:
                    frm = TextOccupant(self.user, self.rooms[0])
                    to = self.rooms[0]
                else:
                    frm = self.user
                    to = self.bot_identifier

                print()
                full_msg = ''
                while True:
                    prompt = '[␍] ' if full_msg else '>>> '
                    if ANSI or self.demo_mode:
                        color = fg.red if self.user.person in self.bot_config.BOT_ADMINS[
                            0] else fg.green
                        prompt = f'{color}[{frm} ➡ {to}] {fg.cyan}{prompt}{fx.reset}'
                        entry = input(prompt)
                    else:
                        entry = input(f'[{frm} ➡ {to}] {prompt}')

                    if not self._multiline:
                        full_msg = entry
                        break

                    if not entry:
                        break

                    full_msg += entry + '\n'

                msg = Message(full_msg)
                msg.frm = frm
                msg.to = to

                self.callback_message(msg)

                mentioned = [
                    self.build_identifier(word)
                    for word in re.findall(r'(?<=\s)@[\w]+', entry)
                ]
                if mentioned:
                    self.callback_mention(msg, mentioned)

                sleep(.5)
        except EOFError:
            pass
        except KeyboardInterrupt:
            pass
        finally:
            # simulate some real presence
            self.callback_presence(
                Presence(identifier=self.user, status=OFFLINE))
            log.debug("Trigger disconnect callback")
            self.disconnect_callback()
            log.debug("Trigger shutdown")
            self.shutdown()