예제 #1
0
def convecho(bot, event, *args):
    """echo back text into filtered conversations"""
    posix_args = get_posix_args(args)

    if(len(posix_args) > 1):
        if not posix_args[0]:
            """block spamming ALL conversations"""
            text = _("<em>sending to ALL conversations not allowed</em>")
            convlist = bot.conversations.get(filter=event.conv_id)
        else:
            convlist = bot.conversations.get(filter=posix_args[0])
            text = ' '.join(posix_args[1:])
            test_segments = simple_parse_to_segments(text)
            if test_segments:
                if test_segments[0].text.lower().strip().startswith(tuple([cmd.lower() for cmd in bot._handlers.bot_command])):
                    """detect and reject attempts to exploit botalias"""
                    text = _("<em>command echo blocked</em>")
                    convlist = bot.conversations.get(filter=event.conv_id)
    elif len(posix_args) == 1 and posix_args[0].startswith("id:"):
        """specialised error message for /devilbot echo (implied convid: <event.conv_id>)"""
        text = _("<em>missing text</em>")
        convlist = bot.conversations.get(filter=event.conv_id)
    else:
        """general error"""
        text = _("<em>required parameters: convfilter text</em>")
        convlist = bot.conversations.get(filter=event.conv_id)

    if not convlist:
        text = _("<em>no conversations filtered</em>")
        convlist = bot.conversations.get(filter=event.conv_id)

    for convid, convdata in convlist.items():
        yield from bot.coro_send_message(convid, text)
예제 #2
0
    def send_data(self,
                  conversation_id,
                  html,
                  image_data=None,
                  image_filename=None):
        """sends html and/or image to a conversation
        image_filename is recommended but optional, fallbacks to <timestamp>.jpg if undefined
        process_request() should determine the image extension prior to this
        """
        image_id = None
        if image_data:
            if not image_filename:
                image_filename = str(int(time.time())) + ".jpg"
                logging.warning(
                    "fallback image filename: {}".format(image_filename))

            image_id = yield from self._bot._client.upload_image(
                image_data, filename=image_filename)

        if not html and not image_id:
            print("{}: nothing to send".format(self.sinkname))
            return

        segments = simple_parse_to_segments(html)
        print("{}: sending segments: {}".format(self.sinkname, len(segments)))

        self._bot.send_message_segments(conversation_id,
                                        segments,
                                        context=None,
                                        image_id=image_id)
예제 #3
0
def convecho(bot, event, *args):
    """echo back text into filtered conversations"""
    posix_args = get_posix_args(args)

    if(len(posix_args) > 1):
        if not posix_args[0]:
            """block spamming ALL conversations"""
            text = _("<em>sending to ALL conversations not allowed</em>")
            convlist = bot.conversations.get(filter=event.conv_id)
        else:
            convlist = bot.conversations.get(filter=posix_args[0])
            text = ' '.join(posix_args[1:])
            test_segments = simple_parse_to_segments(text)
            if test_segments:
                if test_segments[0].text.lower().strip().startswith(tuple([cmd.lower() for cmd in bot._handlers.bot_command])):
                    """detect and reject attempts to exploit botalias"""
                    text = _("<em>command echo blocked</em>")
                    convlist = bot.conversations.get(filter=event.conv_id)
    elif len(posix_args) == 1 and posix_args[0].startswith("id:"):
        """specialised error message for /bot echo (implied convid: <event.conv_id>)"""
        text = _("<em>missing text</em>")
        convlist = bot.conversations.get(filter=event.conv_id)
    else:
        """general error"""
        text = _("<em>required parameters: convfilter text</em>")
        convlist = bot.conversations.get(filter=event.conv_id)

    if not convlist:
        text = _("<em>no conversations filtered</em>")
        convlist = bot.conversations.get(filter=event.conv_id)

    for convid, convdata in convlist.items():
        bot.send_message_parsed(convid, text)
