Beispiel #1
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 #2
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)
Beispiel #3
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 #4
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 #5
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 #6
0
class Matrix(object):
    def __init__(self, main):
        self.main = main
        self.login = login

        self.client = MatrixClient(address, encryption=encryption)
        self.client.login(login, passwd, device_id=device_id)

        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.rooms[room_id].send_text(text)
Beispiel #7
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 #8
0
class Matrix:
    def __init__(self, credentials, rooms, send_to, transport):
        self.credentials = credentials
        self.rooms = rooms
        self.send_to = send_to
        self.transport = transport
        self.connect()

    def connect(self):
        self.client = MatrixClient(self.credentials.host,
                                   token=self.credentials.token,
                                   user_id=self.credentials.userid)

        # Listen for events in all configured rooms
        for room in self.rooms:
            joined_room = self.client.join_room(room)
            joined_room.add_listener(self.listener)

        self.client.start_listener_thread()
        self.print_rooms()
        self.runner()

    def print_rooms(self):
        rooms = self.client.get_rooms()
        for room_id, room in rooms.items():
            print("Matrix: {} ({})".format(room_id, room.display_name))

    def runner(self):
        worker_thread = threading.Timer(1.0, self.runner)
        worker_thread.daemon = True
        worker_thread.start()

        if not self.transport.to_matrix.empty():
            message = self.transport.to_matrix.get()
            self.client.api.send_message(message.destination,
                                         message.get_message())

    def listener(self, room, message):
        if self.send_to.get(room.room_id):
            if message.get('content', {}).get('msgtype') == 'm.text':
                if self.credentials.userid != message['sender']:
                    message = Message(self.send_to[room.room_id],
                                      message['sender'],
                                      message['content']['body'])
                    self.transport.send_hangouts(message)
def main():
    client = MatrixClient(os.environ.get('BASE_URL'),
                          token=os.environ.get('TOKEN'),
                          user_id=os.environ.get('USER_ID'))

    # 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(os.environ.get('ROOM_ID'))
    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)
    print("Starting listener thread, bot ready")
    client.start_listener_thread()

    while True:
        msg = samples_common.get_input()
        if msg == "/quit":
            break
        else:
            room.send_text(msg)
