aboutsummaryrefslogtreecommitdiff
path: root/plugins/Matrix.hpp
blob: 7df29e1eb50b57b4513f546c8d65eb52f2af7e59 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#pragma once

#include "Plugin.hpp"
#include <unordered_map>
#include <json/value.h>

namespace QuickMedia {
    struct UserInfo {
        std::string user_id;
        std::string display_name;
        std::string avatar_url;
        sf::Color display_name_color;
    };

    enum class MessageType {
        TEXT,
        IMAGE,
        VIDEO
    };

    struct Message {
        // Index into |RoomData.user_info|
        size_t user_id;
        std::string event_id;
        std::string body;
        std::string url;
        std::string thumbnail_url;
        std::string replaces_event_id;
        MessageType type;
    };

    struct MessageInfo {
        int size = 0;
        int w = 0;
        int h = 0;
        const char* mimetype = nullptr;
    };

    struct RoomData {
        std::string id;
        // Each room has its own list of user data, even if multiple rooms has the same user
        // because users can have different display names and avatars in different rooms.
        // The value is an index to |user_info|.
        std::unordered_map<std::string, size_t> user_info_by_user_id;
        std::vector<UserInfo> user_info;
        std::vector<std::shared_ptr<Message>> messages;
        std::unordered_map<std::string, std::shared_ptr<Message>> message_by_event_id;
        std::string name;
        std::string avatar_url;
        std::string prev_batch;
        bool initial_fetch_finished = false;
        size_t last_read_index = 0;
    };

    enum class MessageDirection {
        BEFORE,
        AFTER
    };

    using RoomSyncMessages = std::unordered_map<RoomData*, std::vector<std::shared_ptr<Message>>>;

    class Matrix : public Plugin {
    public:
        Matrix();
        virtual ~Matrix() = default;
        bool search_is_filter() override { return true; }
        bool search_suggestions_has_thumbnails() const override { return true; }
        bool search_results_has_thumbnails() const override { return false; }
        int get_search_delay() const override { return 0; }
        bool search_suggestion_is_search() const override { return true; }
        Page get_page_after_search() const override { return Page::EXIT; }
        PluginResult get_cached_sync(BodyItems &result_items);
        PluginResult sync(RoomSyncMessages &room_messages);
        PluginResult get_joined_rooms(BodyItems &result_items);
        PluginResult get_all_synced_room_messages(const std::string &room_id, BodyItems &result_items);
        PluginResult get_new_room_messages(const std::string &room_id, BodyItems &result_items);
        PluginResult get_previous_room_messages(const std::string &room_id, BodyItems &result_items);
        SearchResult search(const std::string &text, BodyItems &result_items) override;

        // |url| should only be set when uploading media.
        // TODO: Make api better.
        PluginResult post_message(const std::string &room_id, const std::string &body, const std::string &url = "", MessageType msgtype = MessageType::TEXT, MessageInfo *info = nullptr);
        // |relates_to| is from |BodyItem.userdata| and is of type |Message*|
        PluginResult post_reply(const std::string &room_id, const std::string &body, void *relates_to);
        // |relates_to| is from |BodyItem.userdata| and is of type |Message*|
        PluginResult post_edit(const std::string &room_id, const std::string &body, void *relates_to);
        
        // TODO: Make this work for all image types and videos and regular files
        PluginResult post_file(const std::string &room_id, const std::string &filepath);
        PluginResult login(const std::string &username, const std::string &password, const std::string &homeserver, std::string &err_msg);
        PluginResult logout();

        // |message| is from |BodyItem.userdata| and is of type |Message*|
        PluginResult delete_message(const std::string &room_id, void *message, std::string &err_msg);

        PluginResult load_and_verify_cached_session();

        PluginResult on_start_typing(const std::string &room_id);
        PluginResult on_stop_typing(const std::string &room_id);

        // |message| is from |BodyItem.userdata| and is of type |Message*|
        bool was_message_posted_by_me(const std::string &room_id, void *message) const;

        std::string message_get_author_displayname(RoomData *room_data, Message *message) const;
    private:
        PluginResult sync_response_to_body_items(const Json::Value &root, RoomSyncMessages &room_messages);
        PluginResult get_previous_room_messages(const std::string &room_id, RoomData *room_data);
        void events_add_user_info(const Json::Value &events_json, RoomData *room_data);
        void events_add_messages(const Json::Value &events_json, RoomData *room_data, MessageDirection message_dir, RoomSyncMessages *room_messages);
        void events_set_room_name(const Json::Value &events_json, RoomData *room_data);

        std::shared_ptr<Message> get_edited_message_original_message(RoomData *room_data, std::shared_ptr<Message> message);
    private:
        std::unordered_map<std::string, std::unique_ptr<RoomData>> room_data_by_id;
        std::string user_id;
        std::string access_token;
        std::string homeserver;
        std::string next_batch;
    };
}