예제 #4
0
    def process_payload(self, path, query_string, payload):
        sinkname = self.sinkname

        path = path.split("/")
        conversation_id = path[1]
        if conversation_id is None:
            print("{}: conversation id must be provided as part of path".format(sinkname))
            return

        image_id = None
        if "image" in payload:
            image_data = False
            image_filename = False
            if "base64encoded" in payload["image"]:
                raw = base64.b64decode(payload["image"]["base64encoded"])
                image_data = io.BytesIO(raw)
            if "filename" in payload["image"]:
                image_filename = payload["image"]["filename"]
            else:
                image_filename = str(int(time.time())) + ".jpg"
            print("{}: uploading image: {}".format(sinkname, image_filename))
            image_id = yield from webhookReceiver._bot._client.upload_image(image_data, filename=image_filename)

        html = ""
        if "echo" in payload:
            html = payload["echo"]
        else:
            # placeholder text
            html = "<b>hello world</b>"
        segments = simple_parse_to_segments(html)
        print("{} sending segments: {}".format(sinkname, len(segments)))

        webhookReceiver._bot.send_message_segments(conversation_id, segments, context=None, image_id=image_id)
예제 #5
0
def echoparsed(bot, event, *args):
    """echo back requested text"""
    formatted_text = ' '.join(args)
    test_segments = simple_parse_to_segments(formatted_text)
    if test_segments:
        if test_segments[0].text.strip().startswith(tuple([cmd.lower() for cmd in bot._handlers.bot_command])):
            formatted_text = _("NOPE! Some things aren't worth repeating.")
        bot.send_message_parsed(event.conv, formatted_text)
예제 #6
0
    def send_message_parsed(self, conversation, html, context=None, image_id=None):
        logger.debug(  '[DEPRECATED]: yield from bot.coro_send_message()'
                        ' instead of send_message_parsed()')

        segments = simple_parse_to_segments(html)

        asyncio.async(
            self.coro_send_message( conversation,
                                    segments,
                                    context=context,
                                    image_id=image_id )
        ).add_done_callback(lambda future: future.result())
예제 #7
0
    def send_message_parsed(self, conversation, html, context=None, image_id=None):
        logger.debug('[DEPRECATED]: yield from bot.coro_send_message()'
                     ' instead of send_message_parsed()')

        segments = simple_parse_to_segments(html)

        asyncio.async(
            self.coro_send_message(conversation,
                                   segments,
                                   context=context,
                                   image_id=image_id)
        ).add_done_callback(lambda future: future.result())
예제 #8
0
 def send_to_bridged_1to1(self, user_id, bridge_id, message):
     if bridge_id is None or bridge_id in self.conversations.catalog:
         # Bridge ID is in fact a hangout, defer to existing handling.
         conv = yield from self.get_1to1(user_id)
         yield from self.coro_send_message(conv.id_, message)
     elif bridge_id in self.bridges:
         # Defer to the bridge to handle sending this message.
         bridge = self.bridges[bridge_id]
         # Strip formatting -- we don't know what format the external side is expecting.
         # Turn it into segments and just keep the plain text.
         segments = simple_parse_to_segments(message)
         message = "".join(segment.text for segment in segments)
         yield from bridge.send_to_external_1to1(user_id, message)
예제 #9
0
    async def process_payload(self, path, query_string, payload):
        logging.warning(
            "[DEPRECATED] simpledemo.webhookReceiver, use sinks.generic.SimpleMessagePoster"
        )

        sinkname = self.sinkname

        path = path.split("/")
        conversation_id = path[1]
        if conversation_id is None:
            print(
                "{}: conversation id must be provided as part of path".format(
                    sinkname))
            return

        image_id = None
        if "image" in payload:
            image_data = False
            image_filename = False
            image_type = 'unknown'
            if "base64encoded" in payload["image"]:
                raw = base64.b64decode(payload["image"]["base64encoded"], None,
                                       True)
                image_data = io.BytesIO(raw)
                image_type = imghdr.what('ignore', raw)
                if not image_type:
                    image_type = 'error'
            if "filename" in payload["image"]:
                image_filename = payload["image"]["filename"]
            else:
                image_filename = str(int(time.time())) + "." + image_type
            print("{}: uploading image: {}".format(sinkname, image_filename))
            image_id = await webhookReceiver._bot._client.upload_image(
                image_data, filename=image_filename)

        html = ""
        if "echo" in payload:
            html = payload["echo"]
        else:
            # placeholder text
            html = "<b>hello world</b>"
        segments = simple_parse_to_segments(html)
        print("{} sending segments: {}".format(sinkname, len(segments)))

        await self._bot.coro_send_message(conversation_id,
                                          segments,
                                          context=None,
                                          image_id=image_id)