Beispiel #10
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

    '''
Beispiel #13
0
class TinyMatrixtBot():
    def __init__(self, path_config):
        signal.signal(signal.SIGHUP, self.on_signal)
        signal.signal(signal.SIGINT, self.on_signal)
        signal.signal(signal.SIGTERM, self.on_signal)

        self.config = configparser.ConfigParser()
        self.config.read(path_config)

        path_current = os.path.dirname(os.path.realpath(__file__))

        self.path_lib = self.config.get("tiny-matrix-bot",
                                        "lib",
                                        fallback=os.path.join(
                                            path_current, "scripts")).strip()
        print("SCRIPTS {}".format(self.path_lib))
        if os.access(self.path_lib, os.R_OK):
            self.scripts = self.load_scripts(self.path_lib)
        else:
            print("ERROR {} is not readable".format(self.path_lib))
            sys.exit(0)

        self.path_var = self.config.get("tiny-matrix-bot",
                                        "var",
                                        fallback=os.path.join(
                                            path_current, "data")).strip()
        print("DATA {}".format(self.path_var))
        if os.access(self.path_var, os.W_OK):
            os.chdir(self.path_var)
        else:
            print("ERROR {} is not writeable".format(self.path_var))
            sys.exit(0)

        self.path_run = self.config.get("tiny-matrix-bot",
                                        "run",
                                        fallback=os.path.join(
                                            path_current, "sockets")).strip()
        if os.access(self.path_run, os.W_OK):
            print("SOCKETS {}".format(self.path_run))
        else:
            print("SOCKETS {} (not writeable, disabling sockets)".format(
                self.path_run))
            self.path_run = False

        self.client = MatrixClient(self.config.get("tiny-matrix-bot", "host"))
        self.client.login_with_password(
            username=self.config.get("tiny-matrix-bot", "user"),
            password=self.config.get("tiny-matrix-bot", "pass"))

        self.user = self.client.get_user(self.client.user_id)
        self.user.set_display_name(self.config.get("tiny-matrix-bot", "name"))

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

    def on_signal(self, signal, frame):
        if signal == 1:
            self.scripts = self.load_scripts(self.path_lib)
        elif signal in [2, 15]:
            sys.exit(0)

    def load_scripts(self, path):
        scripts = {}
        for script in os.listdir(path):
            script_path = os.path.join(path, script)
            if not os.access(script_path, os.R_OK) \
                or not os.access(script_path, os.X_OK):
                continue
            output = subprocess.Popen(
                [script_path],
                env={
                    "CONFIG": "1"
                },
                stdout=subprocess.PIPE,
                universal_newlines=True).communicate()[0].strip()
            if not output:
                continue
            scripts[output] = script_path
            print("LOAD {} {}".format(script, output))
        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.path_run is not False:
            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.path_run, 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("SOCKET {}".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, event, [script, body])

    def run_script(self, room, event, args):
        print("ROOM {}".format(event["room_id"]))
        print("SENDER {}".format(event["sender"]))
        print("RUN {}".format(args))
        output = subprocess.Popen(
            args,
            env={
                "MXROOMID": event["room_id"],
                "MXSENDER": event["sender"]
            },
            stdout=subprocess.PIPE,
            universal_newlines=True).communicate()[0].strip()
        sleep(0.5)
        for p in output.split("\n\n"):
            for l in p.split("\n"):
                print("OUTPUT {}".format(l))
            room.send_text(p)
            sleep(1)
Beispiel #14
0
def start(stdscr):
    global server, base_url, username, access_token, password
    global size, room, 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(base_url,
                          token=access_token,
                          user_id='@{}:{}'.format(username, server))
    if access_token is None:
        access_token = client.login_with_password(username, password, size[0])

    rooms = client.get_rooms()

    all_rooms = "all rooms"
    rooms[all_rooms] = all_rooms

    room_keys = list(rooms.keys())
    room = all_rooms

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

        line = "redpill v0.7"
        line += " · screen size: " + str(size)
        if isinstance(rooms[room], Room):
            line += " · chat size: " + str(len(rooms[room].events))
        line += " · room: "

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

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

        if isinstance(rooms[room], Room) and rooms[room].topic is not None:
            line += " · topic: " + rooms[room].topic

        line += " · variables: room: " + room + ", last: " + lastEventRoom

        stdscr.addstr(0, 0, line, curses.A_UNDERLINE)

        current = len(rooms[room].events) - 1 if isinstance(rooms[room],
                                                            Room) else -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):
                    log(event)
                    log("maxDisplayName: {}, size: {}, currentLine: {}".format(
                        maxDisplayName, size, currentLine))

                    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 = len(
                            event["sender"]) if "sender" in event else 0
                        log("length: {}, currentLine: {}".format(
                            length, currentLine))

                        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 = 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 += int(
                                                (displayNamestartingPos +
                                                 maxDisplayName + 3 + len(buf))
                                                / size[1])
                                        else:
                                            linesNeeded += int(
                                                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 += int(
                                (displayNamestartingPos + maxDisplayName + 3 +
                                 len(buf)) / size[1])
                            buf = ""

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

                            if PAD_COMMENTS:
                                pad = displayNamestartingPos + maxDisplayName + 3

                                linesNeeded += 1
                                currentLine -= linesNeeded

                                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

                                currentLine -= linesNeeded
                                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["sender"]

                            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"

                            currentLine -= 1
                            if length > maxDisplayName:
                                if currentLine == size[0] - 2:
                                    stdscr.addstr(
                                        currentLine,
                                        displayNamestartingPos + 1,
                                        str(event["sender"]),
                                        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["sender"]),
                                                  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["sender"]),
                                        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["sender"]), 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)
                log("key pressed: 0x{:X}".format(c))
                room = room_keys[(room_keys.index(room) + 1) % len(rooms)]
                the_room_to_post_to = None
            elif c == 10:  # enter
                with open('redpill-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
class matrix_utils_ext(object):

    __MODULE_NAME__ = "Matrix Bot"
    __VERSION__ = "v0.0.1a"

    __MAX_SERVICE__ = 32
    # Number of services that can be simultaneously installed.
    room_tuple = namedtuple("room_tuple", "room_addr listener")

    def __init__(self, config_path="config.json"):
        self.room_dic = {}
        self.services_sensitive_on_clock = set()
        self.is_timer_on = False
        self.is_on = False
        self.nb_current_service = 0
        self.service_list = {}
        # self.logger.setLevel(logging.DEBUG) ;
        try:
            with open(config_path) as f:
                self.config = json.loads(f.read())
        except IOError as e:
            print(e)
        self.login = self.config["login"]
        self.password = self.config["password"]
        module.config = self.config.copy()
        try:
            self.client = MatrixClient(self.config["host"])
            self.client.login(self.login, self.password)
        except MatrixRequestError as e:
            print(e)
            sys.exit()

    def add_service_to_room(self, room, service, message_on_start=None):
        ret = False
        if self.nb_current_service < matrix_utils_ext.__MAX_SERVICE__:
            if service.add_room(
                    room):  # if room has been added to the service correctly
                if service in self.service_list:
                    self.service_list[service] += 1
                else:
                    self.service_list[service] = 1
                ret = True
        else:
            #raise Exception("Maximum number of services ({}) reached".format(str(matrix_utils.__MAX_SERVICE__))) ;
            pass
        return ret

    def remove_service_from_room(self, room, service):
        ret = False
        if service.remove_room(room):
            ret = True
            # if service is not linked to any room, remove from service_list
            self.service_list[service] -= 1
            if self.service_list[service] == 0:
                del self.service_list[service]

        else:
            #raise Exception("Service {} does not exist in room {}.".format(service, room)) ;
            pass
        return ret

# TODO ; eventuellement vérifier si une room avec une même adresse n'existe pas ?

    def add_room(self, room_addr, message_on_start=""):
        room = self.client.join_room(room_addr)
        listener = room.add_listener(self.callback)
        self.room_dic[room] = matrix_utils_ext.room_tuple(
            room_addr, listener
        )  # (room object address, room_name (room address), listener object)
        if message_on_start:
            # Conversion to HTML format
            message_on_start = message_on_start.replace("\n", "<br>")
            message_on_start = message_on_start.replace("\t", "&emsp;")
            room.send_html(message_on_start, msgtype="m.notice")
        return room

    def remove_room(self, room):
        if not (room in self.room_dic):
            return False
        for service in service_list.keys():
            if (room in service.get_room_list()):
                # there are still some services linked to room.
                return False
        listener = self.room_dic[room].listener
        self.client.remove_listener(listener)
        room.leave()
        del self.room_dic[room]
        return True

    def callback(self, room, event):
        if event["type"] == "m.room.message":
            login = re.search("@[aA-zZ]+[0-9]*", event["sender"]).group(0)
            login = login[1:]
            tmp_log = "Event from " + bcolors.OKGREEN + self.room_dic[
                room].room_addr + bcolors.ENDC + " at " + str(
                    datetime.datetime.now()) + " by " + login
            print(tmp_log)
            text = str(event["content"]["body"])
            ## Stop Service Management
            if text == self.config["bot_down_cmd"]:
                self.exit()
            ## Otherwise, run services
            for service in self.service_list.keys():
                if (room in service.get_room_list()):
                    ret = service.run(text, login, room)
                    if ret:
                        for msg in ret:
                            # Conversion to HTML format
                            msg = msg.replace("\n", "<br>")
                            msg = msg.replace("\t", "&emsp;")
                            room.send_html(msg, msgtype="m.notice")

    def spawn(self):
        self.client.start_listener_thread(exception_handler=self.error_handle)
        self.is_on = True
        print(bcolors.OKGREEN +
              "\n---------------------------------------------------\n" +
              "---- Matrix Bot v0.0.1 ----------------------------\n" +
              "---------------------------------------------------\n" +
              bcolors.ENDC)
        while (self.is_on):
            time.sleep(0.5)

    def timer_callback(self, t):
        while (self.is_timer_on):
            if self.is_on:
                for service in self.service_list:
                    if service.is_clock_sensitive():
                        service.clock_update()
                        ret = service.run_on_clock()
                        if ret:
                            # Conversion to HTML format
                            ret = ret.replace("\n", "<br>")
                            ret = ret.replace("\t", "&emsp;")
                            for room in service.get_room_list():
                                room.send_html(ret, msgtype="m.notice")
            time.sleep(t)

    def start_timer(self, t=1):
        if not (self.is_timer_on):
            self.is_timer_on = True
            t1 = threading.Thread(target=self.timer_callback, args=(t, ))
            t1.start()

    def stop_timer(self):
        self.is_timer_on = False

    def exit(self):
        self.is_timer_on = False
        self.is_on = False
        for service in self.service_list:
            print("Module {} {} {} is shutting down.".format(
                bcolors.OKGREEN, service.module_name, bcolors.ENDC))
            tmp_msg = service.exit()
            if tmp_msg:
                for room in service.get_room_list():
                    room.send_text(tmp_msg)
        # for room in self.room_dic:
        # room.send_text(self.config["bot_stop_txt"]);
        sys.exit()

    def error_handle(self, err):
        print("Server is not {} responding {} ({}). Restarting ...".format(
            bcolors.FAIL, bcolors.ENDC, err))
        self.exit()
Beispiel #16
0
class matrixConnector:
    """
    Connector to the Matrix network

    Example:
    matrixObj = MatrixConnector(url, username, password, updatePersistentData, token)
        url = the url to the matrix server
        username = the username of the matrix Server
        password = the password of the matrix user
        updatePersistentData = Callback to the function to save the learned token
        token = the token of this client, we will resived this at the first connection.
    """

    # declare the variable
    __rooms = {}


    def __init__(self, url, username, password, updatePersistentData, token=None ):
        # save my own name
        matrixConnector.username = username
        if token is None:
            # Try to login with username and password
            self.__client = MatrixClient(url)
            try:
                self.__token = self.__client.login_with_password(username, password)
                # save the token
                value = self.__token
                updatePersistentData('matrix_token', value)

            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)
        else:
            # Try to login with token
            try:
                self.__client = MatrixClient(url, token, username)
                print("UserId:", self.__client.user_id)
            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)

    def joinRoom(self, room_id_alias):
        """ Join a Room
        room = obj.joinRoom(room_id_alias)
        """

        roomID = room_id_alias

        if room_id_alias.startswith("#"):
            roomID = self.__client.api.get_room_id(room_id_alias)


        if roomID not in self.discoverJoinedRooms().keys():
            return False

        try:
            room = self.__client.join_room(roomID)
        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.__rooms[roomID] = room

    def discoverJoinedRooms(self):
        # Discover what rooms the user has joined
        return self.__client.get_rooms()

    def start_listener_thread(self, onMessage):
        # Login to the rooms, to get the message out of the room
        matrixConnector.onMessage = onMessage
        self.__client.add_listener(self.__onEvent)
        self.__client.start_listener_thread()

    def __onEvent(room, event):
        # get the events out of the room
        message = event["content"]["body"]
        roomId = event["room_id"]
        matrixConnector.onMessage(message, roomId)

    def sendMessage(self, message, roomId):
        # Let the bot say something
        self.__rooms[roomId].send_html(message)
Beispiel #17
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 #18
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 #19
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 #20
0
class Glenda:
    def __init__(self, cfg):

        self.log = logging.getLogger(__name__)

        self.cfg = cfg

        self.matrix_rooms = {}
        self.lobby_rooms = {}
        self.matrix_client = None
        self.lobby_client = None

    # Called when a message is recieved from the matrix
    def on_room_message(self, room, event):
        if event['sender'] == "@{}:{}".format(self.cfg["matrix"]["username"],
                                              self.cfg["matrix"]["domain"]):
            # ignore messages sent by ourself
            return
        if event['type'] != "m.room.message":
            self.log.error("unknown event: %s" % (event))
            return
        if not event["room_id"] in self.matrix_rooms:
            self.log.error("Unknown room: %s vs %s" %
                           (event, self.matrix_rooms))
            return

        lobby_room = self.matrix_rooms[event["room_id"]]
        if event['content']['msgtype'] == "m.text":
            user = self.matrix_client.get_user(event['sender'])
            user_display_name = user.get_display_name()
            self.lobby_client.say(
                lobby_room, "<{}> {}".format(user_display_name,
                                             event['content']['body']))
        elif event['content']['msgtype'] == "m.emote":
            user = self.matrix_client.get_user(event['sender'])
            user_display_name = user.get_display_name()
            self.lobby_client.say_ex(
                lobby_room, "<{}> {}".format(user_display_name,
                                             event['content']['body']))
        elif event['content']['msgtype'] == "m.image":
            user = self.matrix_client.get_user(event['sender'])
            user_display_name = user.get_display_name()
            mxc_url = event['content']['url']
            o = urlparse(mxc_url)
            domain = o.netloc
            pic_code = o.path
            url = "https://{0}/_matrix/media/v1/download/{0}{1}".format(
                domain, pic_code)
            msg = "<{}> {}".format(user_display_name, url)
            self.lobby_client.say_ex(lobby_room,
                                     "<{}> {}".format(user_display_name, msg))

    def setup_bridge(self, lobby_room, matrix_room):
        self.lobby_client.channels_to_join.append("#{}".format(lobby_room))
        try:
            response = self.matrix_client.join_room(matrix_room)
            response.add_listener(self.on_room_message)
            self.lobby_rooms[lobby_room] = response
            self.matrix_rooms[response.room_id] = lobby_room
        except MatrixRequestError as e:
            if e.code == 400:
                self.log.error("Room ID/Alias in the wrong format")
                sys.exit(11)
            else:
                self.log.error("Couldn't find  %s room." % (matrix_room))
                sys.exit(12)

    async def run(self):

        self.lobby_client = await spring.connect(
            self.cfg["lobby"]["host"], port=self.cfg["lobby"]["port"])

        self.matrix_client = MatrixClient(self.cfg["matrix"]["host"])

        try:
            self.matrix_client.login(self.cfg["matrix"]["username"],
                                     self.cfg["matrix"]["pwd"],
                                     sync=True)

        except MatrixRequestError as e:
            self.log.debug(e)
            if e.code == 403:
                self.log.error("Bad username or password.")
                sys.exit(4)
            else:
                self.log.error("Check your sever details are correct.")
                sys.exit(2)

        except MissingSchema as e:
            self.log.error("Bad URL format.")
            self.log.error(e)
            sys.exit(3)

        for lobby_room, matrix_room in self.cfg["rooms"].items():
            self.setup_bridge(lobby_room, matrix_room)

        self.lobby_client.login(self.cfg["lobby"]["username"],
                                self.cfg["lobby"]["pwd"])

        try:
            self.matrix_client.login(self.cfg["matrix"]["username"],
                                     self.cfg["matrix"]["pwd"],
                                     sync=True)

        except MatrixRequestError as e:
            if e.code == 403:
                self.log.error("Bad username or password.")
                sys.exit(4)
            else:
                self.log.error("Check your sever details are correct.")
                sys.exit(2)

        except MissingSchema as e:
            self.log.error("Bad URL format.")
            self.log.error(e)
            sys.exit(3)

        self.matrix_client.start_listener_thread()
Beispiel #21
0
class matrix_utils_room(object):

    __MODULE_NAME__ = "Matrix Bot"
    __VERSION__ = "v0.0.2a"

    __MAX_SERVICE__ = 32 ; # Number of services that can be simultaneously installed.


    room_tuple = namedtuple("room_tuple", "room_obj, service_set")

    def __init__(self, config_path = "config.json"):
        self.room_dic = {} ;
        self.services_sensitive_on_clock = set() ;
        self.is_timer_on = False
        self.is_on = False ;
        self.nb_current_service = 0 ;
        self.service_list = {};
        # self.logger.setLevel(logging.DEBUG) ;
        try:
            with open(config_path) as f:
                self.config = json.loads(f.read());
        except IOError as e:
            print(e) ;
        self.login = self.config["login"] ;
        self.password = self.config["password"] ;
        module.config = self.config.copy();
        try:
            self.client = MatrixClient(self.config["host"])
            self.client.login(self.login, self.password) ;
        except MatrixRequestError as e:
            print(e)
            sys.exit() ;

    # @lock_dec
    def add_service_to_room(self, room, service, message_on_start = None):
        ret = False;
        if self.nb_current_service < matrix_utils_room.__MAX_SERVICE__:
            room_id = room.room_id;
            self.room_dic[room_id].service_set.add(service);
            service.add_room(room);
            on_start = service.on_start();
            if on_start:
                on_start = on_start.replace("\n", "<br>");
                on_start = on_start.replace("\t", "&emsp;");
                room.send_html(on_start, msgtype="m.notice");
            ret = True ;
        else:
            #raise Exception("Maximum number of services ({}) reached".format(str(matrix_utils.__MAX_SERVICE__))) ;
            pass;
        return ret;

    @lock_dec
    def remove_service_from_room(self, room, service):
        ret = False;
        room_id = room.room_id;
        if service in self.room_dic[room_id]:
            self.room_dic[room_id].service_set.remove(service);
            service.remove_room(room);
            ret = True;
        else:
            #raise Exception("Service {} does not exist in room {}.".format(service, room)) ;
            pass;
        return ret;

# TODO ; eventuellement vérifier si une room redirige vers un même salon ...
    @lock_dec
    def add_room(self, room_addr, message_on_start = ""):
        room = self.client.join_room(room_addr) ;
        room.current_alias = room_addr;
        room_id = room.room_id;
        if not(room_id in self.room_dic):
            listener = room.add_listener(self.callback) ;
            self.room_dic[room.room_id] = matrix_utils_room.room_tuple(room, set())  # (room object address, room_name (room address), listener object)
            if message_on_start:
                # Conversion to HTML format
                message_on_start = message_on_start.replace("\n", "<br>");
                message_on_start = message_on_start.replace("\t", "&emsp;");
                room.send_html(message_on_start, msgtype="m.notice");
        else:
            room = None;
        return room ;

    @lock_dec
    def remove_room(self, room):
        room_id = room.room_id;
        if not(room_id in self.room_dic) or (self.room_dic[room_id].service_set):
            return False;
        room.leave() ;
        del self.room_dic[room_id];
        return True;

    @lock_dec # ??
    def callback(self, room, event):
        if event["type"] == "m.room.message":
            login = re.search("@[aA-zZ]+[0-9]*", event["sender"]).group(0) ;
            login = login[1:] ;
            room_id = room.room_id;
            tmp_log = "Event from " + bcolors.OKGREEN + room.current_alias + bcolors.ENDC + " at " + str(datetime.datetime.now())+ " by "+login ;
            print(tmp_log)
            if "m.relates_to" in event["content"]:
                print("Current Event Ignored: "+bcolors.WARNING+"/!\\ Message Edit - Ignore"+bcolors.ENDC);
                return None;
            text = str(event["content"]["body"]) ;
            ## Stop Service Management
            if text == self.config["bot_down_cmd"]:
                self.exit();
            ## Otherwise, run services
            room_id = room.room_id;
            for service in self.room_dic[room_id].service_set:
                ret = service.run(text, login, room) ;
                if ret:
                    for msg in ret:
                        # Conversion to HTML format
                        msg = msg.replace("\n", "<br>");
                        msg = msg.replace("\t", "&emsp;");
                        room.send_html(msg, msgtype="m.notice");

    def spawn(self):
        self.client.start_listener_thread(exception_handler=self.error_handle);
        self.is_on = True ;
        print(bcolors.OKGREEN+
        "\n---------------------------------------------------\n"+
        "---- Matrix Bot v0.0.2 ----------------------------\n"+
        "---------------------------------------------------\n"+
        bcolors.ENDC)
        while(self.is_on):
            time.sleep(1)

    def timer_callback(self, t):
        format_to_html = lambda s : s.replace("\n", "<br>").replace("\t", "&emsp;");
        while(self.is_timer_on):
            time.sleep(t)
            for room_id in self.room_dic:
                room = self.room_dic[room_id].room_obj;
                for service in self.room_dic[room_id].service_set:
                    if service.is_clock_sensitive():
                        service.clock_update() ;
                        ret = service.run_on_clock(room) ;
                        if ret: # should return a string
                            ret = ret.replace("\n", "<br>");
                            ret = ret.replace("\t", "&emsp;");
                            room.send_html(ret, msgtype="m.notice");

    def start_timer(self, t = 1):
        if not(self.is_timer_on):
            self.is_timer_on = True ;
            t1 = threading.Thread(target=self.timer_callback, args=(t,))
            t1.start();

    def stop_timer(self):
        self.is_timer_on = False ;

    @lock_dec
    def exit(self):
        self.is_timer_on = False ;
        self.is_on = False ;
        service_ret_buffer = {}
        for room_id in self.room_dic:
            room = self.room_dic[room_id].room_obj;
            service_set = self.room_dic[room_id].service_set;
            for service in service_set:
                if not(service in service_ret_buffer):
                    print("Module {} {} {} is shutting down.".format(bcolors.OKGREEN, service.module_name, bcolors.ENDC)) ;
                    ret = service.exit();
                    service_ret_buffer[service] = ret;
                else:
                    ret = service_ret_buffer[service];
                if ret:
                    room.send_html(ret, msgtype="m.notice");
        # for room in self.room_dic:
            # room.send_text(self.config["bot_stop_txt"]);
        sys.exit() ;

    def error_handle(self, err):
        print("Server is not {} responding {} ({}). Restarting ...".format(bcolors.FAIL, bcolors.ENDC, err));
        self.exit();
def main():
    # type: () -> None
    signal.signal(signal.SIGINT, die)
    logging.basicConfig(level=logging.WARNING)

    parser = generate_parser()
    options = parser.parse_args()

    if options.sample_config:
        try:
            write_sample_config(options.sample_config)
        except Bridge_ConfigException as exception:
            sys.exit(exception)
        print("Wrote sample configuration to '{}'".format(options.sample_config))
        sys.exit(0)
    elif not options.config:
        print("Options required: -c or --config to run, OR --write-sample-config.")
        parser.print_usage()
        sys.exit(1)

    try:
        config = read_configuration(options.config)
    except Bridge_ConfigException as exception:
        sys.exit("Could not parse config file: {}".format(exception))

    # Get config for each client
    zulip_config = config["zulip"]
    matrix_config = config["matrix"]

    # Initiate clients
    backoff = zulip.RandomExponentialBackoff(timeout_success_equivalent=300)
    while backoff.keep_going():
        print("Starting matrix mirroring bot")
        try:
            zulip_client = zulip.Client(email=zulip_config["email"],
                                        api_key=zulip_config["api_key"],
                                        site=zulip_config["site"])
            matrix_client = MatrixClient(matrix_config["host"])

            # Login to Matrix
            matrix_login(matrix_client, matrix_config)
            # Join a room in Matrix
            room = matrix_join_room(matrix_client, matrix_config)

            room.add_listener(matrix_to_zulip(zulip_client, zulip_config, matrix_config,
                                              options.no_noise))

            print("Starting listener thread on Matrix client")
            matrix_client.start_listener_thread()

            print("Starting message handler on Zulip client")
            zulip_client.call_on_each_message(zulip_to_matrix(zulip_config, room))

        except Bridge_FatalMatrixException as exception:
            sys.exit("Matrix bridge error: {}".format(exception))
        except Bridge_ZulipFatalException as exception:
            sys.exit("Zulip bridge error: {}".format(exception))
        except zulip.ZulipError as exception:
            sys.exit("Zulip error: {}".format(exception))
        except Exception as e:
            traceback.print_exc()
        backoff.fail()
Beispiel #23
0
class MatrixBotAPI:

    # username - Matrix username
    # password - Matrix password
    # server   - Matrix server url : port
    # rooms    - List of rooms ids to operate in, or None to accept all rooms
    def __init__(self, username, password, server, rooms=None):
        self.username = username

        # Authenticate with given credentials
        self.client = MatrixClient(server)
        try:
            self.client.login_with_password(username, password)
        except MatrixRequestError as e:
            print(e)
            if e.code == 403:
                print("Bad username/password")
        except Exception as e:
            print("Invalid server URL")
            traceback.print_exc()

        # Store allowed rooms
        self.rooms = rooms

        # Store empty list of handlers
        self.handlers = []

        # If rooms is None, we should listen for invites and automatically accept them
        if rooms is None:
            self.client.add_invite_listener(self.handle_invite)
            self.rooms = []

            # Add all rooms we're currently in to self.rooms and add their callbacks
            for room_id, room in self.client.get_rooms().items():
                room.add_listener(self.handle_message)
                self.rooms.append(room_id)
        else:
            # Add the message callback for all specified rooms
            for room in self.rooms:
                room.add_listener(self.handle_message)

    def add_handler(self, handler):
        self.handlers.append(handler)

    def handle_message(self, room, event):
        # Make sure we didn't send this message
        if re.match("@" + self.username, event['sender']):
            return

        # Loop through all installed handlers and see if they need to be called
        for handler in self.handlers:
            if handler.test_callback(room, event):
                # This handler needs to be called
                handler.handle_callback(room, event)

    def handle_invite(self, room_id, state):
        print("Got invite to room: " + str(room_id))
        print("Joining...")
        room = self.client.join_room(room_id)

        # Add message callback for this room
        room.add_listener(self.handle_message)

        # Add room to list
        self.rooms.append(room)

    def start_polling(self):
        # Starts polling for messages
        self.client.start_listener_thread()
Beispiel #24
0
    matrix_config = config["matrix"]

    # Initiate clients
    backoff = wyzepal.RandomExponentialBackoff(timeout_success_equivalent=300)
    while backoff.keep_going():
        print("Starting matrix mirroring bot")
        try:
            wyzepal_client = wyzepal.Client(email=wyzepal_config["email"],
                                            api_key=wyzepal_config["api_key"],
                                            site=wyzepal_config["site"])
            matrix_client = MatrixClient(matrix_config["host"])

            # Login to Matrix
            matrix_login(matrix_client, matrix_config)
            # Join a room in Matrix
            room = matrix_join_room(matrix_client, matrix_config)

            room.add_listener(
                matrix_to_wyzepal(wyzepal_client, wyzepal_config,
                                  matrix_config))

            print("Starting listener thread on Matrix client")
            matrix_client.start_listener_thread()

            print("Starting message handler on WyzePal client")
            wyzepal_client.call_on_each_message(
                wyzepal_to_matrix(wyzepal_config, room))
        except Exception:
            traceback.print_exc()
        backoff.fail()
class MatrixBotAPI:

    # username          - Matrix username
    # password          - Matrix password
    # server            - Matrix server url : port
    # rooms             - List of rooms ids to operate in, or None to accept all rooms
    # accept_invites    - If true, accept invites to rooms
    def __init__(self,
                 username,
                 password,
                 server,
                 rooms=None,
                 accept_invites=True):
        self.username = username

        # Authenticate with given credentials
        self.client = MatrixClient(server)
        try:
            self.client.login(username, password)
        except MatrixRequestError as e:
            print(e)
            if e.code == 403:
                print("Bad username/password")
        except Exception as e:
            print(e)

        # Store allowed rooms. If rooms is None, store empty list
        # of rooms and add all rooms we're currently in
        if rooms:
            self.rooms = rooms
        else:
            self.rooms = []
            for room in self.client.rooms.values():
                self.rooms.append(room)
        print('Total rooms: ', len(self.rooms))
        # Store empty list of handlers
        self.handlers = []

        # we should listen for invites and automatically accept them
        if accept_invites:
            self.client.add_invite_listener(self.handle_invite)

        # Add handlers for all rooms
        for room in self.rooms:
            room.add_listener(self.handle_message)

    def add_handler(self, handler):
        self.handlers.append(handler)

    def handle_message(self, room, event):
        # Make sure we didn't send this message
        if re.match("@" + self.username, event['sender']):
            return

        # Loop through all installed handlers and see if they need to be called
        for handler in self.handlers:
            if handler.test_callback(event):
                # This handler needs to be called
                try:
                    handler.handle_callback(room, event)
                except:
                    traceback.print_exc()

    def handle_invite(self, room_id, state):
        print("Got invite to room: " + str(room_id))
        print("Joining...")
        room = self.client.join_room(room_id)

        # Add message callback for this room
        room.add_listener(self.handle_message)

        # Add room to list
        self.rooms.append(room)

    def send_message(self, message, room_id=None, room_alias=None):
        if not room_id:
            if not room_alias:  # send to all rooms if no room specified
                for room in self.rooms:
                    room.send_text(message)
                return True
            else:  # no ID but we have alias, so get room_id from it
                room_id = self.client.api.get_room_id(room_alias)
        room = self.client.rooms.get(room_id)
        if room and room in self.rooms:
            room.send_text(message)
            return True
        return False

    def start_polling(self):
        # Starts polling for messages
        self.client.start_listener_thread()
        return self.client.sync_thread
Beispiel #26
0
				chat off - disables all server logs
				spg:command - run spigot command, no feedback
				SPG:command - run spigot command, auto enables all logs on
				webcam - sends current webcam image
				generatemap - generates latest map
				minemap - sends current minecraft map image
				address - sends currect IP addresses
				help - that is me :)
				Bye master!"""
			    send_to_matrix("Yes master, {0} !".format(msg[1:]))
    else:
        #print(event['type'])
        pass

room.add_listener(on_message)
client.start_listener_thread()
room.send_notice("I am ready my master!")
print "I am ready"

server_screen=screenutils.Screen('server')

def follow(thefile,curinode,name):
    thefile.seek(0,2)
    while True:
        line = thefile.readline()
        if not line:
            time.sleep(0.1)
            try:
                if os.stat(name).st_ino != curinode:
                    new = open(name, "r")
                    thefile.close()
Beispiel #27
0
def main():
  global client
  global data
  global log
  global lock

  lock = threading.RLock()

  log.debug("try lock before main load_data()")
  with lock:
    log.debug("success lock before main load_data()")
    data=load_data()
  log.debug("release lock() after access global data")

  log.info("try init matrix-client")
  client = MatrixClient(conf.server)
  log.info("success init matrix-client")

  try:
      log.info("try login matrix-client")
      token = client.login(username=conf.username, password=conf.password,device_id=conf.device_id)
      log.info("success login matrix-client")
  except MatrixRequestError as e:
      print(e)
      log.debug(e)
      if e.code == 403:
          log.error("Bad username or password.")
          sys.exit(4)
      else:
          log.error("Check your sever details are correct.")
          sys.exit(2)
  except MissingSchema as e:
      log.error("Bad URL format.")
      print(e)
      log.debug(e)
      sys.exit(3)

  log.info("try init listeners")
  client.add_listener(on_message)
  client.add_ephemeral_listener(on_event)
  client.add_invite_listener(on_invite)
  client.start_listener_thread(exception_handler=exception_handler)
  log.info("success init listeners")

  try:
    x=0
    log.info("enter main loop")
    while True:
      if conf.type_translate == "yandex_long":
        # check yandex_long_jobs:
        num_jobs=0
        for room_id in data["rooms"]:
          if "jobs" in data["rooms"][room_id]:
            for job in data["rooms"][room_id]["jobs"]:
              ret_value=False
              num_jobs+=1
              ret_value=check_long_yandex_job(log,room_id,data["rooms"][room_id]["jobs"],job)
              if ret_value==False:
                log.error("check_long_yandex_job(), room_id=%s, job_id=%s"%(room_id,job["id"]))
                result_string="error get result from yandex speech api - yandex api error"
                log.error(result_string)
                if send_notice(room_id,result_string)==False:
                  log.error("send_notice(%s)"%room_id)
        if num_jobs > 0:
          log.debug("len jobs list for all rooms = %d"%num_jobs)
      time.sleep(3)
  except Exception as e:
    log.error(get_exception_traceback_descr(e))
    log.error("exception at main loop check jobs: %s"%e)
    sys.exit(1)

  log.info("exit main loop")
Beispiel #28
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 #29
0
class MatrixEngine(object):
    chatapi = ''
    chatclient = ''
    chattoken = ''
    listener_thread_id = 0
    new_msg_queue = []
    new_msg_senders = []

    def __init__(self, host=bothost, user=botuser, pwd=botpwd, room=botroom):
        print("Logging to matrix server...")
        self.chatclient = MatrixClient(host)
        try:
            self.chattoken = self.chatclient.login(username=user,
                                                   password=pwd,
                                                   sync=True)
        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)
        self.chatapi = MatrixHttpApi(host, self.chattoken)
        print("Login OK")

        ### handle messages
        print("Setting up listener")
        try:
            room = self.chatclient.join_room(room)
        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(self.on_message)
        self.listener_thread_id = self.chatclient.start_listener_thread()
        print('Listener set.. OK!')

    def sendmsg(self, msg, chatid=botroom):
        room = self.chatclient.join_room(chatid)
        response = self.chatapi.send_message(chatid, msg)

    def sendhtml(self, msg, chatid=botroom):
        room = self.chatclient.join_room(chatid)
        room.send_html(msg)

    def create_room(self, alias):
        ex_room = matrix_mongo.matrix_chats.find_one({"alias": alias})
        if ex_room:
            room_id = ex_room['room_id']
            room = self.chatclient.join_room(room_id)
            room.invite_user(ebuser)
        else:
            try:
                aldt = datetime.datetime.strftime(datetime.datetime.now(),
                                                  '%Y%m%d%H%M%S')
                new_room = self.chatclient.create_room(alias=alias + "_" +
                                                       aldt,
                                                       is_public=False,
                                                       invitees=[ebuser])
                room_id = new_room.room_id
                dtime = datetime.datetime.strftime(datetime.datetime.now(),
                                                   '%Y-%m-%d %H:%M:%S')
                chatdata = {
                    "created_date": dtime,
                    "alias": alias,
                    "room_alias": alias + "_" + aldt,
                    "room_id": room_id,
                    "room_data": room
                }

                recordID = matrix_mongo.matrix_chats.insert_one(chatdata)
            except MatrixRequestError as e:
                print(str(e))

        return room_id

    def sendfile(self, filename, chatid=botroom):
        room = self.chatclient.join_room(chatid)

        with open(filename, 'rb') as datafile:
            data = datafile.read()
            uri = self.chatclient.upload(content=data,
                                         content_type='image/jpg')
            print(uri)
            filedate = datetime.datetime.strftime(datetime.datetime.now(),
                                                  '%Y-%m-%d %H:%M:%S')
            room.send_image(
                uri, filedate + '_' + filename.replace('/', '_') + '.jpg')

    def on_message(self, room, event):
        try:
            # Called when a message is recieved.
            if event['type'] == "m.room.member":
                if event['membership'] == "join":
                    # print("{0} joined".format(event['content']['displayname']))
                    dtime = datetime.datetime.strftime(datetime.datetime.now(),
                                                       '%Y-%m-%d %H:%M:%S')
                    print(dtime + " new user joined to the room ")
            elif event['type'] == "m.room.message":
                if event['content']['msgtype'] == "m.text":
                    # print("{0}: {1}".format(event['sender'], event['content']['body']))
                    dtime = datetime.datetime.strftime(datetime.datetime.now(),
                                                       '%Y-%m-%d %H:%M:%S')
                    print(dtime + "|  '" + event['content']['body'] +
                          "' msg received from " + event['sender'])
                    if event['sender'] != "@mybot:matrix.org":
                        self.new_msg_senders.append(event['sender'])
                        self.new_msg_queue.append(event['content']['body'])
            else:
                print('new event in room:' + event['type'])
        except Exception as e:
            print('error @ on_message: ' + str(e))

    def parsemsg(self):
        for i in range(len(self.new_msg_queue)):
            origMsg = self.new_msg_queue[i]
            sender = self.new_msg_senders[i]

            msg = origMsg.lower()

            print("PARSER:  '" + origMsg + "' msg received from " + sender)

            def doshit():
                print('shit done')

            if msg == "test":
                doshit()
            elif msg == "msg":
                sendmsg("your msg responded!")
            elif msg == "html":
                sendhtml("your <b>html</b>  message <h1>responded</h1>!")
            else:
                print("message not understood")

            self.new_msg_queue.remove(origMsg)
            self.new_msg_senders.remove(sender)
def main() -> None:
    signal.signal(signal.SIGINT, die)
    logging.basicConfig(level=logging.WARNING)

    parser = generate_parser()
    options = parser.parse_args()

    if options.sample_config:
        try:
            write_sample_config(options.sample_config, options.zuliprc)
        except Bridge_ConfigException as exception:
            print(f"Could not write sample config: {exception}")
            sys.exit(1)
        if options.zuliprc is None:
            print(f"Wrote sample configuration to '{options.sample_config}'")
        else:
            print("Wrote sample configuration to '{}' using zuliprc file '{}'".
                  format(options.sample_config, options.zuliprc))
        sys.exit(0)
    elif not options.config:
        print(
            "Options required: -c or --config to run, OR --write-sample-config."
        )
        parser.print_usage()
        sys.exit(1)

    try:
        config = read_configuration(options.config)
    except Bridge_ConfigException as exception:
        print(f"Could not parse config file: {exception}")
        sys.exit(1)

    # Get config for each client
    zulip_config = config["zulip"]
    matrix_config = config["matrix"]

    # Initiate clients
    backoff = zulip.RandomExponentialBackoff(timeout_success_equivalent=300)
    while backoff.keep_going():
        print("Starting matrix mirroring bot")
        try:
            zulip_client = zulip.Client(
                email=zulip_config["email"],
                api_key=zulip_config["api_key"],
                site=zulip_config["site"],
            )
            matrix_client = MatrixClient(matrix_config["host"])

            # Login to Matrix
            matrix_login(matrix_client, matrix_config)
            # Join a room in Matrix
            room = matrix_join_room(matrix_client, matrix_config)

            room.add_listener(
                matrix_to_zulip(zulip_client, zulip_config, matrix_config,
                                options.no_noise))

            print("Starting listener thread on Matrix client")
            matrix_client.start_listener_thread()

            print("Starting message handler on Zulip client")
            zulip_client.call_on_each_message(
                zulip_to_matrix(zulip_config, room))

        except Bridge_FatalMatrixException as exception:
            sys.exit(f"Matrix bridge error: {exception}")
        except Bridge_ZulipFatalException as exception:
            sys.exit(f"Zulip bridge error: {exception}")
        except zulip.ZulipError as exception:
            sys.exit(f"Zulip error: {exception}")
        except Exception:
            traceback.print_exc()
        backoff.fail()
Beispiel #31
0
class Client:
    """
    A Matrix client implementation.

    :param server_url: The Matrix server URL
    :type server_url: str
    :param UI: The user interface object
    :type UI: :class:`.ui.base.BaseUI`
    """
    def __init__(self, server_url, UI):
        assert server_url, "Missing server URL"

        self.room = None

        self.client = MatrixClient(server_url)

        self.op_executor = OPExecutor(self._server_exception_handler)

        self.room_event_observer = RoomEventObserver(self)

        self.users = Users(self.client.api)

        commands = {}
        for name in dir(self):
            attr = getattr(self, name)
            if isinstance(attr, command.Command):
                commands[attr.cmd_type] = attr
        self.ui = UI(self.send_message, self.users, commands)

        self.users.set_modified_callback(self.ui.refresh_user_list)

    @property
    def connected(self):
        return self.client and self.client.should_listen

    def register(self, username, password):
        """
        Register a new user on the server.

        :param username: The username to register
        :type username: str
        :param password: The password to register
        :type password: str
        :raises RegistrationException:
        """
        assert username, "Missing username"
        assert password, "Missing password"

        LOG.info("Registering user {}".format(username))

        try:
            self.client.register_with_password(username=username,
                                               password=password)
        except MatrixRequestError as exc:
            LOG.exception(exc)

            try:
                content = json.loads(exc.content)
            except json.decoder.JSONDecodeError as json_exc:
                raise exceptions.RegistrationException(str(json_exc))

            try:
                if content["errcode"] in ("M_USER_IN_USE", "M_EXCLUSIVE"):
                    raise exceptions.UsernameTaken(username)

                if content["errcode"] == "M_INVALID_USERNAME":
                    raise exceptions.RegistrationException(content["error"])

                if content["errcode"] == "M_UNKNOWN":
                    if content["error"] == "Captcha is required.":
                        raise exceptions.CaptchaRequired()
            except KeyError:
                pass

            raise exceptions.RegistrationUnknownError(exc)

    def login(self, username, password):
        """
        Login to the server.

        If the login fails we try to register a new user using the same
        username and password.

        :param username: The username to login with
        :type username: str
        :param password: The password to login with
        :type password: str
        :raises LoginException:
        """
        assert username, "Missing username"
        assert password, "Missing password"

        LOG.info("Login with username {}".format(username))

        try:
            self.client.login_with_password(username=username,
                                            password=password)
        except MatrixRequestError as exc:
            LOG.exception(exc)

            try:
                content = json.loads(exc.content)
            except json.decoder.JSONDecodeError as json_exc:
                raise exceptions.LoginException(str(json_exc))

            try:
                if content["errcode"] == "M_FORBIDDEN":
                    raise exceptions.LoginFailed()
            except KeyError:
                pass

            raise exceptions.LoginUnknownError(exc)

    def create_room(self, room_alias):
        """
        Create a new room on the server.

        :param room_alias: The alias of the room to create
        :type room_alias: str
        """
        assert room_alias, "Missing room"

        LOG.info("Creating room {}".format(room_alias))
        """ #room:host -> room """
        room_alias_name = room_alias[1:].split(':')[0]

        self.room = self.client.create_room(room_alias_name)

    def join(self, room_alias):
        """
        Join a room.

        If the room does not already exist on the server we try to
        automatically create it.

        :param room_alias: The alias of the room to join
        :type room_alias: str
        :raises JoinRoomException:
        """
        assert room_alias, "Missing room"

        LOG.info("Joining room {}".format(room_alias))

        try:
            self.room = self.client.join_room(room_alias)
        except MatrixRequestError as exc:
            LOG.exception(exc)

            try:
                content = json.loads(exc.content)
            except json.decoder.JSONDecodeError as json_exc:
                exceptions.JoinRoomException(json_exc)

            try:
                if content["errcode"] == "M_NOT_FOUND":
                    raise exceptions.RoomNotFound()

                if content["errcode"] in ("M_FORBIDDEN", "M_UNKNOWN"):
                    raise exceptions.JoinRoomException(content["error"])
            except (KeyError, AttributeError):
                pass

            raise exceptions.JoinRoomUnknownError(exc)

    def run(self):
        """
        Run the client.
        """
        assert self.room, "You need to join a room before you run the client"

        self.room.add_listener(self.room_event_observer.on_room_event)

        self.op_executor.start()

        self.connect()

        self.ui.run()

    def stop(self):
        """
        Stop the client.
        """
        self.ui.stop()

        self.op_executor.stop()

        if self.connected:
            print("Waiting for server connection to close")
            print("Press ctrl+c to force stop")
            try:
                self.disconnect()
            except KeyboardInterrupt:
                pass

    def _server_exception_handler(self, exc):
        """
        Exception handler for Matrix server errors.
        """
        LOG.exception(exc)

        if isinstance(exc, ConnectionError):
            self.ui.draw_client_info("Server connection error")
        else:
            self.ui.draw_client_info("Unexpected server error: {}".format(exc))
            if not settings.debug:
                self.ui.draw_client_info(
                    "For more details enable debug mode, "
                    "reproduce the issue and check the logs. "
                    "Debug mode is enabled by setting the "
                    "MATRIX_DEBUG environment variable")

        self.disconnect()

    def _populate_room(self):
        # Clear the users model from old user data. To avoid duplicates when
        # for example reconnecting
        self.users.clear()

        # Temporarily disable UI user list refresh callback when doing the
        # initial population of the users model. Especially important for large
        # rooms which would cause an excessive amount of re-draws.
        modified_callback = self.users.modified_callback
        self.users.set_modified_callback(lambda: None)

        users = self.room.get_joined_members().items()
        for user_id, user in users:
            self.users.add_user(user_id, nick=user["displayname"])

        # Restore refresh callback
        self.users.set_modified_callback(modified_callback)

        # Execute an initial refresh
        modified_callback()

    @command.cmd(command.CONNECT, help_msg="Reconnect to the server")
    @op(require_connection=False)
    def connect(self):
        """
        Connect to the server.

        Before the client starts syncing events with the server it retrieves
        the users currently in the room and backfills previous messages. The
        number of previous messages backfilled are decidede by
        :const:`HISTORY_LIMIT`.
        """
        if self.connected:
            self.ui.draw_client_info("Already connected")
            return

        # Retrieve users currently in the room
        self._populate_room()

        # Get message history
        self.room.backfill_previous_messages(limit=HISTORY_LIMIT)

        self.client.start_listener_thread(
            timeout_ms=SERVER_TIMEOUT_MS,
            exception_handler=self._server_exception_handler)

        self.ui.draw_client_info("Connected to server")

    def disconnect(self):
        """
        Disconnect from the server.

        This also causes the user to logout when the sync thread has closed.
        """
        if self.connected:
            # Can't unfortunately cancel an in-flight request
            # https://github.com/kennethreitz/requests/issues/1353
            self.client.should_listen = False

            self.ui.draw_client_info("Disconnected")

            # Wait here for the matrix client sync thread to exit before
            # joining so that we can interrupt using signals.
            while self.client.sync_thread.isAlive():
                time.sleep(0.1)

        try:
            self.client.api.logout()
        except ConnectionError:
            pass

    @op
    def send_message(self, msg):
        """
        Send a message to the room.

        :param msg: Message to send
        :type msg: str
        """
        self.room.send_text(msg)

    @command.cmd(command.INVITE,
                 help_msg=("Invite a user to the room "
                           "(user_id syntax: @[mxid]:[server])"))
    @op
    def invite(self, user_id):
        """
        Invite a user to the room.

        :param user_id: The MXID of the user you want to invite
        :type user_id: str
        """
        try:
            self.client.api.invite_user(self.room.room_id, user_id)
            # self.room.invite_user(args[0])
        except MatrixRequestError as exc:
            try:
                error_msg = json.loads(exc.content)["error"]
            except:
                error_msg = str(exc)
            self.ui.draw_client_info("Invite error: {}".format(error_msg))

    @command.cmd(command.CHANGE_NICK, help_msg="Change nick")
    @op
    def change_nick(self, nick):
        """
        Change your nick.

        :param nick: The displayname you want to change to.
        :type nick: str
        """
        self.users.get_user(self.client.user_id).set_display_name(nick)

    @command.cmd(command.LEAVE, help_msg="Leave the room")
    def leave(self):
        """
        Leave the room.
        """
        # Stop listening for new events, when we leave the room we're forbidden
        # from interacting with the it anything anyway
        self.client.should_listen = False

        self.room.leave()

        self.ui.stop()

    @command.cmd(command.QUIT, help_msg="Exit the client")
    def quit(self):
        """
        Exit the client.
        """
        self.ui.stop()

    @command.cmd(command.HELP, help_msg="Show this")
    def show_help(self, cmd_type=None):
        """
        Show a help message explaining all the available commands.

        :param cmd_type: Use cmd_type to display the help message of a specific
                         command rather than all of them.
        :type cmd_type: int
        """
        self.ui.draw_help(cmd_type)
Beispiel #32
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 #33
0
class MatrigramClient(object):
    def __init__(self, server, tb, username):
        self.client = MatrixClient(server)
        self.tb = tb
        self.token = None
        self.server = server
        self.username = username
        self.focus_room_id = None
        self.msg_type_router = {
            'm.image': self.forward_image_to_tb,
            'm.audio': self.forward_voice_to_tb,
            'm.video': self.forward_video_to_tb,
            'm.emote': self.forward_emote_to_tb,
        }
        self.room_listener_uid = None
        self.ephemeral_listener_uid = None

    def login(self, username, password):
        try:
            self.token = self.client.login_with_password(username, password)
            logger.info('token = %s', self.token)
            rooms = self.get_rooms_aliases()
            if rooms:
                # set focus room to "first" room
                self.set_focus_room(rooms.keys()[0])

            self.client.add_invite_listener(self.on_invite_event)
            self.client.add_leave_listener(self.on_leave_event)
            self.client.start_listener_thread()
            return True, "OK"
        except MatrixRequestError:
            return False, "Failed to login"
        except ConnectionError:
            return False, "Server is offline"

    def logout(self):
        self.client.logout()

    def on_event(self, _, event):
        logger.debug('entered with message %s', pprint_json(event))
        sender = event['sender'].split(':')[0].encode('utf-8')

        # Prevent messages loopback
        if sender.startswith(u'@{}'.format(self.username)):
            return

        if event['type'] == "m.room.message":
            msgtype = event['content']['msgtype']

            if msgtype != 'm.text':
                callback = self.msg_type_router.get(msgtype)
                if callback:
                    callback(event)
                return

            content = event['content']['body'].encode('utf-8')
            self.tb.send_message(sender, content, self)

        elif event['type'] == "m.room.topic":
            topic = event['content']['topic'].encode('utf-8')
            self.tb.send_topic(sender, topic, self)

    def on_ephemeral_event(self, _, ee):
        logger.debug(pprint_json(ee))

        if ee['type'] == 'm.typing':
            if ee['content']['user_ids']:
                self.tb.start_typing_thread(self)
            else:
                self.tb.stop_typing_thread(self)

    def on_leave_event(self, room_id, le):
        logger.debug(pprint_json(le))

        if le['timeline']['events'][0]['sender'] != le['timeline']['events'][
                0]['state_key']:
            self.tb.send_kick(self._room_id_to_alias(room_id), self)

    def on_invite_event(self, _, ie):
        logger.debug('invite event %s', pprint_json(ie))
        room_name = None
        for event in ie['events']:
            if event['type'] == 'm.room.name':
                room_name = event['content']['name']

        if room_name:
            self.tb.send_invite(self, self._room_id_to_alias(room_name))

    def join_room(self, room_id_or_alias):
        try:
            self.client.join_room(room_id_or_alias)
            self.set_focus_room(room_id_or_alias)
            return True
        except MatrixRequestError:
            return False

    def leave_room(self, room_id_or_alias):
        room = self.get_room_obj(room_id_or_alias)
        if not room:
            logger.error('cant find room')
            return False

        if self.focus_room_id == room.room_id:
            rooms = self.get_rooms_aliases()
            room_id = self._room_alias_to_id(room_id_or_alias)

            del rooms[room_id]
            new_focus_room = rooms.keys()[0] if rooms else None
            self.set_focus_room(new_focus_room)

        return room.leave()

    def set_focus_room(self, room_id_or_alias):
        if self._room_alias_to_id(room_id_or_alias) == self.focus_room_id:
            return

        # remove current focus room listeners
        if self.focus_room_id is not None:
            room_obj = self.get_room_obj(self.focus_room_id)
            room_obj.remove_listener(self.room_listener_uid)
            self.room_listener_uid = None
            room_obj.remove_ephemeral_listener(self.ephemeral_listener_uid)
            self.ephemeral_listener_uid = None
            logger.info("remove focus room %s", self.focus_room_id)
            self.focus_room_id = None

        # set new room on focus
        if room_id_or_alias is not None:
            self.focus_room_id = self._room_alias_to_id(room_id_or_alias)
            room_obj = self.get_room_obj(self.focus_room_id)
            self.room_listener_uid = room_obj.add_listener(self.on_event)
            self.ephemeral_listener_uid = room_obj.add_ephemeral_listener(
                self.on_ephemeral_event)
            logger.info("set focus room to %s", self.focus_room_id)

    def get_focus_room_alias(self):
        return self._room_id_to_alias(self.focus_room_id)

    def have_focus_room(self):
        return self.focus_room_id is not None

    def get_members(self):
        room_obj = self.get_room_obj(self.focus_room_id)
        rtn = room_obj.get_joined_members()

        return [
            member['displayname'] for _, member in rtn.items()
            if member.get('displayname')
        ]

    def set_name(self, name):
        user = self.client.get_user(self.client.user_id)
        user.set_display_name(name)

    def emote(self, body):
        room_obj = self.get_room_obj(self.focus_room_id)
        room_obj.send_emote(body)

    def create_room(self, alias, is_public=False, invitees=()):
        try:
            room_obj = self.client.create_room(alias, is_public, invitees)
            room_obj.update_aliases()
            logger.debug('room_id %s', room_obj.room_id)
            logger.debug('room_alias %s', room_obj.aliases[0])
            return (room_obj.room_id, room_obj.aliases[0])
        except MatrixRequestError:
            logger.error('error creating room')
            return None, None

    def backfill_previous_messages(self, limit=10):
        room_obj = self.get_room_obj(self.focus_room_id)
        room_obj.backfill_previous_messages(limit=limit)

    def get_rooms_aliases(self):
        # returns a dict with id: room obj
        rooms = self._get_rooms_updated()
        if not rooms:
            return rooms

        logger.debug("rooms got from server are %s", rooms)

        # return dict with id: list of aliases or id (if no alias exists)
        return {
            key: val.aliases if val.aliases else [key]
            for (key, val) in rooms.items()
        }

    def get_room_obj(self, room_id_or_alias):
        """Get room object of specific id or alias.

        Args:
            room_id_or_alias (str): Room's id or alias.

        Returns (Room): Room object corresponding to room_id_or_alias.

        """
        rooms = self._get_rooms_updated()
        room_id = self._room_alias_to_id(room_id_or_alias)

        return rooms.get(room_id)

    def send_message(self, msg):
        room_obj = self.get_room_obj(self.focus_room_id)

        if not room_obj:
            logger.error('cant find room')
        else:
            room_obj.send_text(msg)

    def send_photo(self, path):
        with open(path, 'rb') as f:
            mxcurl = self.client.upload(f.read(),
                                        mimetypes.guess_type(path)[0])

            room_obj = self.get_room_obj(self.focus_room_id)

            if not room_obj:
                logger.error('cant find room')
            else:
                room_obj.send_image(mxcurl, os.path.split(path)[1])

    def send_voice(self, path):
        with open(path, 'rb') as f:
            mxcurl = self.client.upload(f.read(),
                                        mimetypes.guess_type(path)[0])
            room_obj = self.get_room_obj(self.focus_room_id)
            room_obj.send_audio(mxcurl, os.path.split(path)[1])

    def send_video(self, path):
        with open(path, 'rb') as f:
            mxcurl = self.client.upload(f.read(),
                                        mimetypes.guess_type(path)[0])
            room_obj = self.get_room_obj(self.focus_room_id)
            room_obj.send_video(mxcurl, os.path.split(path)[1])

    def discover_rooms(self):
        res = requests.get('{}/_matrix/client/r0/publicRooms?limit=20'.format(
            self.server))
        res_json = res.json()

        room_objs = res_json['chunk']
        return [
            room['aliases'][0] for room in room_objs if room.get('aliases')
        ]

    def download_from_event(self, event):
        mxcurl = event['content']['url']
        link = self.client.api.get_download_url(mxcurl)
        media_id = mxcurl.split('/')[3]
        media_type = event['content']['info']['mimetype'].split('/')[1]
        path = os.path.join(self.tb.config['media_dir'],
                            '{}.{}'.format(media_id, media_type))
        download_file(link, path)

        return path

    def forward_image_to_tb(self, event):
        sender = event['sender'].split(':')[0].encode('utf-8')
        path = self.download_from_event(event)
        self.tb.send_photo(sender, path, self)

    def forward_voice_to_tb(self, event):
        sender = event['sender'].split(':')[0].encode('utf-8')
        path = self.download_from_event(event)
        self.tb.send_voice(sender, path, self)

    def forward_video_to_tb(self, event):
        sender = event['sender'].split(':')[0].encode('utf-8')
        path = self.download_from_event(event)
        self.tb.send_video(sender, path, self)

    def forward_emote_to_tb(self, event):
        sender = event['sender'].split(':')[0].encode('utf-8')
        content = event['content']['body'].encode('utf-8')
        self.tb.send_emote(sender, content, self)

    def _room_id_to_alias(self, id):
        """Convert room id to alias.

        Args:
            id (str): Room id.

        Returns (str): Room alias.

        """
        if id is None:
            return None
        if id.startswith('#'):
            return id
        rooms = self.get_rooms_aliases()
        if id in rooms:
            return rooms[id][0]
        else:
            return None

    def _room_alias_to_id(self, alias):
        """Convert room alias to id.

        Args:
            alias (str): Room alias.

        Returns (str): Room id.

        """
        if alias is None:
            return None

        if not alias.startswith('#'):
            return alias

        return self.client.api.get_room_id(alias)

    def _get_rooms_updated(self):
        """Return rooms dictionary with updated aliases.

        Returns (dict): Return rooms dictionary with updated aliases.

        """
        rooms = self.client.get_rooms()
        for room in rooms.values():
            room.update_aliases()

        return rooms
Beispiel #34
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 #35
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