Beispiel #1
0
def main(host, username, password, room_id_alias):
    client = MatrixClient(host)
    try:
        client.login_with_password(username, password)
    except MatrixRequestError as e:
        print(e)
        if e.code == 403:
            print ""
        else:
            print ""
    except MissingSchema as e:
        print(e)
    try:
        room = client.join_room(room_id_alias)
    except MatrixRequestError as e:
        print(e)
        if e.code == 400:
            print ""
        else:
            print ""
            
    room.add_listener(on_message)
    client.start_listener_thread()

    while True:
        
        time.sleep(5)
Beispiel #2
0
    def change_password(self, mxid, old_password, new_password):
        """Change a user's password.
        Warning: this function is slow as balls."""
        matrix = MatrixClient(self._server)
        matrix.login_with_password(username=mxid, password=old_password)

        body = {
            "auth": {
                "type": "m.login.password",
                "user": mxid,
                "password": old_password
            },
            "new_password": new_password
        }

        try:
            matrix.api._send('POST',
                             '/account/password',
                             body,
                             api_path='/_matrix/client/r0')
            return True

        except MatrixRequestError as exception:
            print exception
            return False
Beispiel #3
0
 def login_by_password():
     """Login using password authentication."""
     try:
         _client = MatrixClient(base_url=homeserver, valid_cert_check=verify_tls)
         _client.login_with_password(username, password)
         store_token(mx_id, _client.token)
         return _client
     except MatrixRequestError as ex:
         _LOGGER.error("login_by_password: (%d) %s", ex.code, ex.content)
def matrix_client():
    global _client
    if _client:
        return _client
    print(f"Signing into {MATRIX_HOST}...")
    client = MatrixClient(MATRIX_HOST)
    client.login_with_password(username=MATRIX_USER, password=MATRIX_PASSWORD)
    _client = client
    return client
Beispiel #5
0
def setup(config):
    """Sets up the Matrix client. Makes sure the (specified) room is joined.
    """
    client = MatrixClient("https://{0}:{1}".format(config['homeserver'],
                                                   int(config['port'])))
    client.login_with_password(username=config['username'],
                               password=config['password'])
    room = client.join_room('{0}:{1}'.format(config['room'], config['domain']))
    return client, room
Beispiel #6
0
 def login_by_password():
     """Login using password authentication."""
     try:
         _client = MatrixClient(base_url=homeserver,
                                valid_cert_check=verify_tls)
         _client.login_with_password(username, password)
         store_token(mx_id, _client.token)
         return _client
     except MatrixRequestError as ex:
         _LOGGER.error('login_by_password: (%d) %s', ex.code, ex.content)
Beispiel #7
0
    def _login_by_password(self):
        """Login using password authentication and return the client."""
        _client = MatrixClient(base_url=self._homeserver,
                               valid_cert_check=self._verify_tls)

        _client.login_with_password(self._mx_id, self._password)

        self._store_auth_token(_client.token)

        return _client
Beispiel #8
0
def main():
    global g_client
    print("Connecting to server: {}".format(botconfig.client_url))
    g_client = MatrixClient(botconfig.client_url)

    password = get_password()

    try:
        print("Logging in with username: {}".format(botconfig.username))
        g_client.login_with_password(botconfig.username, password)
    except MatrixRequestError as e:
        print(e)
        if e.code == 403:
            print("Bad username or password.")
            sys.exit(4)
        else:
            print("Check your sever details are correct.")
            sys.exit(2)
    except MissingSchema as e:
        print("Bad URL format.")
        print(e)
        sys.exit(3)

    # room dictionary that will be passed to the listener manager
    rooms = {}

    for room_address in botconfig.rooms:
        try:
            room = g_client.join_room(room_address)
            room.add_listener(on_message)
            rooms[room_address] = room
            print("Joined room: {}".format(room_address))
        except MatrixRequestError as e:
            print(e)
            if e.code == 400:
                print("{}: Room ID/Alias in the wrong format".format(
                    room_address))
                sys.exit(11)
            else:
                print("Couldn't find room: {}".format(room_address))
                sys.exit(12)

    g_client.add_invite_listener(on_invite)

    g_client.start_listener_thread()

    listener = ListenerManager(rooms, botconfig.listener_port)

    listener.start_listener_thread()

    try:
        while True:
            pass
    except KeyboardInterrupt:
        print("Shutting down.")
Beispiel #9
0
class Matrix(object):
    def __init__(self, main):
        self.main = main
        self.login = login

        self.client = MatrixClient(address)
        self.client.login_with_password(login, passwd)

        self.rooms = []
        self.room_data = {}

        for room_id, room in self.client.get_rooms().items():
            self.main.system(f'add matrix room {room_id}')
            self.rooms.append(room_id)
            self.room_data[room_id] = {
                'history': [],
                'last_read': 0,
                'name': room.name or room_id,
                'topic': room.topic or '',
            }
            for event in room.events:
                if event['type'] == 'm.room.message':
                    self.room_data[room_id]['history'].append(
                        self.event_to_history(event))
            if chan in room.aliases:
                self.main.active_room_idx = len(self.rooms) - 1
                self.main.active_account_idx = 1
            room.add_listener(self.listener)
        self.client.start_listener_thread()

    def __str__(self):
        return f'Matrix {self.login}'

    def event_to_history(self, event):
        self.add_sender(event['sender'])
        return datetime.fromtimestamp(
            event['origin_server_ts'] /
            1000), event['sender'], event['content']['body']

    def add_sender(self, sender):
        if sender not in self.main.users:
            self.main.users[sender] = self.client.api.get_display_name(sender)

    def listener(self, room, event):
        if event['type'] == 'm.room.message':
            history = self.room_data[room.room_id]['history']
            history.append(self.event_to_history(event))
            if self.main.account == self and room.room_id == self.main.room_id:
                self.main.update_text(history)
        else:
            self.main.system(str(event))

    def send(self, text, room_id):
        self.client.api.send_message(room_id, text)
    def login_by_password(self):
        """Login using password authentication and return the client."""
        from matrix_client.client import MatrixClient

        _client = MatrixClient(base_url=self.homeserver,
                               valid_cert_check=self.verify_tls)

        _client.login_with_password(self.username, self.password)

        self.store_auth_token(_client.token)

        return _client
Beispiel #11
0
    def _login_by_password(self):
        """Login using password authentication and return the client."""
        from matrix_client.client import MatrixClient

        _client = MatrixClient(
            base_url=self._homeserver,
            valid_cert_check=self._verify_tls)

        _client.login_with_password(self._mx_id, self._password)

        self._store_auth_token(_client.token)

        return _client
Beispiel #12
0
    def __init__(self, server, username, password, rooms, nick=None):
        client = MatrixClient(server)
        self.viewer_url = server.strip('/') + "/_matrix/media/v1/download/"

        try:
            client.login_with_password(username, password)
        except MatrixRequestError as e:
            if e.code == 403:
                logger.error("403 Bad username or password.")
                sys.exit(4)
            else:
                logger.error("{} Check your server details are correct.".format(e))
                sys.exit(2)
        except MissingSchema as e:
            logger.error("{} Bad URL format.".format(e))
            sys.exit(3)

        self.username = client.user_id
        logger.info("logged in as: {}".format(self.username))

        if nick is not None:
            u = client.get_user(client.user_id)
            logger.info("Setting display name to {}".format(nick))
            try:
                u.set_display_name(nick)
            except MatrixRequestError as e:
                logger.error("Fail to set display name: error = {}".format(e))

        self.joined_rooms = {}
        self.room_id_to_alias = {}
        self.displaynames = {}

        for room_id_alias in rooms:
            try:
                room = client.join_room(room_id_alias)
            except MatrixRequestError as e:
                if e.code == 400:
                    logger.error("400 Room ID/Alias in the wrong format")
                    sys.exit(11)
                else:
                    logger.error("{} Couldn't find room {}".format(e, room_id_alias))
                    sys.exit(12)
            logger.info("Joined room {}".format(room_id_alias))
            self.joined_rooms[room_id_alias] = room
            self.room_id_to_alias[room.room_id] = room_id_alias
            room.add_listener(self.on_message)

        self.client = client
        self.bot_msg_pattern = config['matrix'].get('bot_msg_pattern', None)
Beispiel #13
0
class ZmalauBot():
    def __init__(self, username, password, roomname):
        # connect to room
        self.crypto = CryptoEngine()
        self.air_pollution = AirPollutionEngine()
        self.client = MatrixClient("http://matrix.org")
        self.token = self.client.login_with_password(username=username,
                                                     password=password)
        self.room = self.client.join_room(roomname)

        # add bot reactions
        self.room.add_listener(self.on_message)
        self.client.start_listener_thread()

        self.room.send_text('Dzień dobry')

    def default_response(self, message):
        return self.crypto.analyze_message_and_prepare_response(message)

    def on_message(self, room, event):
        if event['type'] == "m.room.message":
            if USERNAME in event['sender']:
                return
            if event['content']['msgtype'] == "m.text":
                message = event['content']['body']
                m = message.lower()
                if 'zmalau' in m or 'urus' in m:
                    if any([word in m for word in self.crypto.trigger_words]):
                        response = self.crypto.analyze_message_and_prepare_response(m)
                    elif any([word in m for word in self.air_pollution.trigger_words]):
                        response = self.air_pollution.analyze_message_and_prepare_response(m)
                    else:
                        response = self.default_response(m)
                    self.room.send_text(response)
def example(host, user, password, token):
    """run the example."""
    client = None
    try:
        if token:
            print('token login')
            client = MatrixClient(host, token=token, user_id=user)
        else:
            print('password login')
            client = MatrixClient(host)
            token = client.login_with_password(user, password)
            print('got token: %s' % token)
    except MatrixRequestError as e:
        print(e)
        if e.code == 403:
            print("Bad username or password")
            exit(2)
        elif e.code == 401:
            print("Bad username or token")
            exit(3)
        else:
            print("Verify server details.")
            exit(4)
    except MissingSchema as e:
        print(e)
        print("Bad formatting of URL.")
        exit(5)
    except InvalidSchema as e:
        print(e)
        print("Invalid URL schema")
        exit(6)
    print("is in rooms")
    for room_id, room in client.get_rooms().items():
        print(room_id)
Beispiel #15
0
class Director:
    def __init__(self):
        self.BOTUSERNAME = "******"
        self.BOTPASSWORD = "******"
        self.BOTSERVO = "matrix.org"
        self.RID = "!RnpiUpFIsfzZfHdHQf:matrix.org"
        self.realRID = "!obQcCWaLRAUgiGBvMg:postmarketos.org"
        self.MainClient = MatrixClient("https://" + self.BOTSERVO)
        self.token = self.MainClient.login_with_password(
            username=self.BOTUSERNAME, password=self.BOTPASSWORD)
        self.APIWrapper = MatrixHttpApi("https://" + self.BOTSERVO,
                                        token=self.token)
        self.target_room = Room(self.MainClient, self.RID)
        print("ready")

    def mainThread(self):
        self.MainClient.add_listener(self.callback_event,
                                     event_type="m.room.member")
        self.MainClient.start_listener_thread()
        while True:
            input()

    def callback_event(room, event):
        if event.get("content").get("membership") == "join":
            user_id = event.get("sender")
            d.target_room.send_html(
                'This room is not official postmarketOS room. Please join the <a href="https://matrix.to/#/#porting:postmarketos.org">#porting:postmarketos.org</a> room'
            )
            try:
                d.APIWrapper.invite_user(d.realRID, user_id)
            except:
                pass  # user already joined the rooms
Beispiel #16
0
class Bot:
    def __init__(self, hs_url, username, password):
        self.cli = MatrixClient(hs_url)
        self.cli.login_with_password(username=username, password=password)
        self.shelf = shelve.open(data_file, writeback=True)
        signal.signal(signal.SIGTERM, self.close_shelf)
        signal.signal(signal.SIGINT, self.close_shelf)
        self.cli.add_invite_listener(self.on_invite)
        self.joined_rooms = self.cli.get_rooms()
        logger.info(
            f'Joined to {[r.display_name for r in self.joined_rooms.values()]}'
        )
        self.add_room_listeners()

    def run(self):
        self.cli.listen_forever(exception_handler=self.sync_exception_handler)
        logger.info('Bot started.')

    def add_room_listeners(self):
        for room in self.joined_rooms.values():
            self.add_local_bot(room)

    def on_invite(self, room_id, state):
        room = self.cli.join_room(room_id)
        # Force a sync in order not to process previous room messages
        self.cli._sync()
        self.add_local_bot(room)
        self.joined_rooms[room_id] = room
        room.send_notice(
            f'Hi! I\'m a list keeping bot. Send {LocalBot.prefix}help'
            ' to learn how to use me.')
        logger.info(
            f'Received an invite for room {room.display_name}, and joined.')

    def add_local_bot(self, room):
        lbot = LocalBot(room, self.cli.api, self.shelf)
        room.add_listener(lbot.on_message, event_type='m.room.message')

    def close_shelf(self, *args):
        logger.info('Closing shelf...')
        self.shelf.close()
        logger.info('Shelf is closed.')
        sys.exit()

    @staticmethod
    def sync_exception_handler(exception):
        logger.warning(exception)