예제 #10
0
    def send_data(self, conversation_id, html, image_data=None, image_filename=None):
        """sends html and/or image to a conversation
        image_filename is optional, defaults to <timestamp>.jpg if not defined
        """
        image_id = None
        if image_data:
            if not image_filename:
                image_filename = str(int(time.time())) + ".jpg"
            image_id = yield from self._bot._client.upload_image(image_data, filename=image_filename)

        if not html and not image_id:
            print("{}: nothing to send".format(self.sinkname))
            return

        segments = simple_parse_to_segments(html)
        print("{}: sending segments: {}".format(self.sinkname, len(segments)))

        self._bot.send_message_segments(conversation_id, segments, context=None, image_id=image_id)
예제 #11
0
def echoparsed(bot, event, *args):
    """echo back requested text"""

    # Check if the first argument is a known conv_id match
    if args[0] in list(bot.memory.get_by_path(["conv_data"]).keys()):
        formatted_text = ' '.join(args[1:])
        conv_id = args[0]

    else:
        formatted_text = ' '.join(args)
        conv_id = event.conv_id

    test_segments = simple_parse_to_segments(formatted_text)
    if test_segments:
        if test_segments[0].text.strip().startswith(tuple([cmd.lower() for cmd in bot._handlers.bot_command])):
            formatted_text = _("NOPE! Some things aren't worth repeating.")
            conv_id = event.conv_id

    bot.send_message_parsed(conv_id, formatted_text)
예제 #12
0
    def process_payload(self, path, query_string, payload):
        logging.warning(
            "[DEPRECATED] simpledemo.webhookReceiver, use sinks.generic.SimpleMessagePoster")

        sinkname = self.sinkname

        path = path.split("/")
        conversation_id = path[1]
        if conversation_id is None:
            print("{}: conversation id must be provided as part of path".format(sinkname))
            return

        image_id = None
        if "image" in payload:
            image_data = False
            image_filename = False
            image_type = 'unknown'
            if "base64encoded" in payload["image"]:
                raw = base64.b64decode(
                    payload["image"]["base64encoded"], None, True)
                image_data = io.BytesIO(raw)
                image_type = imghdr.what('ignore', raw)
                if not image_type:
                    image_type = 'error'
            if "filename" in payload["image"]:
                image_filename = payload["image"]["filename"]
            else:
                image_filename = str(int(time.time())) + "." + image_type
            print("{}: uploading image: {}".format(sinkname, image_filename))
            image_id = yield from webhookReceiver._bot._client.upload_image(image_data, filename=image_filename)

        html = ""
        if "echo" in payload:
            html = payload["echo"]
        else:
            # placeholder text
            html = "<b>hello world</b>"
        segments = simple_parse_to_segments(html)
        print("{} sending segments: {}".format(sinkname, len(segments)))

        yield from self._bot.coro_send_message(conversation_id, segments, context=None, image_id=image_id)
    def send_data(self, conversation_id, html, image_data=None, image_filename=None):
        """sends html and/or image to a conversation
        image_filename is recommended but optional, fallbacks to <timestamp>.jpg if undefined
        process_request() should determine the image extension prior to this
        """
        image_id = None
        if image_data:
            if not image_filename:
                image_filename = str(int(time.time())) + ".jpg"
                logging.warning("fallback image filename: {}".format(image_filename))

            image_id = yield from self._bot._client.upload_image(image_data, filename=image_filename)

        if not html and not image_id:
            print("{}: nothing to send".format(self.sinkname))
            return

        segments = simple_parse_to_segments(html)
        print("{}: sending segments: {}".format(self.sinkname, len(segments)))

        self._bot.send_message_segments(conversation_id, segments, context=None, image_id=image_id)
