aboutsummaryrefslogtreecommitdiff
path: root/libdino/src/service/notification_events.vala
blob: d1e55113fba2a596815f1c98b0bffa83e9d75a4e (plain) (blame)
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
121
122
123
124
125
126
127
128
129
using Gee;

using Dino.Entities;
using Xmpp;

namespace Dino {

public class NotificationEvents : StreamInteractionModule, Object {
    public static ModuleIdentity<NotificationEvents> IDENTITY = new ModuleIdentity<NotificationEvents>("notification_events");
    public string id { get { return IDENTITY.id; } }

    public signal void notify_content_item(ContentItem content_item, Conversation conversation);
    public signal void notify_subscription_request(Conversation conversation);
    public signal void notify_connection_error(Account account, ConnectionManager.ConnectionError error);
    public signal void notify_muc_invite(Account account, Jid room_jid, Jid from_jid, string? password, string? reason);
    public signal void notify_voice_request(Account account, Jid room_jid, Jid from_jid, string nick);

    private StreamInteractor stream_interactor;
    private NotificationProvider? notifier;

    public static void start(StreamInteractor stream_interactor) {
        NotificationEvents m = new NotificationEvents(stream_interactor);
        stream_interactor.add_module(m);
    }

    public NotificationEvents(StreamInteractor stream_interactor) {
        this.stream_interactor = stream_interactor;

        stream_interactor.get_module(ContentItemStore.IDENTITY).new_item.connect(on_content_item_received);
        stream_interactor.get_module(PresenceManager.IDENTITY).received_subscription_request.connect(on_received_subscription_request);
        stream_interactor.get_module(MucManager.IDENTITY).invite_received.connect(on_invite_received);
        stream_interactor.get_module(MucManager.IDENTITY).voice_request_received.connect((account, room_jid, from_jid, nick) => {
            Conversation? conversation = stream_interactor.get_module(ConversationManager.IDENTITY).get_conversation(room_jid, account, Conversation.Type.GROUPCHAT);
            if (conversation == null) return;
            notifier.notify_voice_request.begin(conversation, from_jid);
        });
        stream_interactor.connection_manager.connection_error.connect((account, error) => notifier.notify_connection_error.begin(account, error));
        stream_interactor.get_module(ChatInteraction.IDENTITY).focused_in.connect((conversation) => {
            notifier.retract_content_item_notifications.begin();
            notifier.retract_conversation_notifications.begin(conversation);
        });
    }

    public void register_notification_provider(NotificationProvider notification_provider) {
        if (notifier == null || notifier.get_priority() < notification_provider.get_priority()) {
            notifier = notification_provider;
        }
    }

    private void on_content_item_received(ContentItem item, Conversation conversation) {
        ContentItem last_item = stream_interactor.get_module(ContentItemStore.IDENTITY).get_latest(conversation);

        if (item.id != last_item.id) return;
        if (item.id == conversation.read_up_to_item) return;
        if (stream_interactor.get_module(ChatInteraction.IDENTITY).is_active_focus()) return;

        Conversation.NotifySetting notify = conversation.get_notification_setting(stream_interactor);
        if (notify == Conversation.NotifySetting.OFF) return;

        string conversation_display_name = get_conversation_display_name(stream_interactor, conversation, null);
        string? participant_display_name = null;
        if (conversation.type_ == Conversation.Type.GROUPCHAT) {
            participant_display_name = get_participant_display_name(stream_interactor, conversation, item.jid);
        }

        switch (item.type_) {
            case MessageItem.TYPE:
                Message message = ((MessageItem) item).message;

                if (message.direction == Message.DIRECTION_SENT) return;

                if (notify == Conversation.NotifySetting.HIGHLIGHT) {
                    Jid? nick = stream_interactor.get_module(MucManager.IDENTITY).get_own_jid(conversation.counterpart, conversation.account);
                    if (nick == null) return;

                    bool highlight = Regex.match_simple("\\b" + Regex.escape_string(nick.resourcepart) + "\\b", message.body, RegexCompileFlags.CASELESS);
                    if (!highlight) return;
                }

                notifier.notify_message.begin(message, conversation, conversation_display_name, participant_display_name);
                break;
            case FileItem.TYPE:
                FileTransfer file_transfer = ((FileItem) item).file_transfer;
                bool is_image = file_transfer.mime_type != null && file_transfer.mime_type.has_prefix("image");

                // Don't notify on file transfers in a groupchat set to "mention only"
                if (notify == Conversation.NotifySetting.HIGHLIGHT) return;
                if (file_transfer.direction == FileTransfer.DIRECTION_SENT) return;

                notifier.notify_file.begin(file_transfer, conversation, is_image, conversation_display_name, participant_display_name);
                break;
        }
    }

    private void on_received_subscription_request(Jid jid, Account account) {
        Conversation conversation = stream_interactor.get_module(ConversationManager.IDENTITY).create_conversation(jid, account, Conversation.Type.CHAT);
        if (stream_interactor.get_module(ChatInteraction.IDENTITY).is_active_focus(conversation)) return;

        notifier.notify_subscription_request.begin(conversation);
    }

    private void on_invite_received(Account account, Jid room_jid, Jid from_jid, string? password, string? reason) {
        string inviter_display_name;
        if (room_jid.equals_bare(from_jid)) {
            Conversation conversation = new Conversation(room_jid, account, Conversation.Type.GROUPCHAT);
            inviter_display_name = get_participant_display_name(stream_interactor, conversation, from_jid);
        } else {
            Conversation direct_conversation = new Conversation(from_jid, account, Conversation.Type.CHAT);
            inviter_display_name = get_participant_display_name(stream_interactor, direct_conversation, from_jid);
        }
        notifier.notify_muc_invite.begin(account, room_jid, from_jid, inviter_display_name);
    }
}

public interface NotificationProvider : Object {
    public abstract double get_priority();

    public abstract async void notify_message(Message message, Conversation conversation, string conversation_display_name, string? participant_display_name);
    public abstract async void notify_file(FileTransfer file_transfer, Conversation conversation, bool is_image, string conversation_display_name, string? participant_display_name);
    public abstract async void notify_subscription_request(Conversation conversation);
    public abstract async void notify_connection_error(Account account, ConnectionManager.ConnectionError error);
    public abstract async void notify_muc_invite(Account account, Jid room_jid, Jid from_jid, string inviter_display_name);
    public abstract async void notify_voice_request(Conversation conversation, Jid from_jid);

    public abstract async void retract_content_item_notifications();
    public abstract async void retract_conversation_notifications(Conversation conversation);
}

}