Beispiel #17
0
def main(host, username, password):
    client = MatrixClient(host)
    rooms = client.get_rooms()

    try:
        db = sqlite3.connect('db')
        cursor = db.cursor()
        cursor.execute(
            '''CREATE TABLE IF NOT EXISTS messages(id INTEGER PRIMARY KEY, date TEXT, roomid TEXT, sender TEXT, message TEXT)'''
        )
        db.commit()
    except Exception as e:
        db.rollback()
        raise e
    finally:
        db.close()

    def on_invite(room_id, state):
        print("joining room " + room_id)
        room = client.join_room(room_id)
        room.add_listener(on_message)

    try:
        token = client.login_with_password(username, password)
        global matrix
        matrix = MatrixHttpApi(host, token)
    except MatrixRequestError as e:
        print(e)
        if e.code == 403:
            print("Bad username or password.")
            sys.exit(4)
        else:
            print("Check if server details are correct.")
            sys.exit(2)
    except MissingSchema as e:
        print("Bad URL format.")
        print(e)
        sys.exit(3)

    for room in rooms:
        try:
            roomname = matrix.get_room_name(room)
            print("Already in room " + roomname['name'])
            room_to_listen = client.join_room(room)
            room_to_listen.add_listener(on_message)
        except MatrixRequestError as e:
            print(e)
            if e.code == 400:
                print("Room ID/Alias in the wrong format")
                sys.exit(11)
            else:
                print("Couldn't find room.")
                sys.exit(12)

    client.add_invite_listener(on_invite)
    client.start_listener_thread()

    while True:
        time.sleep(30)
Beispiel #18
0
    def run(self):
        client = MatrixClient(self._mconf.host)

        try:
            log.debug('Logging into Matrix')
            client.login_with_password(self._mconf.username,
                                       self._mconf.password)
        except MatrixRequestError as e:
            if e.code == 403:
                log.error('Bad username or password: {}'.format(str(e)))
                sys.exit(2)
            else:
                log.error(
                    'Could not log in - check the server details are correct: {}'
                    .format(str(e)))
                sys.exit(2)
        except Exception as e:
            log.error('Error while logging in: {}'.format(str(e)))
            sys.exit(2)

        log.debug('Joining rooms')
        self._rooms = []
        for room_id in self._mconf.rooms:
            try:
                room = client.join_room(room_id)
            except MatrixRequestError as e:
                if e.code == 400:
                    log.error(
                        'Room ID/Alias ("{}") in the wrong format. Can not join room: {}'
                        .format(room_id, str(e)))
                    sys.exit(2)
                else:
                    log.error('Could not find room "{}"'.format(room_id))
                    sys.exit(2)

            room.add_listener(self._on_room_message)
            self._rooms.append(room)

        log.info('Logged into Matrix, ready to publish information')
        client.start_listener_thread()

        while True:
            topic, msg_b = self._lhsub_socket.recv_multipart()
            # TODO: Validate signature here!
            event = json.loads(str(msg_b, 'utf-8'))
            self._on_event_received(event)
Beispiel #19
0
def setup(config):
    """Sets up the Matrix client. Makes sure the (specified) room is joined.
    """
    loginargs = {}
    if 'token' in config:
        loginargs['user_id'] = '@{0}:{1}'.format(config['username'],
                                                 config['domain'])
        loginargs['token'] = config['token']

    client = MatrixClient(
        "https://{0}:{1}".format(config['homeserver'], int(config['port'])),
        **loginargs)
    if 'token' not in config:
        client.login_with_password(username=config['username'],
                                   password=config['password'])

    room = client.join_room('{0}:{1}'.format(config['room'], config['domain']))
    return client, room
Beispiel #20
0
def main(host, username, password, room_id_alias):
    client = MatrixClient(host)

    try:
        client.login_with_password(username, password)
    except MatrixRequestError as e:
        print(e)
        if e.code == 403:
            print("Bad username or password.")
            sys.exit(4)
        else:
            print("Check your sever details are correct.")
            sys.exit(2)
    except MissingSchema as e:
        print("Bad URL format.")
        print(e)
        sys.exit(3)

    try:
        room = client.join_room(room_id_alias)
    except MatrixRequestError as e:
        print(e)
        if e.code == 400:
            print("Room ID/Alias in the wrong format")
            sys.exit(11)
        else:
            print("Couldn't find room.")
            sys.exit(12)

    room.add_listener(on_message)
    client.start_listener_thread()

    while True:
        msg = samples_common.get_input()
        if msg == "/quit":
            break
        else:
            room.send_text(msg)
class Client():
    def __init__(self):
        self.client = None
        self.room = None

    def authenticate(self, username, password, host):
        self.client = MatrixClient(host)
        try:
            self.client.login_with_password(username, password)
        except MatrixRequestError as e:
            if e.code == 403:
                print("Bad username or password.")
            else:
                print("Check your sever details are correct.")
                return False
        except MissingSchema as e:
            print("Bad URL format.")
            print(e)
            return False

    def get_contacts(self):
        return self.client.get_rooms()

    def get_messages(self, contact):
        pass

    def start_conversation(self, room_id):
        self.room = self.client.join_room(room_id)
        self.room.add_listener(event_listener)
        self.client.start_listener_thread()

    def send_message(self, message):
        self.room.send_text(message)

    def event_listener(self, room, event):
        global app
        app.send_signal("matrix", {"contact": room, "event": event})