예제 #14
0
    def coro_send_message(self, conversation, message, context=None, image_id=None):
        if not message and not image_id:
            # at least a message OR an image_id must be supplied
            return

        # get the context

        if not context:
            context = {}

        if "base" not in context:
            # default legacy context
            context["base"] = self._messagecontext_legacy()

        # get the conversation id

        if isinstance(conversation, (FakeConversation, hangups.conversation.Conversation)):
            conversation_id = conversation.id_
        elif isinstance(conversation, str):
            conversation_id = conversation
        else:
            raise ValueError('could not identify conversation id')

        # parse message strings to segments

        if message is None:
            segments = []
        elif "parser" in context and context["parser"] is False and isinstance(message, str):
            message = re.sub('f**k', 'fsck', message, flags=re.I)
            message = re.sub('n***a|nigger', 'n***a', message, flags=re.I)
            message = re.sub('bitch', 'b***h', message, flags=re.I)
            message = re.sub('w***e', 'w***e', message, flags=re.I)
            segments = [hangups.ChatMessageSegment(message)]
        elif isinstance(message, str):
            message = re.sub('f**k', 'fsck', message, flags=re.I)
            message = re.sub('n***a|nigger', 'n***a', message, flags=re.I)
            message = re.sub('bitch', 'b***h', message, flags=re.I)
            message = re.sub('w***e', 'w***e', message, flags=re.I)
            segments = simple_parse_to_segments(message)
        elif isinstance(message, list):
            message = [re.sub('f**k', 'fsck', seg, flags=re.I)
                       for seg in message]
            message = [re.sub('n***a|nigger', 'n***a', seg, flags=re.I)
                       for seg in message]
            message = [re.sub('bitch', 'b***h', seg, flags=re.I)
                       for seg in message]
            message = [re.sub('w***e', 'w***e', seg, flags=re.I)
                       for seg in message]
            segments = message
        else:
            raise TypeError("unknown message type supplied")

        # determine OTR status

        if "history" not in context:
            context["history"] = True
            try:
                context["history"] = self.conversations.catalog[
                    conversation_id]["history"]

            except KeyError:
                # rare scenario where a conversation was not refreshed
                # once the initial message goes through, convmem will be
                # updated
                logger.warning("CORO_SEND_MESSAGE(): could not determine otr for {}".format(
                    conversation_id))

        if context["history"]:
            otr_status = OffTheRecordStatus.ON_THE_RECORD
        else:
            otr_status = OffTheRecordStatus.OFF_THE_RECORD

        broadcast_list = [(conversation_id, segments)]

        # run any sending handlers

        try:
            yield from self._handlers.run_pluggable_omnibus("sending", self, broadcast_list, context)
        except self.Exceptions.SuppressEventHandling:
            logger.info("message sending: SuppressEventHandling")
            return
        except:
            raise

        logger.debug("message sending: global context = {}".format(context))

        # begin message sending.. for REAL!

        for response in broadcast_list:
            logger.debug("message sending: {}".format(response[0]))

            # send messages using FakeConversation as a workaround

            _fc = FakeConversation(self._client, response[0])
            try:
                yield from _fc.send_message(response[1],
                                            image_id=image_id,
                                            otr_status=otr_status)
            except hangups.NetworkError as e:
                logger.exception(
                    "CORO_SEND_MESSAGE: error sending {}".format(response[0]))
    def send_message(self, message, image_id=None, otr_status=None, context=None):

        """ChatMessageSegment: parse message"""

        if message is None:
            # nothing to do if the message is blank
            segments = []
            raw_message = ""
        elif "parser" in context and context["parser"] is False and isinstance(message, str):
            # no parsing requested, escape anything in raw_message that can be construed as valid markdown
            segments = [hangups.ChatMessageSegment(message)]
            raw_message = message.replace("*", "\\*").replace("_", "\\_").replace("`", "\\`")
        elif isinstance(message, str):
            # preferred method: markdown-formatted message (or less preferable but OK: html)
            segments = simple_parse_to_segments(message)
            raw_message = message
        elif isinstance(message, list):
            # who does this anymore?
            logger.error( "[INVALID]: send messages as html or markdown, "
                          "not as list of ChatMessageSegment, context={}".format(context) )
            segments = message
            raw_message = "".join([ segment_to_html(seg)
                                    for seg in message ])
        else:
            raise TypeError("unknown message type supplied")

        if segments:
            serialised_segments = [seg.serialize() for seg in segments]
        else:
            serialised_segments = None

        if "original_request" not in context["passthru"]:
            context["passthru"]["original_request"] = { "message": raw_message,
                                                        "image_id": image_id,
                                                        "segments": segments }

        """OffTheRecordStatus: determine history"""

        if otr_status is None:
            if "history" not in context:
                context["history"] = True
                try:
                    context["history"] = self.bot.conversations.catalog[self.id_]["history"]

                except KeyError:
                    # rare scenario where a conversation was not refreshed
                    # once the initial message goes through, convmem will be updated
                    logger.warning("could not determine otr for {}".format(self.id_))

            if context["history"]:
                otr_status = hangups_shim.schemas.OffTheRecordStatus.ON_THE_RECORD
            else:
                otr_status = hangups_shim.schemas.OffTheRecordStatus.OFF_THE_RECORD

        """ExistingMedia: attach previously uploaded media for display"""

        media_attachment = None
        if image_id:
            media_attachment = hangups.hangouts_pb2.ExistingMedia(
                photo = hangups.hangouts_pb2.Photo( photo_id = image_id ))

        """EventAnnotation: combine with client-side storage to allow custom messaging context"""

        annotations = []
        if "reprocessor" in context:
            annotations.append( hangups.hangouts_pb2.EventAnnotation(
                type = 1025,
                value = context["reprocessor"]["id"] ))

        # define explicit "passthru" in context to "send" any type of variable
        if "passthru" in context:
            annotations.append( hangups.hangouts_pb2.EventAnnotation(
                type = 1026,
                value = self.bot._handlers.register_passthru(context["passthru"]) ))

        # always implicitly "send" the entire context dictionary
        annotations.append( hangups.hangouts_pb2.EventAnnotation(
            type = 1027,
            value = self.bot._handlers.register_context(context) ))

        """send the message"""

        with (yield from asyncio.Lock()):
            yield from self._client.send_chat_message(
                hangups.hangouts_pb2.SendChatMessageRequest(
                    request_header = self._client.get_request_header(),
                    message_content = hangups.hangouts_pb2.MessageContent( segment=serialised_segments ),
                    existing_media = media_attachment,
                    annotation = annotations,
                    event_request_header = hangups.hangouts_pb2.EventRequestHeader(
                        conversation_id=hangups.hangouts_pb2.ConversationId( id=self.id_ ),
                        client_generated_id=self._client.get_client_generated_id(),
                        expected_otr = otr_status )))
