aboutsummaryrefslogtreecommitdiff
path: root/libdino
diff options
context:
space:
mode:
Diffstat (limited to 'libdino')
-rw-r--r--libdino/CMakeLists.txt2
-rw-r--r--libdino/src/dbus/notifications.vala29
-rw-r--r--libdino/src/service/notification_events.vala100
-rw-r--r--libdino/src/util/display_name.vala97
4 files changed, 202 insertions, 26 deletions
diff --git a/libdino/CMakeLists.txt b/libdino/CMakeLists.txt
index 9c2145e3..b3293a68 100644
--- a/libdino/CMakeLists.txt
+++ b/libdino/CMakeLists.txt
@@ -11,6 +11,7 @@ SOURCES
src/application.vala
src/dbus/login1.vala
+ src/dbus/notifications.vala
src/dbus/upower.vala
src/entity/account.vala
@@ -49,6 +50,7 @@ SOURCES
src/service/stream_interactor.vala
src/service/util.vala
+ src/util/display_name.vala
src/util/util.vala
src/util/weak_map.vala
CUSTOM_VAPIS
diff --git a/libdino/src/dbus/notifications.vala b/libdino/src/dbus/notifications.vala
new file mode 100644
index 00000000..68401440
--- /dev/null
+++ b/libdino/src/dbus/notifications.vala
@@ -0,0 +1,29 @@
+namespace Dino {
+
+ [DBus (name = "org.freedesktop.Notifications")]
+ public interface DBusNotifications : GLib.Object {
+
+ public signal void action_invoked(uint32 key, string action_key);
+
+ public signal void notification_closed (uint32 id, uint32 reason);
+
+ public abstract uint32 notify(string app_name, uint32 replaces_id, string app_icon, string summary,
+ string body, string[] actions, HashTable<string, Variant> hints, int32 expire_timeout) throws DBusError, IOError;
+
+ public abstract void get_capabilities(out string[] capabilities) throws Error;
+
+ public abstract void close_notification(uint id) throws DBusError, IOError;
+
+ public abstract void get_server_information(out string name, out string vendor, out string version, out string spec_version) throws DBusError, IOError;
+ }
+
+ public static DBusNotifications? get_notifications_dbus() {
+ DBusNotifications? upower = null;
+ try {
+ upower = Bus.get_proxy_sync(BusType.SESSION, "org.freedesktop.Notifications", "/org/freedesktop/Notifications");
+ } catch (IOError e) {
+ warning("Couldn't get org.freedesktop.Notifications DBus instance: %s\n", e.message);
+ }
+ return upower;
+ }
+} \ No newline at end of file
diff --git a/libdino/src/service/notification_events.vala b/libdino/src/service/notification_events.vala
index f6ef7019..d1e55113 100644
--- a/libdino/src/service/notification_events.vala
+++ b/libdino/src/service/notification_events.vala
@@ -16,6 +16,7 @@ public class NotificationEvents : StreamInteractionModule, Object {
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);
@@ -27,55 +28,102 @@ public class NotificationEvents : StreamInteractionModule, Object {
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((account, room_jid, from_jid, password, reason) => notify_muc_invite(account, room_jid, from_jid, password, reason));
- stream_interactor.get_module(MucManager.IDENTITY).voice_request_received.connect((account, room_jid, from_jid, nick) => notify_voice_request(account, room_jid, from_jid, nick));
- stream_interactor.connection_manager.connection_error.connect((account, error) => notify_connection_error(account, error));
+ 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 && last_item.id != conversation.read_up_to_item) return;
-
- if (!should_notify(item, conversation)) return;
+ 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;
- notify_content_item(item, conversation);
- }
- private bool should_notify(ContentItem content_item, Conversation conversation) {
Conversation.NotifySetting notify = conversation.get_notification_setting(stream_interactor);
+ if (notify == Conversation.NotifySetting.OFF) return;
- if (notify == Conversation.NotifySetting.OFF) return false;
+ 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 (content_item.type_) {
+ switch (item.type_) {
case MessageItem.TYPE:
- Message message = ((MessageItem) content_item).message;
- if (message.direction == Message.DIRECTION_SENT) return false;
+ 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) content_item).file_transfer;
- // Don't notify on file transfers in a groupchat set to "mention only"
- if (notify == Conversation.NotifySetting.HIGHLIGHT) return false;
- if (file_transfer.direction == FileTransfer.DIRECTION_SENT) return false;
- break;
- }
+ FileTransfer file_transfer = ((FileItem) item).file_transfer;
+ bool is_image = file_transfer.mime_type != null && file_transfer.mime_type.has_prefix("image");
- if (content_item.type_ == MessageItem.TYPE && notify == Conversation.NotifySetting.HIGHLIGHT) {
- Jid? nick = stream_interactor.get_module(MucManager.IDENTITY).get_own_jid(conversation.counterpart, conversation.account);
- if (nick == null) return false;
+ // 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;
- Entities.Message message = ((MessageItem) content_item).message;
- return Regex.match_simple("\\b" + Regex.escape_string(nick.resourcepart) + "\\b", message.body, RegexCompileFlags.CASELESS);
+ notifier.notify_file.begin(file_transfer, conversation, is_image, conversation_display_name, participant_display_name);
+ break;
}
- return true;
}
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;
- notify_subscription_request(conversation);
+ 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);
}
}
diff --git a/libdino/src/util/display_name.vala b/libdino/src/util/display_name.vala
new file mode 100644
index 00000000..9296fbf3
--- /dev/null
+++ b/libdino/src/util/display_name.vala
@@ -0,0 +1,97 @@
+using Gee;
+
+using Dino.Entities;
+using Xmpp;
+
+namespace Dino {
+ public static string get_conversation_display_name(StreamInteractor stream_interactor, Conversation conversation, string? muc_pm_format) {
+ if (conversation.type_ == Conversation.Type.CHAT) {
+ string? display_name = get_real_display_name(stream_interactor, conversation.account, conversation.counterpart);
+ if (display_name != null) return display_name;
+ return conversation.counterpart.to_string();
+ }
+ if (conversation.type_ == Conversation.Type.GROUPCHAT) {
+ return get_groupchat_display_name(stream_interactor, conversation.account, conversation.counterpart);
+ }
+ if (conversation.type_ == Conversation.Type.GROUPCHAT_PM) {
+ return (muc_pm_format ?? "%s / %s").printf(get_occupant_display_name(stream_interactor, conversation, conversation.counterpart), get_groupchat_display_name(stream_interactor, conversation.account, conversation.counterpart.bare_jid));
+ }
+ return conversation.counterpart.to_string();
+ }
+
+ public static string get_participant_display_name(StreamInteractor stream_interactor, Conversation conversation, Jid participant, string? self_word = null) {
+ if (self_word != null) {
+ if (conversation.account.bare_jid.equals_bare(participant) ||
+ (conversation.type_ == Conversation.Type.GROUPCHAT || conversation.type_ == Conversation.Type.GROUPCHAT_PM) &&
+ conversation.nickname != null && participant.equals_bare(conversation.counterpart) && conversation.nickname == participant.resourcepart) {
+ return self_word;
+ }
+ }
+ if (conversation.type_ == Conversation.Type.CHAT) {
+ return get_real_display_name(stream_interactor, conversation.account, participant, self_word) ?? participant.bare_jid.to_string();
+ }
+ if ((conversation.type_ == Conversation.Type.GROUPCHAT || conversation.type_ == Conversation.Type.GROUPCHAT_PM) && conversation.counterpart.equals_bare(participant)) {
+ return get_occupant_display_name(stream_interactor, conversation, participant);
+ }
+ return participant.bare_jid.to_string();
+ }
+
+ private static string? get_real_display_name(StreamInteractor stream_interactor, Account account, Jid jid, string? self_word = null) {
+ if (jid.equals_bare(account.bare_jid)) {
+ if (self_word != null || account.alias == null || account.alias.length == 0) {
+ return self_word;
+ }
+ return account.alias;
+ }
+ Roster.Item roster_item = stream_interactor.get_module(RosterManager.IDENTITY).get_roster_item(account, jid);
+ if (roster_item != null && roster_item.name != null && roster_item.name != "") {
+ return roster_item.name;
+ }
+ return null;
+ }
+
+ private static string get_groupchat_display_name(StreamInteractor stream_interactor, Account account, Jid jid) {
+ MucManager muc_manager = stream_interactor.get_module(MucManager.IDENTITY);
+ string? room_name = muc_manager.get_room_name(account, jid);
+ if (room_name != null && room_name != jid.localpart) {
+ return room_name;
+ }
+ if (muc_manager.is_private_room(account, jid)) {
+ Gee.List<Jid>? other_occupants = muc_manager.get_other_offline_members(jid, account);
+ if (other_occupants != null && other_occupants.size > 0) {
+ var builder = new StringBuilder ();
+ foreach(Jid occupant in other_occupants) {
+ if (builder.len != 0) {
+ builder.append(", ");
+ }
+ builder.append((get_real_display_name(stream_interactor, account, occupant) ?? occupant.localpart ?? occupant.domainpart).split(" ")[0]);
+ }
+ return builder.str;
+ }
+ }
+ return jid.to_string();
+ }
+
+ private static string get_occupant_display_name(StreamInteractor stream_interactor, Conversation conversation, Jid jid, string? self_word = null, bool muc_real_name = false) {
+ if (muc_real_name) {
+ MucManager muc_manager = stream_interactor.get_module(MucManager.IDENTITY);
+ if (muc_manager.is_private_room(conversation.account, jid.bare_jid)) {
+ Jid? real_jid = muc_manager.get_real_jid(jid, conversation.account);
+ if (real_jid != null) {
+ string? display_name = get_real_display_name(stream_interactor, conversation.account, real_jid, self_word);
+ if (display_name != null) return display_name;
+ }
+ }
+ }
+
+ // If it's us (jid=our real full JID), display our nick
+ if (conversation.type_ == Conversation.Type.GROUPCHAT_PM && conversation.account.bare_jid.equals_bare(jid)) {
+ var muc_conv = stream_interactor.get_module(ConversationManager.IDENTITY).get_conversation(conversation.counterpart.bare_jid, conversation.account, Conversation.Type.GROUPCHAT);
+ if (muc_conv != null && muc_conv.nickname != null) {
+ return muc_conv.nickname;
+ }
+ }
+
+ return jid.resourcepart ?? jid.to_string();
+ }
+} \ No newline at end of file