class MatrixHandler():
    def __init__(self, username, password, room, gotMsgCallback=blackhole):
        try:
            from matrix_client.client import MatrixClient
        except ImportError:
            print("ERR:matrix_client import fail: Please exec:")
            print("cd ./matrix-python-sdk")
            print("pip install ./")
            raise RuntimeError("Failed to import matrix_client sdk")
        self.matrix = MatrixClient("https://matrix.org")
        self.matrix.login_with_password(username=username, password=password)
        self.matrix.start_listener_thread()
        self.room = self.matrix.join_room(room)
        self.room.send_text("Hello!")
        self.room.add_listener(gotMsgCallback)
        #self.gotMsgCallback=gotMsgCallback
    def sendMsg(self, msgData):
        res = self.room.send_text(msgData)
        return res

    def sendImg(self, imgdir, content_type="image/jpeg"):
        with open(imgdir, mode="rb") as f:
            uri = self.matrix.upload(f.read(), content_type)
            self.room.send_image(uri, 'wximg')
            f.close()

    def sendAudio(self, fdir, content_type="audio/mp3"):
        with open(fdir, mode="rb") as f:
            uri = self.matrix.upload(f.read(), content_type)
            self.room.send_audio(uri, 'wxaudio')
            f.close()

    def sendHtml(self, htmlData):
        res = self.room.send_html(htmlData)
        return res

    '''
class MatrixSendServer:
    def __init__(self, config, room):
        self.queue_path = config['queue_path']
        self.client = MatrixClient(config['homeserver_uri'])
        self.token = self.client.login_with_password(username=config['username'],
                                                     password=config['password'])
        self.room = self.client.join_room(room)
        self.room_id = room
        self.message_queue = []
        self.limited_until = None

    def dequeue(self):
        """Dequeue as many messages as the server lets us"""
        for f in self.message_queue:
            with open(f, "r", encoding="UTF-8") as fin:
                message = fin.read()

            if self.limited_until is not None and time.time() * 1000 < self.limited_until:
                return

            try:
                self.room.send_text(message)
                self.message_queue.pop(0)
            except Exception as e:
                necessary_delay = json.loads(e.content)['retry_after_ms']
                sys.stderr.write("Sleeping for %s seconds... Queue depth %s\n" % (necessary_delay, len(self.message_queue)))
                sys.stderr.flush()
                self.limited_until = time.time() * 1000 + necessary_delay
            else:
                os.remove(f)

    def enqueue(self, f):
        if os.path.isfile(f) and not f in self.message_queue:
            self.message_queue.append(f)

    def run(self):
        print("run!")
        while True:
            for f in os.listdir(self.queue_path):
                f = os.path.join(self.queue_path, f)
                self.enqueue(f)
            self.dequeue()
            time.sleep(10)
Beispiel #24
0
class MCat:
    def __init__(self, config):
        self.client = MatrixClient(config['server'])
        self.token = self.client.login_with_password(username=config['user'],
                                                     password=config['password'])
        self.room = self.client.join_room(config['room'])
        self.room_id = config['room']
        self.message_queue = []
        self.limited_until = None

    def dequeue(self):
        """Dequeue as many messages as the server lets us"""
        for message in self.message_queue:
            if time.time() * 1000 < self.limited_until:
                return

            try:
                self.room.send_html(message)
                self.message_queue.pop(0)
            except Exception as e:
                necessary_delay = json.loads(e.content)['retry_after_ms']
                sys.stderr.write("Sleeping for %s seconds... Queue depth %s\n" % (necessary_delay, len(self.message_queue)))
                sys.stderr.flush()
                self.limited_until = time.time() * 1000 + necessary_delay

    def enqueue(self, message):
        self.message_queue.append(message)

    def f_to_matrix(self, f):
        for line in f:
            self.enqueue(line)
            self.dequeue()
        while len(self.message_queue) > 0:
            self.dequeue()

    def matrix_to_f(self, f):
        def stdout_cb(chunk):
            if chunk[u'type'] != u"m.presence" and chunk[u'room_id'] == self.room_id:
                f.write(json.dumps(chunk))
                f.write('\n')
                f.flush()
        self.client.add_listener(stdout_cb)
        self.client.listen_forever()
Beispiel #25
0
class MatrixProtocol(Protocol):
    """
    A Matrix Protocol wrapper.
    """

    def __init__(self, username, password, room, server):
        super().__init__(username, password, room, server)
        self.username = username
        # Connect to Matrix
        self.client = MatrixClient(server)
        self.token = self.client.login_with_password(username=username,
                                                     password=password)

        self.room = self.client.join_room(room)
        self.room.add_listener(self.process_event)

    def listen_forever(self):
        self.room.send_text('My name is PyAstroBot! I seek the grail!')
        try:
            self.client.listen_forever()
        except KeyboardInterrupt:
            pass
        finally:
            self.room.send_text("PyAstroBot is sneaking away and buggering off...")

    def send_message(self, message):
        self.room.send_text(message)

    def send_emote(self, message):
        self.room.send_emote(message)

    def _is_message(self, event):
        if event['type'] == "m.room.message":
            if event['content']['msgtype'] == "m.text":
                # Ignore everything the bot says.
                if event['sender'] != self.username:
                    return event

    def process_event(self, room, event):
        if self._is_message(event):
            for call in self.event_callbacks:
                call(event['content']['body'], event['sender'])
Beispiel #26
0
import time
import datetime
import dateutil.relativedelta
import os
#import sched
import threading
import re
import screenutils
import logging

my_server="https://matrix.org"
my_username="******"
my_password="******"
my_room="!DJppiagxDRhqgGMLVq:matrix.org"
client=MatrixClient(my_server)
token=client.login_with_password(my_username,my_password)
room=client.join_room(my_room)
all_chat=True

chat_bot_users=['@vanous','@pokusnykralik']

msg_send=""


def send_to_matrix(message):
    global msg_send
    try:
	#print threading.active_count()
	if threading.active_count()<3:
	    res=room.send_text("%s: %s" % (time.strftime('%X'),message,))
	else:
Beispiel #27
0
from matrix_client.client import MatrixClient
import time

client = MatrixClient("http://167.99.238.80:8008")

# New user
#token = client.register_with_password(username="******", password="******")


def listener(event):
    print(event)


# Existing user
token = client.login_with_password(username="******", password="******")
client.add_listener(listener)

#room = client.create_room("my_room_alias")
room = client.join_room("#my_room_alias:teamspeak.sigmapenguinplace.net")
room.send_text("Hello!")

while True:
    client.listen_for_events()
Beispiel #28
0
def start(stdscr):
    global size, room, data, rooms, access_token, endTime, rooms, all_rooms, lastEventRoom, room_keys

    curses.curs_set(0)
    curses.use_default_colors()
    size = stdscr.getmaxyx()

    stdscr.addstr(0, 0, "loading...")
    stdscr.refresh()
    loadCredentials("./credentials.json")

    client = MatrixClient(server)
    access_token = client.login_with_password(
        username,
        password,
        size[0])

    rooms = client.get_rooms()

    all_rooms = "all rooms"
    rooms[all_rooms] = Room(client, all_rooms)

    rooms[all_rooms].events = []
    room_keys = list(rooms.keys())
    room = all_rooms  #room_keys[1] # "all_rooms"
    nextRoom = 1
    endTime = client.end

    curses.halfdelay(10)
    maxDisplayName = 24
    displayNamestartingPos = 20
    PAD_COMMENTS = True
    pause = False

    client.add_listener(processMessage)
    client.start_listener_thread()

    curses.echo()
    stdscr.keypad(True)
    inputBuffer = ""
    lastEventRoom = all_rooms
    the_room_to_post_to = None  # store the last room we saw before we started typing

    while(True):
        size = stdscr.getmaxyx()
        maxChars = size[1] - 1 - len(username) - 3

        stdscr.clear()

        # we want NAME aka ALIAS[0] (ROOM_ID)
        # or 2nd choice: ALIAS[0] (ROOM_ID)
        # or fallback: ROOM_ID
        line = str(room)

        if line == all_rooms:
            pass
        elif rooms[room].name is None:
            if len(rooms[room].aliases) > 0 and rooms[room].aliases[0] != room:
                line = rooms[room].aliases[0] + " (" + line + ")"
        else:
            if len(rooms[room].aliases) > 0 and rooms[room].aliases[0] != room:
                line = rooms[room].name + " aka " + getFirstRoomAlias(rooms[room]) + " (" + line + ")"
            else:
                if rooms[room].name != room:
                    line = rooms[room].name + " (" + line + ")"

        #line.encode("utf-8")
        if rooms[room].topic is not None:
            line += " · topic: " + rooms[room].topic

        stdscr.addstr(
            0, 0, (
                "redpill v0.7 · screen size: " + str(size) + " · chat size: "
                + str(len(rooms[room].events)) + " · room: " + str(line) + " the variables: room: " + room + " last: "
                + lastEventRoom
            ), curses.A_UNDERLINE
        )

        current = len(rooms[room].events) - 1

        if True:
            y = 1
            if current >= 0:

                # TODO: something when the first event is a typing event
                currentLine = size[0] - 1

                # input
                space = ""
                for i in range(size[1] - 1):
                    space += " "
                stdscr.addstr(currentLine, 0, space, curses.A_DIM)
                stdscr.addstr(currentLine, 0, "<" + username + ">", curses.A_DIM)
                stdscr.addstr(currentLine - 1, 0, space, curses.A_UNDERLINE)

                for event in reversed(rooms[room].events):
                    if event["type"] == "m.typing":
                    #if True:
                        continue  # do something clever
                    elif event["type"] == "m.presence":
                    #if True:
                        continue  # do something clever

                    elif event["type"] == "m.roomchange":
                        room_id = event["room_id"]
                        #lin = (str(rooms[room_id].name) + " aka " + getFirstRoomAlias(rooms[room_id]) + " (" +
                        #    rooms[room_id].room_id + ")")
                        line = room_id
                        if line == all_rooms:
                            pass
                        elif rooms[line].name is None:
                            if len(rooms[room_id].aliases) > 0 and rooms[room_id].aliases[0] != room_id:
                                line = rooms[room_id].aliases[0] + " (" + line + ")"
                        else:
                            if len(rooms[room_id].aliases) > 0 and rooms[room_id].aliases[0] != room_id:
                                line = rooms[room_id].name + " aka " + getFirstRoomAlias(rooms[room_id]) + " (" + line + ")"
                            else:
                                if rooms[room_id].name != room_id:
                                    line = rooms[room_id].name + " (" + line + ")"

                        #if rooms[room].topic is not None:
                        #    line += " · topic: " + rooms[room].topic

                        currentLine -= 1
                        stdscr.addstr(currentLine, 0, "Event(s) from " + line, curses.A_DIM)


                    else:
                        #currentLine = size[0] - y
                        currentLine -= 1

                        if currentLine < 3:  # how many lines we want to reserve
                            break
                        #if currentLine == 5:
                        #    currentLine -= 1
                        y += 1
                        if "origin_server_ts" in event:
                            convertedDate = datetime.datetime.fromtimestamp(
                                int(
                                    event["origin_server_ts"] / 1000)
                                ).strftime('%Y-%m-%d %H:%M:%S')

                        # assumption: body == normal message
                        length = 0
                        if "user_id" in event:
                            length = len(
                                event["user_id"]
                            )
                        if "body" in event["content"]:

                            rawText = event["content"]["body"].encode('utf-8')

                            if event["content"]["msgtype"] == "m.emote":
                                if len(rawText) > 0 and rawText[0] == " ":
                                    rawText = rawText[1:]

                            linesNeeded = (displayNamestartingPos + maxDisplayName + 3 + len(rawText)) / size[1]
                            lin = (displayNamestartingPos + maxDisplayName + 3 + len(rawText))

                            #if currentLine == size[0] - 2:
                            #    stdscr.addstr(currentLine, 0, str(lin) + " " + str(size[1]) + " " + str(linesNeeded) + "  ", curses.A_UNDERLINE)
                            #else:
                            #    stdscr.addstr(currentLine, 0, str(lin) + " " + str(size[1]) + " " + str(linesNeeded) + "  ")



                            linesNeeded = 0

                            buf = ""
                            lineByLineText = []
                            first = True
                            bufSinceLastWord = ""
                            for char in rawText:
                                if True: #for char in line:

                                    bufSinceLastWord += char

                                    if char == '\n':
                                        linesNeeded += 1
                                        buf += bufSinceLastWord

                                        if PAD_COMMENTS or first:
                                            linesNeeded += (displayNamestartingPos + maxDisplayName + 3 + len(buf)) / size[1]
                                        else:
                                            linesNeeded += len(buf) / size[1]

                                        first = False
                                        lineByLineText.append(buf)
                                        buf = ""
                                        bufSinceLastWord = ""
                                    else:
                                        if ((PAD_COMMENTS and (displayNamestartingPos + maxDisplayName + 3 + len(buf + bufSinceLastWord)) == size[1] - 1)
                                            or (not PAD_COMMENTS and (len(buf + bufSinceLastWord)) == size[1] - 1)):

                                        #if (displayNamestartingPos + maxDisplayName + 3 + len(buf + bufSinceLastWord)) == size[1] - 1:
                                            if len(buf) == 0:
                                                buf += bufSinceLastWord
                                                bufSinceLastWord = ""

                                            if char.isspace():
                                                buf += bufSinceLastWord
                                                lineByLineText.append(buf)
                                                bufSinceLastWord = ""
                                                buf = ""
                                            else:
                                                lineByLineText.append(buf)
                                                buf = bufSinceLastWord
                                                bufSinceLastWord = ""
                                            linesNeeded += 1

                                    if char.isspace():
                                        buf += bufSinceLastWord
                                        bufSinceLastWord = ""

#                                if (displayNamestartingPos + maxDisplayName + 3 + len(buf + bufSinceLastWord)) == size[1] - 1:
                                if ((PAD_COMMENTS and (displayNamestartingPos + maxDisplayName + 3 + len(buf + bufSinceLastWord)) == size[1] - 1)
                                   or (not PAD_COMMENTS and (len(buf + bufSinceLastWord)) == size[1] - 1)):

                                    buf += bufSinceLastWord
                                    bufSinceLastWord = ""
                                    lineByLineText.append(buf)
                                    linesNeeded += 1
                                    buf = ""
                                    #elif char == ' ':   # skip all whitespace
                                    #    self.X += 1
                            buf += bufSinceLastWord
                            lineByLineText.append(buf)
                            linesNeeded += (displayNamestartingPos + maxDisplayName + 3 + len(buf)) / size[1]
                            buf = ""

                            currentLine -= linesNeeded
                            if currentLine - linesNeeded < 2:  # how many lines we want to reserve
                                break

                            if currentLine == size[0] - 2:
                                stdscr.addstr(currentLine, 0, str(lin) + " " + str(size[1]) + " " + str(linesNeeded) + "  ", curses.A_UNDERLINE)
                            else:
                                stdscr.addstr(currentLine, 0, str(lin) + " " + str(size[1]) + " " + str(linesNeeded) + "  ")

                            #for i in range(linesNeeded):


                            if PAD_COMMENTS:
                                pad = displayNamestartingPos + maxDisplayName + 3


                                #if linesNeeded == 0:
                                linesNeeded += 1

                                for i in range(linesNeeded):
                                    buf = rawText[:size[1] - pad]
                                    rawText = rawText[size[1] - pad:]


                                    if currentLine + i == size[0] - 2:
                                        stdscr.addstr(
                                            currentLine + i, displayNamestartingPos +
                                            maxDisplayName + 3, lineByLineText[i],
                                            curses.A_BOLD + curses.A_UNDERLINE
                                        )
                                    else:
                                        try:
                                            stdscr.addstr(
                                                currentLine + i, displayNamestartingPos +
                                                maxDisplayName + 3, lineByLineText[i],
                                                curses.A_BOLD
                                            )
                                        except:
                                            e = sys.exc_info()[0]
                                            print("Error: unable to start thread. " + str(e))
                                            stdscr.addstr(1, 0, str(e))



                            else:
                                # TODO: need to split this out to get proper underline
                                if currentLine == size[0] - 2:
                                    stdscr.addstr(
                                        currentLine, displayNamestartingPos +
                                        maxDisplayName + 3, rawText,
                                        curses.A_BOLD + curses.A_UNDERLINE
                                    )
                                else:
                                    stdscr.addstr(
                                        currentLine, displayNamestartingPos +
                                        maxDisplayName + 3, rawText,
                                        curses.A_BOLD
                                    )

                            usern = event["user_id"]

                            if length > maxDisplayName:
                                usern = usern[:maxDisplayName - 3] + "..."

                            if event["content"]["msgtype"] == "m.emote":

                                usern = "* " + usern
                                if currentLine == size[0] - 2:
                                    stdscr.addstr(
                                        currentLine, displayNamestartingPos + max(0,  maxDisplayName - length),
                                        str(usern),
                                        curses.A_UNDERLINE + curses.A_BOLD
                                    )
                                else:
                                    stdscr.addstr(
                                        currentLine, displayNamestartingPos + max(0,  maxDisplayName - length),
                                        str(usern),
                                        curses.A_BOLD
                                    )
                            else:
                                usern = "<" + usern + ">"
                                if currentLine == size[0] - 2:
                                    stdscr.addstr(
                                        currentLine, displayNamestartingPos + max(0,  maxDisplayName - length),
                                        str(usern),
                                        curses.A_UNDERLINE
                                    )
                                else:
                                    stdscr.addstr(
                                        currentLine, displayNamestartingPos + max(0,  maxDisplayName - length),
                                        str(usern)
                                    )

                            if currentLine == size[0] - 2:
                                stdscr.addstr(currentLine, 0, convertedDate, curses.A_UNDERLINE)
                            else:
                                stdscr.addstr(currentLine, 0, convertedDate)

                            #if currentLine == size[1]:  # last line
                            #    stdscr.addstr(
                            #        currentLine, displayNamestartingPos +
                            #        maxDisplayName + 3, buf[:size[1] -
                            #        (displayNamestartingPos + maxDisplayName + 4)],
                            #         curses.A_BOLD
                            #    )
                            #else:
                            #    stdscr.addstr(
                            #        currentLine, displayNamestartingPos +
                            #        maxDisplayName + 3, buf,
                            #        curses.A_BOLD
                            #    )

                        # membership == join/leave events
                        elif "membership" in event["content"]:
                            buf = " invited someone"
                            if event["content"]["membership"] == "invite":
                                if "state_key" in event:
                                    buf = " invited " + event["state_key"]
                            elif event["content"]["membership"] == "join":
                                buf = " has joined"
                            elif event["content"]["membership"] == "leave":
                                buf = " has left"

                            if length > maxDisplayName:
                                if currentLine == size[0] - 2:
                                    stdscr.addstr(
                                        currentLine,
                                        displayNamestartingPos + 1,
                                        str(event["user_id"]),
                                        curses.A_DIM + curses.A_UNDERLINE
                                    )
                                    stdscr.addstr(
                                        currentLine,
                                        displayNamestartingPos + length + 1,
                                        buf,
                                        curses.A_DIM + curses.A_UNDERLINE
                                    )
                                else:
                                    stdscr.addstr(
                                        currentLine,
                                        displayNamestartingPos + 1,
                                        str(event["user_id"]),
                                        curses.A_DIM
                                    )
                                    stdscr.addstr(
                                        currentLine,
                                        displayNamestartingPos + length + 1,
                                        buf,
                                        curses.A_DIM
                                    )

                            else:
                                if currentLine == size[0] - 2:
                                    stdscr.addstr(
                                        currentLine,
                                        displayNamestartingPos + 1 +
                                        maxDisplayName - length,
                                        str(event["user_id"]),
                                        curses.A_DIM + curses.A_UNDERLINE
                                    )
                                    stdscr.addstr(
                                        currentLine,
                                        displayNamestartingPos + maxDisplayName + 1,
                                        buf,
                                        curses.A_DIM + curses.A_UNDERLINE
                                    )
                                else:
                                    stdscr.addstr(
                                        currentLine,
                                        displayNamestartingPos + 1 +
                                        maxDisplayName - length,
                                        str(event["user_id"]),
                                        curses.A_DIM
                                    )
                                    stdscr.addstr(
                                        currentLine,
                                        displayNamestartingPos + maxDisplayName + 1,
                                        buf,
                                        curses.A_DIM
                                    )

                    current -= 1
        if pause:
            stdscr.addstr(
                int(size[0] / 2) - 1,
                int(size[1] / 2),
                "          ",
                curses.A_REVERSE
            )
            stdscr.addstr(
                int(size[0] / 2),
                int(size[1] / 2),
                "  PAUSED  ",
                curses.A_REVERSE
            )
            stdscr.addstr(
                int(size[0] / 2) + 1,
                int(size[1] / 2),
                "          ",
                curses.A_REVERSE
            )
        try:
            stdscr.addstr(size[0] - 1, len(username) + 3, inputBuffer[-maxChars:])
        except:
            e = sys.exc_info()[0]
            print("Error: unable to start thread. " + str(e))
            stdscr.addstr(1, 0, str(e))

        stdscr.refresh()

 #       getInput(stdscr)

#def getInput(stdscr):
 #   if True:
        try:

            c = stdscr.getch(size[0] - 1, len(username) + 3)
            #c = stdscr.getkey(size[0] - 1, len(username) + 3)

            #stri = stdscr.getstr(size[0] - 1, len(username) + 3, 10)
            if c == -1:
                stdscr.addstr(1, 0, "timeout")
            else:
                if c <= 256 and c != 10 and c != 9: ## enter and tab
                    inputBuffer += chr(c)
                if len(inputBuffer) == 1:  # e.g. just started typing
                    if lastEventRoom != all_rooms:
                        the_room_to_post_to = lastEventRoom

            if c == 9:
                #stdscr.addstr(1, 0, "%s was pressed\n" % c)
                room = room_keys[nextRoom]
                nextRoom = (nextRoom + 1) % len(rooms)
                the_room_to_post_to = None
            elif c == 10: # enter
                with open('sends.log', 'a') as the_file:
                    the_file.write("the_room_to_post_to:" + str(the_room_to_post_to) + "\n")
                    the_file.write("lastEventRoom: " + str(lastEventRoom) + "\n")
                    the_file.write("room: " + str(room) + "\n")
                    the_file.write("inputBuffer: " + str(inputBuffer) + "\n")
                    the_file.write("---\n")

                if inputBuffer.startswith("/invite"):
                    user_id = inputBuffer[7:].strip()
                    rooms[room].invite_user(user_id)
                elif inputBuffer.startswith("/kick"):
                    user_id = inputBuffer[5:].strip()
                    reason = "no reason..."
                    rooms[room].kick_user(user_id, reason)
                elif inputBuffer.startswith("/power"):
                    user_id = inputBuffer[7:].strip()
                    power_level = 50
                    rooms[room].set_power_level(user_id, power_level)
                elif inputBuffer.startswith("/op"):
                    user_id = inputBuffer[2:].strip()
                    rooms[room].set_power_level(user_id)
                elif inputBuffer.startswith("/ban"): # reason
                    user_id = inputBuffer[4:].strip()
                    reason = "sux" #FIXME
                    rooms[room].ban(user_id, reason)
                elif inputBuffer.startswith("/join"):   # there's a /join that supports aliases
                    room_alias = inputBuffer[5:].strip()
                    client.join_room(room_alias)
                elif inputBuffer.startswith("/j"):
                    room_alias = inputBuffer[2:].strip()
                    client.join_room(room_alias)
                elif inputBuffer.startswith("/leave"):
                    rooms[room].leave_room(room_id)
                elif inputBuffer.startswith("/create"): # create a new room
                    is_public = True
                    invitees = ()
                    #     def create_room(self, alias=None, is_public=False, invitees=()):
                    room_alias = inputBuffer[7:].strip()
                    client.create_room(room_alias, is_public, invitees)
                elif inputBuffer.startswith("/topic"):   # get or set topic
                    new_topic = inputBuffer[6:].strip()
                    if len(new_topic) > 0:
                        rooms[room].topic = new_topic
                    else:
                        pass
                        #rooms[room].topic = "fail"
                else:
                    if room == all_rooms:
                        if the_room_to_post_to is None:
                            if lastEventRoom != all_rooms:
                                the_room_to_post_to = lastEventRoom
                            else:
                                stdscr.addstr(1, 0, "No idea what room to post to!")
                                stdscr.refresh()
                                inputBuffer = "No idea what room to post to!"
                                continue
                    else:
                        the_room_to_post_to = room

                    if inputBuffer.startswith("/me"):
                        rooms[the_room_to_post_to].send_emote(inputBuffer[3:])
                    else:
                        rooms[the_room_to_post_to].send_text(inputBuffer)

                inputBuffer = ""
                the_room_to_post_to = None
            elif c == curses.KEY_DC:
                inputBuffer = ""
                the_room_to_post_to = None
            elif c == curses.KEY_BACKSPACE:
                if len(inputBuffer) > 0:
                    inputBuffer = inputBuffer[:-1]
                if len(inputBuffer) == 0:
                    the_room_to_post_to = None
            elif c == curses.KEY_IC:
                pause = not(pause)
                if pause:
                    curses.nocbreak()
                    curses.cbreak()
                    stdscr.timeout(-1)
                    stdscr.addstr(
                        int(size[0] / 2) - 1,
                        int(size[1] / 2),
                        "          ",
                        curses.A_REVERSE
                    )
                    stdscr.addstr(
                        int(size[0] / 2),
                        int(size[1] / 2),
                        " PAUSING  ",
                        curses.A_REVERSE
                    )
                    stdscr.addstr(
                        int(size[0] / 2) + 1,
                        int(size[1] / 2),
                        "          ",
                        curses.A_REVERSE
                    )
                    stdscr.refresh()
                else:
                    stdscr.addstr(
                        int(size[0] / 2) - 1,
                        int(size[1] / 2),
                        "          ",
                        curses.A_REVERSE
                    )
                    stdscr.addstr(
                        int(size[0] / 2),
                        int(size[1] / 2),
                        " RESUMING ",
                        curses.A_REVERSE
                    )
                    stdscr.addstr(
                        int(size[0] / 2) + 1,
                        int(size[1] / 2),
                        "          ",
                        curses.A_REVERSE
                    )
                    stdscr.refresh()
                    curses.halfdelay(10)
                    stdscr.timeout(1)
            elif c == 27:  # need to test for alt combo or ESC
                curses.cbreak()
                curses.echo()
                #curses.curs_set(1)
                stdscr.keypad(0)
                curses.endwin()
                quit()
            elif c == curses.KEY_F2:
                PAD_COMMENTS = not PAD_COMMENTS

            #stdscr.addstr(2, 0, "time() == %s\n" % time.time())

        finally:
            do_nothing = True
Beispiel #29
0
        room = client.join_room(room_id)
        botinfo = info
        botinfo['room_id'] = room_id
        botinfo['room'] = room
        botinfo['state'] = state
        botinfo['caller'] = state['events'][0]['sender']
        bf[room_id] = BabelFish(botinfo)
        room.add_listener(handle_message)
        print('joined room %s' % room_id)
    else:
        print(
            'Unauthorized user access in room %s. I will not join this room.' %
            room_id)


# **** Main ****
if __name__ == '__main__':
    client = MatrixClient(SERVER)
    client.login_with_password(USERNAME, PASSWORD)
    print('Login as %s successful' % USERNAME)
    client.add_invite_listener(handle_invite)
    for room_id, room in client.get_rooms().items():
        botinfo = info
        botinfo['room_id'] = room_id
        botinfo['room'] = room
        bf[room_id] = BabelFish(botinfo)
        room.add_listener(handle_message)
    client.start_listener_thread()
    print('Listeners started successfully')
    while True:
        time.sleep(0.2)
Beispiel #30
0
class TinyMatrixtBot():
    def __init__(self, hostname, username, password, displayname):
        signal.signal(signal.SIGTERM, self.on_signal)
        signal.signal(signal.SIGHUP, self.on_signal)

        self.current_path = os.path.dirname(os.path.realpath(__file__))
        self.scripts_path = os.path.join(self.current_path, "scripts")
        self.sockets_path = os.path.join(self.current_path, "sockets")

        if not os.access(self.sockets_path, os.W_OK):
            self.sockets_path = None

        os.chdir(self.scripts_path)
        self.scripts = self.load_scripts(self.scripts_path)

        self.client = MatrixClient(hostname)
        self.client.login_with_password(username=username, password=password)

        self.user = self.client.get_user(self.client.user_id)
        self.user.set_display_name(displayname)

        for room_id in self.client.get_rooms():
            self.join_room(room_id)

        self.client.start_listener_thread()
        self.client.add_invite_listener(self.on_invite)
        self.client.add_leave_listener(self.on_leave)

        while True:
            sleep(10)

    def on_signal(self, signal, frame):
        if signal == 1:
            self.scripts = self.load_scripts(self.scripts_path)
        if signal == 15:
            sys.exit()

    def load_scripts(self, path):
        scripts = {}
        for script in os.listdir(path):
            script = os.path.join(path, script)
            if not stat.S_IXUSR & os.stat(script)[stat.ST_MODE]:
                continue
            output = subprocess.Popen(
                [script],
                env={
                    "CONFIG": "1"
                },
                stdout=subprocess.PIPE,
                universal_newlines=True).communicate()[0].strip()
            if not output:
                continue
            scripts[output] = script
            print("script {} {}".format(output, script))
        return scripts

    def on_invite(self, room_id, state):
        print("invite {}".format(room_id))
        self.join_room(room_id)

    def join_room(self, room_id):
        room = self.client.join_room(room_id)
        room.add_listener(self.on_room_event)
        print("join {}".format(room_id))
        if self.sockets_path is not None:
            thread = Thread(target=self.create_socket, args=(room, ))
            thread.daemon = True
            thread.start()

    def create_socket(self, room):
        socket_name = re.search("^\!([a-z]+):", room.room_id,
                                re.IGNORECASE).group(1)
        socket_path = os.path.join(self.sockets_path, socket_name)
        try:
            os.remove(socket_path)
        except OSError:
            pass
        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
        sock.bind(socket_path)
        sock.listen(1)
        print("bind {}".format(socket_path))
        while True:
            conn, addr = sock.accept()
            recv = conn.recv(4096).decode('utf-8').strip()
            print("recv {} {}".format(socket_path, recv))
            room.send_text(recv)

    def on_leave(self, room_id, state):
        print("leave {}".format(room_id))

    def on_room_event(self, room, event):
        if event["sender"] == self.client.user_id:
            return
        if event["type"] == "m.room.message":
            if event["content"]["msgtype"] == "m.text":
                body = event["content"]["body"].strip()
                for regex, script in self.scripts.items():
                    if re.search(regex, body, re.IGNORECASE):
                        self.run_script(room, script, body)

    def run_script(self, room, script, args):
        print("run {} {}".format(script, args))
        output = subprocess.Popen(
            [script, args], stdout=subprocess.PIPE,
            universal_newlines=True).communicate()[0].strip()
        for line in output.split("\n\n"):
            sleep(1)
            print(line)
            room.send_text(line)
Beispiel #31
0
class MatrixBot():
    def __init__(self, settings):
        self.sync_token = None

        self.logger = utils.get_logger()
        self.cache = utils.create_cache(settings)
        self.cache_timeout = int(settings["memcached"]["timeout"])

        self.settings = settings
        self.period = settings["DEFAULT"]["period"]
        self.uri = settings["matrix"]["uri"]
        self.username = settings["matrix"]["username"].lower()
        self.password = settings["matrix"]["password"]
        self.room_ids = settings["matrix"]["rooms"]
        self.domain = self.settings["matrix"]["domain"]
        self.only_local_domain = self.settings["matrix"]["only_local_domain"]

        self.subscriptions_room_ids = settings["subscriptions"].keys()
        self.revokations_rooms_ids = settings["revokations"].keys()
        self.allowed_join_rooms_ids = filter(lambda x: x != 'default',
                                             settings["allowed-join"].keys())
        self.default_allowed_join_rooms = settings["allowed-join"]["default"]

        self.client = MatrixClient(self.uri)
        self.token = self.client.login_with_password(username=self.username,
                                                     password=self.password)
        self.api = MatrixHttpApi(self.uri, token=self.token)

        self.rooms = []
        self.room_aliases = {}
        self.plugins = []
        for plugin in settings['plugins'].itervalues():
            mod = __import__(plugin['module'], fromlist=[plugin['class']])
            klass = getattr(mod, plugin['class'])
            self.plugins.append(klass(self, plugin['settings']))

    def _get_selected_users(self, groups_users_list):
        def _add_or_remove_user(users, username, append):
            username = self.normalize_user_id(username)
            if append and username not in users["in"]:
                users["in"].append(username)
            if not append and username not in users["out"]:
                users["out"].append(username)

        ldap_settings = self.settings["ldap"]
        append = True
        users = {"in": [], "out": []}
        for item in groups_users_list:
            if item == ("but"):
                append = False
            elif item.startswith("+"):
                group_name = item[1:]
                groups_members = bot_ldap.get_ldap_groups_members(
                    ldap_settings)
                if group_name in groups_members.keys():
                    map(lambda x: _add_or_remove_user(users, x, append),
                        groups_members[group_name])
            else:
                _add_or_remove_user(users, item, append)

        selected_users = filter(lambda x: x not in users["out"], users["in"])
        return selected_users

    def normalize_user_id(self, user_id):
        if not user_id.startswith("@"):
            user_id = "@" + user_id
            self.logger.debug("Adding missing '@' to the username: %s" %
                              user_id)
        if user_id.count(":") == 0:
            user_id = "%s:%s" % (user_id, self.domain)
        return user_id

    def get_user_id(self, username=None, normalized=True):
        if not username:
            username = self.username
        normalized_username = self.normalize_user_id(username)
        if normalized:
            return normalized_username
        else:
            return normalized_username[1:].split(':')[0]

    def is_local_user_id(self, username):
        normalized_username = self.get_user_id(username, normalized=True)
        if normalized_username.split(':')[1] == self.domain:
            return True
        return False

    def get_real_room_id(self, room_id):
        if room_id.startswith("#"):
            room_id = self.api.get_room_id(room_id)
        return room_id

    def get_room_members(self, room_id):
        key = "get_room_members-%s" % room_id
        res = self.cache.get(key)
        if res:
            self.logger.debug("get_room_members (cached): %s" % (key))
            return res
        res = self.call_api("get_room_members", 2, room_id)
        self.cache.set(key, res, self.cache_timeout)
        self.logger.debug("get_room_members (non cached): %s" % (key))
        return res

    def is_room_member(self, room_id, user_id):
        try:
            r = Room(self.client, room_id)
            return user_id in r.get_joined_members().keys()
        except Exception, e:
            return False
        return False
Beispiel #32
0
def main():

    tmp_dir = conf.zbx_matrix_tmp_dir
    if tmp_dir == "/tmp/" + conf.zbx_tg_prefix:
        print_message(
            "WARNING: it is strongly recommended to change `zbx_tg_tmp_dir` variable in config!!!"
        )
        print_message(
            "https://github.com/ableev/Zabbix-in-Telegram/wiki/Change-zbx_tg_tmp_dir-in-settings"
        )

    tmp_cookie = tmp_dir + "/cookie.py.txt"
    tmp_uids = tmp_dir + "/uids.txt"
    tmp_need_update = False  # do we need to update cache file with uids or not

    rnd = random.randint(0, 999)
    ts = time.time()
    hash_ts = str(ts) + "." + str(rnd)

    log_file = conf.log_path

    args = sys.argv

    settings = {
        "zbxtg_itemid": "0",  # itemid for graph
        "zbxtg_title": None,  # title for graph
        "zbxtg_image_period": None,
        "zbxtg_image_age": "3600",
        "zbxtg_image_width": "900",
        "zbxtg_image_height": "200",
        "tg_method_image":
        False,  # if True - default send images, False - send text
        "is_debug": False,
        "is_channel": False,
        "disable_web_page_preview": False,
        "location": None,  # address
        "lat": 0,  # latitude
        "lon": 0,  # longitude
        "is_single_message": False,
        "markdown": False,
        "html": False,
        "signature": None,
        "signature_disable": False,
        "graph_buttons": False,
        "extimg": None,
        "to": None,
        "to_group": None,
        "forked": False,
    }

    settings_description = {
        "itemid": {
            "name": "zbxtg_itemid",
            "type": "list",
            "help":
            "script will attach a graph with that itemid (could be multiple)",
            "url": "Graphs"
        },
        "title": {
            "name": "zbxtg_title",
            "type": "str",
            "help": "title for attached graph",
            "url": "Graphs"
        },
        "graphs_period": {
            "name": "zbxtg_image_period",
            "type": "int",
            "help": "graph period",
            "url": "Graphs"
        },
        "graphs_age": {
            "name": "zbxtg_image_age",
            "type": "str",
            "help": "graph period as age",
            "url": "Graphs"
        },
        "graphs_width": {
            "name": "zbxtg_image_width",
            "type": "int",
            "help": "graph width",
            "url": "Graphs"
        },
        "graphs_height": {
            "name": "zbxtg_image_height",
            "type": "int",
            "help": "graph height",
            "url": "Graphs"
        },
        "graphs": {
            "name": "tg_method_image",
            "type": "bool",
            "help": "enables graph sending",
            "url": "Graphs"
        },
        "chat": {
            "name": "tg_chat",
            "type": "bool",
            "help": "deprecated, don't use it, see 'group'",
            "url": "How-to-send-message-to-the-group-chat"
        },
        "group": {
            "name": "tg_group",
            "type": "bool",
            "help": "sends message to a group",
            "url": "How-to-send-message-to-the-group-chat"
        },
        "debug": {
            "name": "is_debug",
            "type": "bool",
            "help": "enables 'debug'",
            "url": "How-to-test-script-in-command-line"
        },
        "channel": {
            "name": "is_channel",
            "type": "bool",
            "help": "sends message to a channel",
            "url": "Channel-support"
        },
        "disable_web_page_preview": {
            "name": "disable_web_page_preview",
            "type": "bool",
            "help": "disable web page preview",
            "url": "Disable-web-page-preview"
        },
        "location": {
            "name": "location",
            "type": "str",
            "help": "address of location",
            "url": "Location"
        },
        "lat": {
            "name": "lat",
            "type": "str",
            "help": "specify latitude (and lon too!)",
            "url": "Location"
        },
        "lon": {
            "name": "lon",
            "type": "str",
            "help": "specify longitude (and lat too!)",
            "url": "Location"
        },
        "single_message": {
            "name": "is_single_message",
            "type": "bool",
            "help": "do not split message and graph",
            "url": "Why-am-I-getting-two-messages-instead-of-one"
        },
        "markdown": {
            "name": "markdown",
            "type": "bool",
            "help": "markdown support",
            "url": "Markdown-and-HTML"
        },
        "html": {
            "name": "html",
            "type": "bool",
            "help": "markdown support",
            "url": "Markdown-and-HTML"
        },
        "signature": {
            "name": "signature",
            "type": "str",
            "help": "bot's signature",
            "url": "Bot-signature"
        },
        "signature_disable": {
            "name": "signature_disable",
            "type": "bool",
            "help": "enables/disables bot's signature",
            "url": "Bot-signature"
        },
        "graph_buttons": {
            "name": "graph_buttons",
            "type": "bool",
            "help":
            "activates buttons under graph, could be using in ZbxTgDaemon",
            "url": "Interactive-bot"
        },
        "external_image": {
            "name": "extimg",
            "type": "str",
            "help":
            "should be url; attaches external image from different source",
            "url": "External-image-as-graph"
        },
        "to": {
            "name": "to",
            "type": "str",
            "help": "rewrite zabbix username, use that instead of arguments",
            "url": "Custom-to-and-to_group"
        },
        "to_group": {
            "name": "to_group",
            "type": "str",
            "help": "rewrite zabbix username, use that instead of arguments",
            "url": "Custom-to-and-to_group"
        },
        "forked": {
            "name": "forked",
            "type": "bool",
            "help": "internal variable, do not use it. Ever.",
            "url": ""
        },
    }

    if len(args) < 4:
        do_not_exit = False
        if "--features" in args:
            print(("List of available settings, see {0}/Settings\n---".format(
                url_wiki_base)))
            for sett, proprt in list(settings_description.items()):
                print(("{0}: {1}\ndoc: {2}/{3}\n--".format(
                    sett, proprt["help"], url_wiki_base, proprt["url"])))

        elif "--show-settings" in args:
            do_not_exit = True
            print_message("Settings: " + str(json.dumps(settings, indent=2)))

        else:
            print((
                "Hi. You should provide at least three arguments.\n"
                "zbxtg.py [TO] [SUBJECT] [BODY]\n\n"
                "1. Read main page and/or wiki: {0} + {1}\n"
                "2. Public Telegram group (discussion): {2}\n"
                "3. Public Telegram channel: {3}\n"
                "4. Try dev branch for test purposes (new features, etc): {0}/tree/dev"
                .format(url_github, url_wiki_base, url_tg_group,
                        url_tg_channel)))
        if not do_not_exit:
            sys.exit(0)

    zbx_to = args[1]
    zbx_subject = args[2]
    zbx_body = args[3]

    zbx = ZabbixWeb(server=conf.zbx_server,
                    username=conf.zbx_api_user,
                    password=conf.zbx_api_pass)
    client = MatrixClient(conf.server)

    token = None
    try:
        token = client.login_with_password(username=conf.username,
                                           password=conf.password)
    except MatrixRequestError as e:
        print(e)
        if e.code == 403:
            print_message("Bad username or password.")
            sys.exit(4)
        else:
            print_message("Check your sever details are correct.")
            sys.exit(2)
    except MissingSchema as e:
        print_message("Bad URL format.")
        print(e)
        sys.exit(3)
    except:
        print_message("ERROR (unknown) login_with_password()!")
        sys.exit(5)

    room = None
    try:
        room = client.join_room(zbx_to)
    except MatrixRequestError as e:
        print(e)
        if e.code == 400:
            print_message("Room ID/Alias in the wrong format")
            sys.exit(11)
        else:
            print_message("Couldn't find room.")
            sys.exit(12)
    except:
        print_message("ERROR (unknown) join_room()!")
        sys.exit(13)

    zbx.tmp_dir = tmp_dir

    # workaround for Zabbix 4.x
    zbx_version = 3

    try:
        zbx_version = conf.zbx_server_version
    except:
        pass


#    if conf.proxy_to_zbx:
#        zbx.proxies = {
#            "http": "http://{0}/".format(conf.proxy_to_zbx),
#            "https": "https://{0}/".format(conf.proxy_to_zbx)
#        }

# https://github.com/ableev/Zabbix-in-Telegram/issues/55
    try:
        if conf.zbx_basic_auth:
            zbx.basic_auth_user = conf.zbx_basic_auth_user
            zbx.basic_auth_pass = conf.zbx_basic_auth_pass
    except:
        pass

    try:
        zbx_api_verify = conf.zbx_api_verify
        zbx.verify = zbx_api_verify
    except:
        pass

    zbxtg_body = (zbx_subject + "\n" + zbx_body).splitlines()
    zbxtg_body_text = []
    ## seems redundant but necessary to avoid errors of using these variables before declaration... shouldn't happen
    tg_method_image = bool(settings["tg_method_image"])
    disable_web_page_preview = bool(settings["disable_web_page_preview"])
    is_single_message = bool(settings["is_single_message"])

    for line in zbxtg_body:
        if line.find(conf.zbx_tg_prefix) > -1:
            setting = re.split("[\s:=]+", line, maxsplit=1)
            key = setting[0].replace(conf.zbx_tg_prefix + ";", "")
            if key not in settings_description:
                # if "--debug" in args:
                room.send_text(
                    str("[ERROR] There is no '{0}' method, use --features to get help"
                        .format(key)))
                # continue
            if settings_description[key]["type"] == "list":
                value = setting[1].split(",")
            elif len(setting) > 1 and len(setting[1]) > 0:
                value = setting[1]
            elif settings_description[key]["type"] == "bool":
                value = True
            else:
                value = settings[settings_description[key]["name"]]
            if key in settings_description:
                settings[settings_description[key]["name"]] = value
            if key == "graphs" and value is True:
                tg_method_image = True
        else:
            zbxtg_body_text.append(line)

    if conf.DEBUG:
        is_debug = True
        zbx.debug = True
        log_file = tmp_dir + ".debug." + hash_ts + ".log"
        print_message(log_file)

    if not os.path.isdir(tmp_dir):
        if is_debug:
            print_message("Tmp dir doesn't exist, creating new one...")
        try:
            os.makedirs(tmp_dir)
            os.chmod(tmp_dir, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
        except:
            tmp_dir = "/tmp"
        if is_debug:
            print_message("Using {0} as a temporary dir".format(tmp_dir))

    done_all_work_in_the_fork = False
    # issue75

    if done_all_work_in_the_fork:
        sys.exit(0)

    # replace text with emojis
    internal_using_emoji = False  # I hate that, but... https://github.com/ableev/Zabbix-in-Telegram/issues/152
    if hasattr(conf, "emoji_map"):
        zbxtg_body_text_emoji_support = []
        for l in zbxtg_body_text:
            l_new = l
            for k, v in list(conf.emoji_map.items()):
                l_new = l_new.replace("{{" + k + "}}", v)
            zbxtg_body_text_emoji_support.append(l_new)
        if len("".join(zbxtg_body_text)) - len(
                "".join(zbxtg_body_text_emoji_support)):
            internal_using_emoji = True
        zbxtg_body_text = zbxtg_body_text_emoji_support

    if not is_single_message and tg_method_image is False:
        text = """%(zbx_subject)s 
        %(zbx_body)s
        """ % {
            "zbx_subject": zbx_subject,
            "zbx_body": zbx_body
        }
        room.send_text(text)

    if settings["zbxtg_image_age"]:
        age_sec = age2sec(settings["zbxtg_image_age"])
        if age_sec > 0 and age_sec > 3600:
            settings["zbxtg_image_period"] = age_sec

    message_id = 0
    if tg_method_image is True:
        zbx.login()
        room.send_text(settings["zbxtg_title"] + "\n" +
                       str(zbxtg_body_text[0]))
        if not zbx.cookie:
            text_warn = "Login to Zabbix web UI has failed (web url, user or password are incorrect), "\
                        "unable to send graphs check manually"
            room.send_text([text_warn])
            print_message(text_warn)
        else:
            if not settings["extimg"]:
                zbxtg_file_img = zbx.graph_get(settings["zbxtg_itemid"],
                                               settings["zbxtg_image_period"],
                                               settings["zbxtg_title"],
                                               settings["zbxtg_image_width"],
                                               settings["zbxtg_image_height"],
                                               version=zbx_version)
            else:
                zbxtg_file_img = external_image_get(settings["extimg"],
                                                    tmp_dir=zbx.tmp_dir)
            zbxtg_body_text, is_modified = list_cut(zbxtg_body_text, 200)
            if not zbxtg_file_img:
                text_warn = "Can't get graph image, check script manually, see logs, or disable graphs"
                room.send_text([text_warn])
                print_message(text_warn)
            else:
                if not is_single_message:
                    zbxtg_body_text = ""
                else:
                    if is_modified:
                        text_warn = "probably you will see MEDIA_CAPTION_TOO_LONG error, "\
                                    "the message has been cut to 200 symbols, "\
                                    "https://github.com/ableev/Zabbix-in-Telegram/issues/9"\
                                    "#issuecomment-166895044"
                        print_message(text_warn)
                in_file = open(zbxtg_file_img, "rb")
                uploaddata = in_file.read(
                )  # if you only wanted to read 512 bytes, do .read(512)
                in_file.close()

                response = client.upload(uploaddata, "image/png")
                room.send_image(str(response), zbxtg_file_img)
                os.remove(zbxtg_file_img)

    if "--show-settings" in args:
        print_message("Settings: " + str(json.dumps(settings, indent=2)))
Beispiel #33
0
class BridgeBot:
    xmpp = None  # type: ClientXMPP
    matrix = None  # type: MatrixClient
    topic_room_id_map = None  # type: Dict[str, str]
    special_rooms = None  # type: Dict[str, MatrixRoom]
    special_room_names = None  # type: Dict[str, str]
    groupchat_flag = None  # type: str
    groupchat_jids = None  # type: List[str]
    restore_room_topic = True  # type: bool

    users_to_invite = None  # type: List[str]
    matrix_room_topics = None  # type: Dict[str, str]
    matrix_server = None  # type: Dict[str, str]
    matrix_login = None  # type: Dict[str, str]
    xmpp_server = None  # type: Tuple[str, int]
    xmpp_login = None  # type: Dict[str, str]
    xmpp_roster_options = None  # type: Dict[str, bool]
    xmpp_groupchat_nick = None  # type: str

    send_messages_to_all_chat = True  # type: bool
    disable_all_chat_room = False  # type: bool
    send_presences_to_control = True  # type: bool
    groupchat_mute_own_nick = True  # type: bool

    disabled_jids = set()  # type: Set[str]

    @property
    def bot_id(self) -> str:
        return self.matrix_login['username']

    def __init__(self, config_file: str = CONFIG_FILE):
        self.groupchat_jids = []
        self.topic_room_id_map = {}
        self.special_rooms = {
            'control': None,
            'all_chat': None,
        }
        self.special_room_names = {
            'control': 'XMPP Control Room',
            'all_chat': 'XMPP All Chat',
        }
        self.xmpp_roster_options = {}

        self.load_config(config_file)

        self.matrix = MatrixClient(**self.matrix_server)
        self.xmpp = ClientXMPP(**self.xmpp_login, **self.xmpp_roster_options)

        self.matrix.login_with_password(**self.matrix_login)

        if self.disable_all_chat_room:
            self.send_messages_to_all_chat = False  #should not be necessary (see load_config)
            if 'all_chat' in self.special_rooms:
                del self.special_rooms['all_chat']
            if 'all_chat' in self.special_room_names:
                del self.special_room_names['all_chat']

        # Prepare matrix special channels and their listeners
        for room in self.matrix.get_rooms().values():
            room.update_room_topic()
            topic = room.topic

            if topic in self.special_rooms.keys():
                logging.debug('Recovering special room: ' + topic)
                self.special_rooms[topic] = room

            elif topic.startswith(self.groupchat_flag):
                room_jid = topic[len(self.groupchat_flag):]
                self.groupchat_jids.append(room_jid)

        for topic, room in self.special_rooms.items():
            if room is None:
                room = self.matrix.create_room()
            self.setup_special_room(room, topic)

        self.special_rooms['control'].add_listener(self.matrix_control_message,
                                                   'm.room.message')
        if not self.disable_all_chat_room:
            self.special_rooms['all_chat'].add_listener(
                self.matrix_all_chat_message, 'm.room.message')

        # Invite users to special rooms
        for room in self.special_rooms.values():
            for user_id in self.users_to_invite:
                room.invite_user(user_id)

        # Prepare xmpp listeners
        self.xmpp.add_event_handler('roster_update', self.xmpp_roster_update)
        self.xmpp.add_event_handler('message', self.xmpp_message)
        self.xmpp.add_event_handler('presence_available',
                                    self.xmpp_presence_available)
        self.xmpp.add_event_handler('presence_unavailable',
                                    self.xmpp_presence_unavailable)
        self.xmpp.add_event_handler('groupchat_message',
                                    self.xmpp_groupchat_message)

        # Connect to XMPP and start processing XMPP events
        self.xmpp.connect(self.xmpp_server)
        self.xmpp.process(block=False)

        # Rejoin group chats
        logging.debug('Rejoining group chats')
        for room_jid in self.groupchat_jids:
            self.xmpp.plugin['xep_0045'].joinMUC(room_jid,
                                                 self.xmpp_groupchat_nick)

        logging.debug('Done with bot init')

    def load_config(self, path: str):
        with open(path, 'r') as conf_file:
            config = yaml.load(conf_file)

        self.users_to_invite = config['matrix']['users_to_invite']
        self.matrix_room_topics = config['matrix']['room_topics']
        self.groupchat_flag = config['matrix']['groupchat_flag']
        if 'restore_room_topic' in config[
                'matrix']:  # to be compatible to other config files
            self.restore_room_topic = config['matrix']['restore_room_topic']

        self.matrix_server = config['matrix']['server']
        self.matrix_login = config['matrix']['login']
        self.xmpp_server = (config['xmpp']['server']['host'],
                            config['xmpp']['server']['port'])
        self.xmpp_login = config['xmpp']['login']
        self.xmpp_groupchat_nick = config['xmpp']['groupchat_nick']

        self.send_presences_to_control = config['send_presences_to_control']
        self.send_messages_to_all_chat = config['send_messages_to_all_chat']
        if not self.send_messages_to_all_chat and 'disable_all_chat_room' in config:
            self.disable_all_chat_room = config['disable_all_chat_room']
        else:
            self.disable_all_chat_room = False

        self.groupchat_mute_own_nick = config['groupchat_mute_own_nick']

        self.xmpp_roster_options = config['xmpp']['roster_options']

        if 'disabled_jids' in config:
            self.disabled_jids = set(config['disabled_jids'])
            if 'xmpp_login_jid' in self.disabled_jids:
                self.disabled_jids.add(self.xmpp_login['jid'])
                self.disabled_jids.remove('xmpp_login_jid')

    def get_room_for_jid(self, jid: str) -> MatrixRoom:
        """
        Return the room corresponding to the given XMPP JID
        :param jid: bare XMPP JID, should not include the resource
        :return: Matrix room object for chatting with that JID
        """
        room_id = self.topic_room_id_map[jid]
        return self.matrix.get_rooms()[room_id]

    def get_unmapped_rooms(self) -> List[MatrixRoom]:
        """
        Returns a list of all Matrix rooms which are not a special room (e.g., the control room) and
        do not have a corresponding entry in the topic -> room map.
        :return: List of unmapped, non-special Matrix room objects.
        """
        special_room_ids = [r.room_id for r in self.special_rooms.values()]
        valid_room_ids = [v for v in self.topic_room_id_map.values()
                          ] + special_room_ids
        unmapped_rooms = [
            room for room_id, room in self.matrix.get_rooms().items()
            if room_id not in valid_room_ids
        ]
        return unmapped_rooms

    def get_empty_rooms(self) -> List[MatrixRoom]:
        """
        Returns a list of all Matrix rooms which are occupied by only one user
        (the bot itself).
        :return: List of Matrix rooms occupied by only the bot.
        """
        empty_rooms = [
            room for room in self.matrix.get_rooms().values()
            if len(room.get_joined_members()) < 2
        ]
        return empty_rooms

    def setup_special_room(self, room, topic: str):
        """
        Sets up a Matrix room with the requested topic and adds it to the self.special_rooms map.

        If a special room with that topic already exists, it is replaced in the special_rooms
         map by the new room.
        :param room: Room to set up
        :param topic: Topic for the room
        """
        room.set_room_topic(topic)
        room.set_room_name(self.special_room_names[topic])
        self.special_rooms[topic] = room

        logging.debug('Set up special room with topic {} and id'.format(
            str(room.topic), room.room_id))

    def create_mapped_room(self,
                           topic: str,
                           name: str = None) -> MatrixRoom or None:
        """
        Create a new room and add it to self.topic_room_id_map.

        :param topic: Topic for the new room
        :param name: (Optional) Name for the new room
        :return: Room which was created
        """
        if not name:  #room without name is shown as the bot's name in clients like riot
            name = topic

        if topic in self.groupchat_jids:
            logging.debug(
                'Topic {} is a groupchat without its flag, ignoring'.format(
                    topic))
            return None
        elif topic in self.topic_room_id_map.keys():
            room_id = self.topic_room_id_map[topic]
            room = self.matrix.get_rooms()[room_id]
            logging.debug('Room with topic {} already exists!'.format(topic))
        else:
            room = self.matrix.create_room()
            room.set_room_topic(topic)
            self.topic_room_id_map[topic] = room
            logging.info('Created mapped room with topic {} and id {}'.format(
                topic, str(room.room_id)))
            room.set_room_name(name)

        room.update_room_name(
        )  #room.name is not set automatically in all cases

        if self.restore_room_topic and room.name != name:
            room.set_room_name(name)

        return room

    def map_rooms_by_topic(self):
        """
        Add unmapped rooms to self.topic_room_id_map, and listen to messages from those rooms.

        Rooms whose topics are empty or do not contain an '@' symbol are assumed to be special
         rooms, and will not be mapped.
        """
        unmapped_rooms = self.get_unmapped_rooms()

        for room in unmapped_rooms:
            room.update_room_topic()

            logging.debug('Unmapped room {} ({}) [{}]'.format(
                room.room_id, room.name, room.topic))

            if room.topic is None or '@' not in room.topic:
                logging.debug(
                    'Leaving it as-is (special room, topic does not contain @)'
                )
            else:
                self.topic_room_id_map[room.topic] = room.room_id

                room.add_listener(self.matrix_message, 'm.room.message')

    def matrix_control_message(self, room: MatrixRoom, event: Dict):
        """
        Handle a message sent to the control room.

        Does nothing unless a valid command is received:
          refresh  Probes the presence of all XMPP contacts, and updates the roster.
          purge    Leaves any ((un-mapped and non-special) or empty) Matrix rooms.
          joinmuc [email protected]   Joins a muc
          leavemuc [email protected]  Leaves a muc

        :param room: Matrix room object representing the control room
        :param event: The Matrix event that was received. Assumed to be an m.room.message .
        """
        # Always ignore our own messages
        if event['sender'] == self.bot_id:
            return

        logging.debug('matrix_control_message: {}  {}'.format(
            room.room_id, str(event)))

        if event['content']['msgtype'] == 'm.text':
            message_body = event['content']['body']
            logging.info('Matrix received control message: ' + message_body)

            message_parts = message_body.split()
            if len(message_parts) > 0:
                message_parts[0] = message_parts[0].lower()
                # what about a empty body?
                if message_parts[0] == 'refresh':
                    for jid in self.topic_room_id_map.keys():
                        self.xmpp.send_presence(pto=jid, ptype='probe')

                    self.xmpp.send_presence()
                    self.xmpp.get_roster()

                elif message_parts[0] == 'purge':
                    self.special_rooms['control'].send_text(
                        'Purging unused rooms')

                    # Leave from unwanted rooms
                    for room in self.get_unmapped_rooms(
                    ) + self.get_empty_rooms():
                        logging.info(
                            'Leaving room {r.room_id} ({r.name}) [{r.topic}]'.
                            format(r=room))
                        if room.topic.startswith(self.groupchat_flag):
                            room_jid = room.topic[len(self.groupchat_flag):]
                            self.xmpp.plugin['xep_0045'].leaveMUC(room_jid)
                        room.leave()

                elif len(message_parts) > 1:
                    if message_parts[0] == 'joinmuc':
                        room_jid = message_parts[1]
                        logging.info('XMPP MUC join: {}'.format(room_jid))
                        self.create_groupchat_room(room_jid)
                        self.xmpp.plugin['xep_0045'].joinMUC(
                            room_jid, self.xmpp_groupchat_nick)
                    elif message_parts[0] == 'leavemuc':
                        room_jid = message_parts[1]
                        logging.info('XMPP MUC leave: {}'.format(room_jid))
                        self.xmpp.plugin['xep_0045'].leaveMUC(
                            room_jid, self.xmpp_groupchat_nick)
                        room = self.get_room_for_jid(self.groupchat_flag +
                                                     room_jid)
                        room.leave()

    def matrix_all_chat_message(self, room: MatrixRoom, event: Dict):
        """
        Handle a message sent to Matrix all-chat room.

        Currently just sends a warning that nobody will hear your message.

        :param room: Matrix room object representing the all-chat room
        :param event: The Matrix event that was received. Assumed to be an m.room.message .
        """
        # Always ignore our own messages
        if event['sender'] == self.bot_id:
            return

        logging.debug('matrix_all_chat_message: {}  {}'.format(
            room.room_id, str(event)))

        room.send_notice('Don\'t talk in here! Nobody gets your messages.')

    def matrix_message(self, room: MatrixRoom, event: Dict):
        """
        Handle a message sent to a mapped Matrix room.

        Sends the message to the xmpp handle specified by the room's topic.

        :param room: Matrix room object representing the room in which the message was received.
        :param event: The Matrix event that was received. Assumed to be an m.room.message .
        """
        if event['sender'] == self.bot_id:
            return

        if room.topic in self.special_rooms.keys():
            logging.error('matrix_message called on special channel')

        logging.debug('matrix_message: {}  {}'.format(room.room_id, event))

        if event['content']['msgtype'] == 'm.text':
            message_body = event['content']['body']

            if room.topic.startswith(self.groupchat_flag):
                jid = room.topic[len(self.groupchat_flag):]
                message_type = 'groupchat'
            else:
                jid = room.topic
                message_type = 'chat'

            name = self.xmpp.jid_nick_map[jid]

            logging.info('Matrix received message to {} : {}'.format(
                jid, message_body))
            self.xmpp.send_message(mto=jid,
                                   mbody=message_body,
                                   mtype=message_type)

            if self.send_messages_to_all_chat:
                self.special_rooms['all_chat'].send_notice('To {} : {}'.format(
                    name, message_body))

    def xmpp_message(self, message: Dict):
        """
        Handle a message received by the XMPP client.

        Sends the message to the relevant mapped Matrix room, as well as the Matrix all-chat room.

        :param message: The message that was received.
        :return:
        """
        logging.info('XMPP received {} : {}'.format(message['from'].full,
                                                    message['body']))

        if message['type'] in ('normal', 'chat'):
            from_jid = message['from'].bare
            from_name = self.xmpp.jid_nick_map[from_jid]

            if from_jid in self.groupchat_jids:
                logging.warning(
                    'Normal chat message from a groupchat, ignoring...')
                return

            room = self.get_room_for_jid(from_jid)
            room.send_text(message['body'])
            if self.send_messages_to_all_chat:
                self.special_rooms['all_chat'].send_text('From {}: {}'.format(
                    from_name, message['body']))

    def xmpp_groupchat_message(self, message: Dict):
        """
        Handle a groupchat message received by the XMPP client.

        Sends the message to the relevant mapped Matrix room, as well as the Matrix all-chat room.

        :param message: The message that was received.
        :return:
        """
        logging.info('XMPP MUC received {} : {}'.format(
            message['from'].full, message['body']))

        if message['type'] == 'groupchat':
            from_jid = message['from'].bare
            from_name = message['mucnick']

            if self.groupchat_mute_own_nick and from_name == self.xmpp_groupchat_nick:
                return

            room = self.get_room_for_jid(self.groupchat_flag + from_jid)
            room.send_text(from_name + ': ' + message['body'])
            if self.send_messages_to_all_chat:
                self.special_rooms['all_chat'].send_text(
                    'Room {}, from {}: {}'.format(from_jid, from_name,
                                                  message['body']))

    def create_groupchat_room(self, room_jid: str):
        room = self.create_mapped_room(topic=self.groupchat_flag + room_jid)
        if room_jid not in self.groupchat_jids:
            self.groupchat_jids.append(room_jid)
        for user_id in self.users_to_invite:
            room.invite_user(user_id)

    def xmpp_presence_available(self, presence: Dict):
        """
        Handle a presence of type "available".

        Sends a notice to the control channel.

        :param presence: The presence that was received.
        """
        logging.debug('XMPP received {} : (available)'.format(
            presence['from'].full))

        jid = presence['from'].bare
        if jid in self.disabled_jids:
            return

        if jid not in self.xmpp.jid_nick_map.keys():
            logging.error('JID NOT IN ROSTER!?')
            self.xmpp.get_roster()
            return

        if self.send_presences_to_control:
            name = self.xmpp.jid_nick_map[jid]
            self.special_rooms['control'].send_notice(
                '{} available ({})'.format(name, jid))

    def xmpp_presence_unavailable(self, presence):
        """
        Handle a presence of type "unavailable".

        Sends a notice to the control channel.

        :param presence: The presence that was received.
        """
        logging.debug('XMPP received {} : (unavailable)'.format(
            presence['from'].full))

        jid = presence['from'].bare
        if jid in self.disabled_jids:
            return

        if self.send_presences_to_control:
            name = self.xmpp.jid_nick_map[jid]
            self.special_rooms['control'].send_notice(
                '{} unavailable ({})'.format(name, jid))

    def xmpp_roster_update(self, _event):
        """
        Handle an XMPP roster update.

        Maps all existing Matrix rooms, creates a new mapped room for each JID in the roster
        which doesn't have one yet, and invites the users specified in the config in to all the rooms.

        :param _event: The received roster update event (unused).
        """
        logging.debug('######### ROSTER UPDATE ###########')

        rjids = [jid for jid in self.xmpp.roster]
        if len(rjids) > 1:
            raise Exception('Not sure what to do with more than one roster...')

        roster0 = self.xmpp.roster[rjids[0]]
        self.xmpp.roster_dict = {jid: roster0[jid] for jid in roster0}
        roster = self.xmpp.roster_dict

        self.map_rooms_by_topic()

        # Create new rooms where none exist
        for jid, info in roster.items():
            if '@' not in jid:
                logging.warning('Skipping fake jid in roster: ' + jid)
                continue
            if jid in self.disabled_jids:
                continue
            name = info['name']
            self.xmpp.jid_nick_map[jid] = name
            self.create_mapped_room(topic=jid, name=name)

        logging.debug('Sending invitations..')
        # Invite to all rooms
        for room in self.matrix.get_rooms().values():
            users_in_room = room.get_joined_members()
            for user_id in self.users_to_invite:
                if user_id not in users_in_room:
                    room.invite_user(user_id)

        logging.debug('######## Done with roster update #######')
Beispiel #34
0
class MatrixBackend(ErrBot):
    def __init__(self, config):
        super().__init__(config)

        if not hasattr(config, 'MATRIX_HOMESERVER'):
            log.fatal("""
            You need to specify a homeserver to connect to in
            config.MATRIX_HOMESERVER.

            For example:
            MATRIX_HOMESERVER = "https://matrix.org"
            """)
            sys.exit(1)

        self._homeserver = config.MATRIX_HOMESERVER
        self._username = config.BOT_IDENTITY['username']
        self._password = config.BOT_IDENTITY['password']
        self._api = None
        self._token = None


    def serve_once(self):
        def dispatch_event(event):
            log.info("Received event: %s" % event)

            if event['type'] == "m.room.member":
                if event['membership'] == "invite" and event['state_key'] == self._client.user_id:
                    room_id = event['room_id']
                    self._client.join_room(room_id)
                    log.info("Auto-joined room: %s" % room_id)

            if event['type'] == "m.room.message" and event['sender'] != self._client.user_id:
                sender = event['sender']
                room_id = event['room_id']
                body = event['content']['body']
                log.info("Received message from %s in room %s" % (sender, room_id))

                # msg = Message(body)
                # msg.frm = MatrixPerson(self._client, sender, room_id)
                # msg.to = MatrixPerson(self._client, self._client.user_id, room_id)
                # self.callback_message(msg) 

                msg = self.build_message(body)
                room = MatrixRoom(room_id)
                msg.frm = MatrixRoomOccupant(self._api, room, sender)
                msg.to = room
                self.callback_message(msg) 

        self.reset_reconnection_count()
        self.connect_callback()

        self._client = MatrixClient(self._homeserver)

        try:
            self._token = self._client.register_with_password(self._username,
                                                              self._password,)
        except MatrixRequestError as e:
            if e.code == 400 or e.code == 403:
                try:
                    self._token = self._client.login_with_password(self._username,
                                                     self._password,)
                except MatrixRequestError:
                    log.fatal("""
                        Incorrect username or password specified in
                        config.BOT_IDENTITY['username'] or config.BOT_IDENTITY['password'].
                    """)
                    sys.exit(1)

        self._api = MatrixHttpApi(self._homeserver, self._token)

        self.bot_identifier = MatrixPerson(self._api)

        self._client.add_listener(dispatch_event)

        try:
            while True:
                self._client.listen_for_events()
        except KeyboardInterrupt:
            log.info("Interrupt received, shutting down...")
            return True
        finally:
            self.disconnect_callback()

    def rooms(self):
        rooms = []
        raw_rooms = self._client.get_rooms()

        for rid, robject in raw_rooms:
            # TODO: Get the canonical alias rather than the first one from
            #       `Room.aliases`.
            log.debug('Found room %s (aka %s)' % (rid, rid.aliases[0]))

    def send_message(self, mess):
        super().send_message(mess)

        room_id = mess.to.room.id
        text_content = item_url = mess.body

        if item_url.startswith("http://") or item_url.startswith("https://"):
            if item_url.endswith("gif"):
                self._api.send_content(room_id, item_url, "image", "m.image")
                return

        # text_content = Markdown().convert(mess.body)
        self._api.send_message(room_id, text_content)

    def connect_callback(self):
        super().connect_callback()

    def build_identifier(self, txtrep):
        raise Exception(
            "XXX"
        )

    def build_reply(self, mess, text=None, private=False):
        log.info("build_reply")

        response = self.build_message(text)
        response.frm = self.bot_identifier
        response.to = mess.frm
        return response

    def change_presence(self, status: str = '', message: str = ''):
        raise Exception(
            "XXX"
        )

    @property
    def mode(self):
        return 'matrix'

    def query_room(self, room):
        raise Exception(
            "XXX"
        )
# 4 - Bad username/password.


import sys
import samples_common  # Common bits used between samples

from matrix_client.client import MatrixClient
from matrix_client.api import MatrixRequestError
from requests.exceptions import MissingSchema

host, username, password = samples_common.get_user_details(sys.argv)

client = MatrixClient(host)

try:
    client.login_with_password(username, password)
except MatrixRequestError as e:
    print(e)
    if e.code == 403:
        print("Bad username or password.")
        sys.exit(4)
    else:
        print("Check your sever details are correct.")
        sys.exit(2)
except MissingSchema as e:
    print("Bad URL format.")
    print(e)
    sys.exit(3)

if len(sys.argv) > 4:
    userid = sys.argv[4]
Beispiel #36
0
class MatrixTransport(Transport):
    def __init__(self, homeserver, username, password, matrix_room):
        super().__init__()
        self.homeserver = homeserver
        self.username = username
        self.password = password
        self.room_name = matrix_room
        self.is_running = gevent.event.Event()
        self.do_reconnect = gevent.event.AsyncResult()
        self.retry_timeout = 5
        self.client = None

    def matrix_exception_handler(self, e):
        """Called whenever an exception occurs in matrix client thread.

            Any exception other than MatrixHttpLibError will be sent to parent hub,
             terminating the program.
        """
        if isinstance(e, MatrixHttpLibError):
            log.warning(str(e))
            self.do_reconnect.set(100)
            raise e
        gevent.get_hub().parent.throw(e)

    def connect(self):
        """Connects to a matrix homeserver and initializes the client class"""
        if self.client is not None:
            self.client.logout()
            self.client = None
        self.client = MatrixClient(self.homeserver)
        self.client.login_with_password(self.username, self.password)
        self.room = self.client.join_room(self.room_name)
        self.client.start_listener_thread(
            exception_handler=lambda e: self.matrix_exception_handler(e), )

    def get_room_events(self, limit=100):
        """Get past messages in the broadcast room, up to the @limit"""
        f = {"room": {"timeline": {"limit": 100}}}
        result = self.client.api.sync(filter=json.dumps(f))
        room_id = self.room.room_id
        room = result['rooms']['join'][room_id]
        return room['timeline']['events']

    def sync_history(self):
        """Calls event callback for all events retrived from the broadcast room history"""
        events = self.get_room_events()
        for event in events:
            self.push_event(event)

    def push_event(self, event):
        """Calls a registered event callback"""
        for listener in self.room.listeners:
            if listener['event_type'] is None or listener[
                    'event_type'] == event['type']:
                listener['callback'](self.room, event)

    def dispatch(self, room, event):
        if event['type'] == "m.room.message":
            if event['content']['msgtype'] == "m.text":
                self.run_message_callbacks(event['content']['body'])
                log.debug("{0}: {1}".format(event['sender'],
                                            event['content']['body']))

    def transmit_data(self, message: str, target_node: str = None):
        # TODO: fix sending to certain receiver
        assert self.room is not None
        self.room.send_text(message)

    def _run(self):
        """Gevent loop. The Matrix connection is restored automatically on error."""
        while self.is_running.is_set() is False:
            try:
                self.connect()
                self.room.add_listener(
                    lambda room, event: self.dispatch(room, event))
                self.sync_history()
                self.do_reconnect.wait()
                if self.do_reconnect.get() == 100:
                    gevent.sleep(self.retry_timeout)
                    continue
            except (requests.exceptions.ConnectionError,
                    MatrixHttpLibError) as e:
                log.warn(
                    "Connection to %s failed. Retrying in %d seconds (%s)" % (
                        self.homeserver,
                        self.retry_timeout,
                        str(e),
                    ), )
                gevent.sleep(self.retry_timeout)
Beispiel #37
0
class MatrixProtocol(Protocol):

  # List of occupants in each room
  # Used to avoid having to re-request the list of members each time
  room_occupants = {}
  # Keep track of when we joined rooms this session
  # Used to filter out historical messages after accepting room invites
  join_timestamps = {}

  # called on bot init; the following are already created by __init__:
  #   self.bot = SibylBot instance
  #   self.log = the logger you should use
  def setup(self):
    self.rooms = {}
    self.bot.add_var("credentials",persist=True)

    # Incoming message queue - messageHandler puts messages in here and
    # process() looks here periodically to send them to sibyl
    self.msg_queue = Queue()

    # Create a client in setup() because we might use self.client before
    # connect() is called
    homeserver = self.opt('matrix.server')
    self.client = MatrixClient(homeserver)

  # @raise (ConnectFailure) if can't connect to server
  # @raise (AuthFailure) if failed to authenticate to server
  def connect(self):
    homeserver = self.opt('matrix.server')
    user = self.opt('matrix.username')
    pw = self.opt('matrix.password')

    self.log.debug("Connecting to %s" % homeserver)

    try:
      self.log.debug("Logging in as %s" % user)

      # Log in with the existing access token if we already have a token
      if(self.bot.credentials and self.bot.credentials[0] == user):
        self.client = MatrixClient(homeserver, user_id=user, token=self.bot.credentials[1])
      # Otherwise, log in with the configured username and password
      else:
        token = self.client.login_with_password(user,pw)
        self.bot.credentials = (user, token)

      self.rooms = self.client.get_rooms()
      self.log.debug("Already in rooms: %s" % self.rooms)

      # Connect to Sibyl's message callback
      self.client.add_listener(self.messageHandler)
      self.client.add_invite_listener(self.inviteHandler)

      self.log.debug("Starting Matrix listener thread")
      self.client.start_listener_thread(exception_handler=self._matrix_exception_handler)

    except MatrixRequestError as e:
      if(e.code in [401, 403]):
        self.log.debug("Credentials incorrect! Maybe your access token is outdated?")
        raise self.AuthFailure
      else:
        if(self.opt('matrix.debug')):
          tb = traceback.format_exc()
          self.log.debug(tb)
        self.log.debug("Failed to connect to homeserver!")
        raise self.ConnectFailure
    except MatrixHttpLibError as e:
      self.log.error("Failed to connect to homeserver!")
      self.log.debug("Received error:" + str(e))
      raise self.ConnectFailure

  def _matrix_exception_handler(self, e):
    self.msg_queue.put(e)

  # receive/process messages and call bot._cb_message()
  # must ignore msgs from myself and from users not in any of our rooms
  # @call bot._cb_message(Message) upon receiving a valid status or message
  # @raise (PingTimeout) if implemented
  # @raise (ConnectFailure) if disconnected
  # @raise (ServerShutdown) if server shutdown
  def process(self):
    while(not self.msg_queue.empty()):
      next = self.msg_queue.get()
      if(isinstance(next, Message)):
        self.log.debug("Placing message into queue: " + next.get_text())
        self.bot._cb_message(next)
      elif(isinstance(next, MatrixHttpLibError)):
        self.log.debug("Received error from Matrix SDK, stopping listener thread: " + str(next))
        self.client.stop_listener_thread()
        raise self.ConnectFailure("Connection error returned by requests library: " + str(next))


  def messageHandler(self, msg):
    if(self.opt('matrix.debug')):
      self.log.debug(str(msg))

    try:
      # Create a new Message to send to Sibyl
      u = self.new_user(msg['sender'], Message.GROUP)
      r = self.new_room(msg['room_id'])

      if(r in self.join_timestamps
         and datetime.datetime.fromtimestamp(msg['origin_server_ts']/1000, pytz.utc) < self.join_timestamps[r]):
        self.log.info('Message received in {} from before room join, ignoring'.format(msg['room_id']))
        return None

      if('msgtype' in msg['content']):
        msgtype = msg['content']['msgtype']

        if(msgtype == 'm.text'):
          m = Message(u, msg['content']['body'], room=r, typ=Message.GROUP)
          self.log.debug('Handling m.text: ' + msg['content']['body'])
          self.msg_queue.put(m)

        elif(msgtype == 'm.emote'):
          m = Message(u, msg['content']['body'], room=r, typ=Message.GROUP,
          emote=True)
          self.log.debug('Handling m.emote: ' + msg['content']['body'])
          self.msg_queue.put(m)

        elif(msgtype == 'm.image' or msgtype == 'm.audio' or msgtype == 'm.file' or msgtype == 'm.video'):
          media_url = urlparse(msg['content']['url'])
          http_url = self.client.api.base_url + "/_matrix/media/r0/download/{0}{1}".format(media_url.netloc, media_url.path)
          if(msgtype == 'm.image'):
            body = "{0} uploaded {1}: {2}".format(msg['sender'], msg['content'].get('body', 'an image'), http_url)
          elif(msgtype == 'm.audio'):
            body = "{0} uploaded {1}: {2}".format(msg['sender'], msg['content'].get('body', 'an audio file'), http_url)
          elif(msgtype == 'm.video'):
            body = "{0} uploaded {1}: {2}".format(msg['sender'], msg['content'].get('body', 'a video file'), http_url)
          elif(msgtype == 'm.file'):
            body = "{0} uploaded {1}: {2}".format(msg['sender'], msg['content'].get('body', 'a file'), http_url)
          m = Message(u, body, room=r, typ=Message.GROUP)
          self.log.debug("Handling " + msgtype + ": " + body)
          self.msg_queue.put(m)

        elif(msgtype == 'm.location'):
          body = "{0} sent a location: {1}".format(msg['sender'], msg['content']['geo_uri'])
          m = Message(u, body, room=r, typ=Message.GROUP)
          self.log.debug('Handling m.location: ' + body)
          self.msg_queue.put(m)


        else:
          self.log.debug('Not handling message, unknown msgtype')

      elif('membership' in msg):
        if(msg['membership'] == 'join'):
          self.room_occupants[r].add(self.new_user(msg['state_key'], Message.GROUP))
        elif(msg['membership'] == 'leave'):
          self.room_occupants[r].remove(self.new_user(msg['state_key'], Message.GROUP))

    except KeyError as e:
      self.log.debug("Incoming message did not have all required fields: " + e.message)


  def inviteHandler(self, room_id, state):
    join_on_invite = self.opt('matrix.join_on_invite')

    invite_events = [x for x in state['events'] if x['type'] == 'm.room.member'
                     and x['state_key'] == str(self.get_user())
                     and x['content']['membership'] == 'invite']
    if(len(invite_events) != 1):
      raise KeyError("Something's up, found more than one invite state event for " + room_id)

    inviter = invite_events[0]['sender']
    inviter_domain = inviter.split(':')[1]
    my_domain = str(self.get_user()).split(':')[1]

    if(join_on_invite == 'accept' or (join_on_invite == 'domain' and inviter_domain == my_domain)):
      self.log.debug('Joining {} on invite from {}'.format(room_id, inviter))
      self.join_room(MatrixRoom(self, room_id))

    elif(join_on_invite == 'domain' and inviter_domain != my_domain):
      self.log.debug("Received invite for {} but inviter {} is on a different homeserver").format(room_id, inviter)

    else:
      self.log.debug("Received invite for {} from {} but join_on_invite is disabled".format(room_id, inviter))


  # called when the bot is exiting for whatever reason
  # NOTE: sibylbot will already call part_room() on every room in get_rooms()
  def shutdown(self):
    pass

  # send a message to a user
  # @param mess (Message) message to be sent
  # @raise (ConnectFailure) if failed to send message
  # Check: get_emote()
  def send(self,mess):
    (text,to) = (mess.get_text(),mess.get_to())
    try:
      if(mess.get_emote()):
        to.room.send_emote(text)
      else:
        to.room.send_text(text)
    except MatrixError as e:
      raise self.ConnectFailure

  # send a message with text to every user in a room
  # optionally note that the broadcast was requested by a specific User
  # @param mess (Message) the message to broadcast
  # @return (str,unicode) the text that was actually sent
  # Check: get_user(), get_users()
  def broadcast(self,mess):
    """send a message to every user in a room"""

    (text,room,frm) = (mess.get_text(),mess.get_to(),mess.get_user())
    users = self.get_occupants(room)+(mess.get_users() or [])

    # Matrix has no built-in broadcast, so we'll just highlight everyone
    s = 'all: %s --- ' % text
    if frm:
      self.log.debug('Broadcast message from: ' + str(frm))
      s += frm.get_name()+' --- '

    me = self.get_user()
    names = [u.get_name() for u in users if (u!=me and (not frm or u!=frm))]
    s += ', '.join(set(names))

    self.send(Message(self.get_user(),s,to=room))
    return s

  # join the specified room using the specified nick and password
  # @param room (Room) the room to join
  # @call bot._cb_join_room_success(room) on successful join
  # @call bot._cb_join_room_failure(room,error) on failed join
  def join_room(self,room):
    try:
      res = self.client.join_room(room.room.room_id)
      self.bot._cb_join_room_success(room)
      self.join_timestamps[room] = datetime.datetime.now(pytz.utc)
    except MatrixError as e:
      self.bot._cb_join_room_failure(room, e.message)

  # part the specified room
  # @param room (Room) the room to leave
  def part_room(self,room):
    raise NotImplementedError

  # helper function for get_rooms() for protocol-specific flags
  # only needs to handle: FLAG_PARTED, FLAG_PENDING, FLAG_IN, FLAG_ALL
  # @param flag (int) one of Room.FLAG_* enums
  # @return (list of Room) rooms matching the flag
  def _get_rooms(self,flag):
    mxrooms = self.client.get_rooms()
    return [self.new_room(mxroom) for mxroom in mxrooms]


  # @param room (Room) the room to query
  # @return (list of User) the Users in the specified room
  def get_occupants(self,room):
    if(room in self.room_occupants):
      return list(self.room_occupants[room])
    else:
      try:
        memberdict = room.room.get_joined_members()
        users = [ self.new_user(x) for x in memberdict ]
        self.room_occupants[room] = set(users)
        return users
      except MatrixError as e:
        raise self.ConnectFailure

  # @param room (Room) the room to query
  # @return (str) the nick name we are using in the specified room
  def get_nick(self,room):
    return self.get_user().get_name() # TODO: per-room nicknames

  # @param room (Room) the room to query
  # @param nick (str) the nick to examine
  # @return (User) the "real" User behind the specified nick/room
  def get_real(self,room,nick):
    raise NotImplementedError

  # @return (User) our username
  def get_user(self):
    return MatrixUser(self,self.opt('matrix.username'),Message.GROUP)

  # @param user (str) a user id to parse
  # @param typ (int) either Message.GROUP or Message.PRIVATE
  # @param real (User) [self] the "real" user behind this user
  # @return (User) a new instance of this protocol's User subclass
  def new_user(self,user,typ=None,real=None):
    return MatrixUser(self,user,typ,real)

  # @param name (object) the identifier for this Room
  # @param nick (str) [None] the nick name to use in this Room
  # @param pword (str) [None] the password for joining this Room
  # @return (Room) a new instance of this protocol's Room subclass
  def new_room(self,room_id_or_alias,nick=None,pword=None):
    return MatrixRoom(self,room_id_or_alias,nick,pword)
Beispiel #38
0
 def login(self):
     client = MatrixClient(self.config.server)
     client.login_with_password(self.config.username, self.config.password)
     self.client = client
Beispiel #39
0
class ChatBot(object):
    def __init__(self, opts):
        jid = opts.jid
        password = opts.password
        url = opts.url
        room_id_alias = opts.room

        #
        # Connect to the server
        # ######################
        self.client = MatrixClient(url)
        try:
            self.token = self.client.login_with_password(username=jid,
                                                         password=password)
        except MatrixRequestError as e:
            print(e)
            if e.code == 403:
                print("Bad username or password.")
                sys.exit(4)
            else:
                print("Check your sever details are correct.")
                sys.exit(2)
        except MissingSchema as e:
            print("Bad URL format.")
            print(e)
            sys.exit(3)

        #
        # Connect to the room
        # ####################
        try:
            self.room = self.client.join_room(room_id_alias)
        except MatrixRequestError as e:
            print(e)
            if e.code == 400:
                print("Room ID/Alias in the wrong format")
                sys.exit(11)
            else:
                print("Couldn't find room.")
                sys.exit(12)

        self.room.send_text('I\'m now online.')
        self.opts = opts

        self.regexp = self.opts.regexp if self.opts.regexp else '^do:[ ]*(.*)::$'
        self.argsep = self.opts.argsep if self.opts.argsep else ';'
        self.inittalkbacktimeout = int(
            self.opts.inittalkbacktimeout
        ) if self.opts.inittalkbacktimeout else 5
        self.talkbacktimeout = int(
            self.opts.talkbacktimeout) if self.opts.talkbacktimeout else 30

        #
        # Listen in the room
        # ##################
        self.room.add_listener(self.command)
        self.client.start_listener_thread()
        while True:
            try:
                time.sleep(5)
            except Exception, e:
                self.room.send_text('I\'m leaving now... (' + str(e) + ")")
Beispiel #40
0
class CmdListener:
    rooms = {}
    mpc = None
    client = None
    stream_url = ""
    cmd_queue = None
    music_dir = None
    def __init__(self,config):
        self.mpc = MPCClient(config["mpc"]["host"],config["mpc"]["port"])
        self.music_dir = config["mpc"]["music_dir"]
        self.cmd_queue = Queue()

        try:
            self.mpc.current()
        except:
            raise Exception("An error occured while connecting to the mpd server.")
            return

        try:
            self.client = MatrixClient(config["matrix"]["host"])
        except:
            raise Exception("An error occured while connecting to the matrix server!")
            return


        self.stream_url = config["mpc"]["streamurl"]
        try:
            self.client.login_with_password(config["matrix"]["user"],config["matrix"]["pass"])
        except MatrixRequestError as e:
            print(e)
            if e.code == 403:
                print("Bad username or password.")
                sys.exit(4)
            else:
                print("Check your sever details are correct.")
                sys.exit(3)

        MTX_ROOMS = config["matrix"]["rooms"].split(",")

        for sroom in MTX_ROOMS:
            room = self.client.join_room(sroom)
            room.add_listener(self.__on_cmd)
            self.rooms[room.room_id] = room

    def run(self):
        self.client.start_listener_thread()
        while True:
            event = self.cmd_queue.get()
            if event is None:
                continue;
            else:
                cmd = event['content']['body']
                body = cmd.lower()
                if body.startswith('mpddj:') or body.startswith('!mpddj'):
                    self.__parse_command(body[6:],event,cmd[6:])
                elif body.startswith('mpd dj:'):
                    self.__parse_command(body[7:],event,cmd[7:])

    def __on_cmd(self,event):
        if event['type'] == "m.room.message" and event['content']['msgtype'] == "m.text":
            if event['age'] < 5000:
                self.cmd_queue.put(event)

    def __newfile_play(self,fname,max_attempts=25):
        # Do update check
        attempts = 0
        gotfile = False
        while attempts < max_attempts and not gotfile:
            musiclist = self.mpc.listall()
            gotfile = fname in musiclist
            if not gotfile:
                sleep(0.5)
            attempts += 1
        if gotfile:
            self.mpc.add(fname)
            self.mpc.play()

    def __parse_command(self,cmd,event,cmd_regular):
        cmd = cmd.strip()
        parts = cmd.split(" ")
        room = self.rooms[event['room_id']];
        if parts[0] == "shuffle":
            self.mpc.shuffle()
        elif parts[0] == "prev":
            self.mpc.next()
        elif parts[0] == "play":
            self.mpc.play()
        elif parts[0] == "next":
            self.mpc.next()
        elif parts[0] == "playlist":
            plist = self.mpc.playlist().split("\n")[:-1][:3]
            if len(plist) > 0:
                plist[0] = "▶ " + plist[0]
                room.send_text("\n".join(plist).replace(".ogg",""))
            else:
                room.send_text("The playlist is empty")
        elif parts[0] == "current":
            fname = self.mpc.current()
            fname = fname.replace("_"," ").replace(".ogg","")
            room.send_text(fname)
        elif parts[0] == "update":
            self.mpc.update()
        elif parts[0] == "help":
            room.send_text("Commands are: play,prev,next,current,playlist,help,[youtube url],stream url")
        elif "youtube.com/" in parts[0] or "soundcloud.com/" in parts[0]:
            pos = 1
            try:
                url = cmd_regular.strip().split(" ")[0]
                pos = len(self.mpc.playlist().split('\n'))-1
                status,fname = download_youtube(url,self.music_dir,self.__newfile_play)
            except Exception as e:
                print(e)
                print(traceback.format_exc())
                room.send_text("Couldn't download the file :(")
                return;
            self.mpc.update(True)


            if status:
                if fname is not False:
                    fi = fname.replace(".ogg","")
                    if pos > 0:
                        room.send_text(fi + " has been queued. It currently at position "+str(pos+1))
                    else:
                        room.send_text(fi + " has begun playing")
                else:
                    if pos > 1:
                        room.send_text("Your playlist has been queued. It currently at position "+str(pos))
                    else:
                        room.send_text("Your playlist has begun playing")
                if self.mpc.current() == '':
                    sleep(0.5)# Allow it to breathe
                    self.mpc.play()
            else:
                room.send_text("I couldn't play the file. This is probably a bug and should be reported to Half-Shot.")

        elif "stream url" in cmd:
            room.send_text(self.stream_url)
Beispiel #41
0
Datei: main.py Projekt: Xe/h2
sys.path += ['plugins']

# bootstrap the reloader
eval(compile(open(os.path.join('core', 'reload.py'), 'U').read(),
             os.path.join('core', 'reload.py'), 'exec'), globals())
reload(init=True)

print "matrix has u"

config = {}

with open("./config.yml", "r") as fin:
    config = load(fin.read())

client = MatrixClient(config["me"]["homeserver"])
token = client.login_with_password(username=config["me"]["user"], password=config["me"]["password"])

rooms = client.get_rooms()

def room_callback(event):
    room = rooms[event[u'room_id']]
    reload()
    if event[u'type'] == "m.room.message":
        print room.name, "<"+event[u'user_id']+">", event[u'content'][u'body']
        if event[u'user_id'] == config["me"]["user"]:
            return
        else:
            content = event[u'content']
            body = content[u'body']

            if body.startswith("."):
Beispiel #42
0
    1: '*WARNING*: ',
    0: 'OK: '
}

# Event information
try:
    client = sensu_event['client']['name']
    check = sensu_event['check']['name']
    output = sensu_event['check']['output']
    status = statuses[sensu_event['check']['status']]
    history = sensu_event['check']['history']
except Exception as e:
    print(str(e))

previous_status = history[len(history)-1]

# Message text
# *WARNING*: Client_name\n /tmp/test does not exists
text = status + client + "\n" + output

# Check previous status and send check information
if previous_status != sensu_event['check']['status']:
    # Initialize Matrix client
    client = MatrixClient(conf['homeserver'])
    token = client.login_with_password(username=conf['username'],
                                       password=conf['password'])
    # Join to Room
    room = client.join_room(conf['room'])

    room.send_text(text)