예제 #16
0
    def coro_send_message(self,
                          conversation,
                          message,
                          context=None,
                          image_id=None):
        if not message and not image_id:
            # at least a message OR an image_id must be supplied
            return

        # get the context

        if not context:
            context = {}

        if "base" not in context:
            # default legacy context
            context["base"] = self._messagecontext_legacy()

        # get the conversation id

        if isinstance(conversation,
                      (FakeConversation, hangups.conversation.Conversation)):
            conversation_id = conversation.id_
        elif isinstance(conversation, str):
            conversation_id = conversation
        else:
            raise ValueError('could not identify conversation id')

        # parse message strings to segments

        if message is None:
            segments = []
        elif "parser" in context and context["parser"] is False and isinstance(
                message, str):
            segments = [hangups.ChatMessageSegment(message)]
        elif isinstance(message, str):
            segments = simple_parse_to_segments(message)
        elif isinstance(message, list):
            segments = message
        else:
            raise TypeError("unknown message type supplied")

        # determine OTR status

        if "history" not in context:
            context["history"] = True
            try:
                context["history"] = self.conversations.catalog[
                    conversation_id]["history"]

            except KeyError:
                # rare scenario where a conversation was not refreshed
                # once the initial message goes through, convmem will be updated
                logger.warning(
                    "CORO_SEND_MESSAGE(): could not determine otr for {}".
                    format(conversation_id))

        if context["history"]:
            otr_status = OffTheRecordStatus.ON_THE_RECORD
        else:
            otr_status = OffTheRecordStatus.OFF_THE_RECORD

        broadcast_list = [(conversation_id, segments)]

        # run any sending handlers

        try:
            yield from self._handlers.run_pluggable_omnibus(
                "sending", self, broadcast_list, context)
        except self.Exceptions.SuppressEventHandling:
            logger.info("message sending: SuppressEventHandling")
            return
        except:
            raise

        logger.debug("message sending: global context = {}".format(context))

        # begin message sending.. for REAL!

        for response in broadcast_list:
            logger.debug("message sending: {}".format(response[0]))

            # send messages using FakeConversation as a workaround

            _fc = FakeConversation(self._client, response[0])

            try:
                yield from _fc.send_message(response[1],
                                            image_id=image_id,
                                            otr_status=otr_status)
            except hangups.NetworkError as e:
                logger.exception("CORO_SEND_MESSAGE: error sending {}".format(
                    response[0]))
예제 #17
0
 def send_message_parsed(self, conversation, html):
     segments = simple_parse_to_segments(html)
     self.send_message_segments(conversation, segments)
예제 #18
0
    def send_message(self,
                     message,
                     image_id=None,
                     otr_status=None,
                     context=None):
        """ChatMessageSegment: parse message"""

        if message is None:
            # nothing to do if the message is blank
            segments = []
            raw_message = ""
        elif "parser" in context and context["parser"] is False and isinstance(
                message, str):
            # no parsing requested, escape anything in raw_message that can be construed as valid markdown
            segments = [hangups.ChatMessageSegment(message)]
            raw_message = message.replace("*", "\\*").replace("_",
                                                              "\\_").replace(
                                                                  "`", "\\`")
        elif isinstance(message, str):
            # preferred method: markdown-formatted message (or less preferable but OK: html)
            segments = simple_parse_to_segments(message)
            raw_message = message
        elif isinstance(message, list):
            # who does this anymore?
            logger.error(
                "[INVALID]: send messages as html or markdown, "
                "not as list of ChatMessageSegment, context={}".format(
                    context))
            segments = message
            raw_message = "".join([segment_to_html(seg) for seg in message])
        else:
            raise TypeError("unknown message type supplied")

        if segments:
            serialised_segments = [seg.serialize() for seg in segments]
        else:
            serialised_segments = None

        if "original_request" not in context["passthru"]:
            context["passthru"]["original_request"] = {
                "message": raw_message,
                "image_id": image_id,
                "segments": segments
            }
        """OffTheRecordStatus: determine history"""

        if otr_status is None:
            if "history" not in context:
                context["history"] = True
                try:
                    context["history"] = self.bot.conversations.catalog[
                        self.id_]["history"]

                except KeyError:
                    # rare scenario where a conversation was not refreshed
                    # once the initial message goes through, convmem will be updated
                    logger.warning("could not determine otr for {}".format(
                        self.id_))

            if context["history"]:
                otr_status = hangups_shim.schemas.OffTheRecordStatus.ON_THE_RECORD
            else:
                otr_status = hangups_shim.schemas.OffTheRecordStatus.OFF_THE_RECORD
        """ExistingMedia: attach previously uploaded media for display"""

        media_attachment = None
        if image_id:
            media_attachment = hangups.hangouts_pb2.ExistingMedia(
                photo=hangups.hangouts_pb2.Photo(photo_id=image_id))
        """EventAnnotation: combine with client-side storage to allow custom messaging context"""

        annotations = []
        if "reprocessor" in context:
            annotations.append(
                hangups.hangouts_pb2.EventAnnotation(
                    type=1025, value=context["reprocessor"]["id"]))

        # define explicit "passthru" in context to "send" any type of variable
        if "passthru" in context:
            annotations.append(
                hangups.hangouts_pb2.EventAnnotation(
                    type=1026,
                    value=self.bot._handlers.register_passthru(
                        context["passthru"])))

        # always implicitly "send" the entire context dictionary
        annotations.append(
            hangups.hangouts_pb2.EventAnnotation(
                type=1027, value=self.bot._handlers.register_context(context)))
        """ Assuming working with phones """
        default_medium = hangups.hangouts_pb2.DeliveryMedium(
            medium_type=hangups.hangouts_pb2.DELIVERY_MEDIUM_GOOGLE_VOICE)
        """send the message"""

        with (yield from asyncio.Lock()):
            yield from self._client.send_chat_message(
                hangups.hangouts_pb2.SendChatMessageRequest(
                    request_header=self._client.get_request_header(),
                    message_content=hangups.hangouts_pb2.MessageContent(
                        segment=serialised_segments),
                    existing_media=media_attachment,
                    annotation=annotations,
                    event_request_header=hangups.hangouts_pb2.
                    EventRequestHeader(
                        conversation_id=hangups.hangouts_pb2.ConversationId(
                            id=self.id_),
                        client_generated_id=self._client.
                        get_client_generated_id(),
                        expected_otr=otr_status,
                        delivery_medium=default_medium)))
예제 #19
0
 def send_message_parsed(self, conversation, html, context=None):
     segments = simple_parse_to_segments(html)
     self.send_message_segments(conversation, segments, context)