aboutsummaryrefslogtreecommitdiff
path: root/libdino/src/service
diff options
context:
space:
mode:
authorfiaxh <git@lightrise.org>2022-01-19 16:54:56 +0100
committerfiaxh <git@lightrise.org>2022-02-07 01:21:11 +0100
commit071d925e370b2238a9804733a484fe4ec9432f44 (patch)
treecd1fba934d8a7f88df771c1df6fa1a3b3fdcd26a /libdino/src/service
parent4ef50db3e581016365087759d5af8649e37ab8a7 (diff)
downloaddino-071d925e370b2238a9804733a484fe4ec9432f44.tar.gz
dino-071d925e370b2238a9804733a484fe4ec9432f44.zip
Add support for call invite messages
As of https://github.com/xsf/xeps/pull/1155
Diffstat (limited to 'libdino/src/service')
-rw-r--r--libdino/src/service/call_state.vala15
-rw-r--r--libdino/src/service/calls.vala75
-rw-r--r--libdino/src/service/module_manager.vala2
3 files changed, 61 insertions, 31 deletions
diff --git a/libdino/src/service/call_state.vala b/libdino/src/service/call_state.vala
index 03ee9595..f49a77da 100644
--- a/libdino/src/service/call_state.vala
+++ b/libdino/src/service/call_state.vala
@@ -15,6 +15,7 @@ public class Dino.CallState : Object {
public Jid? parent_muc { get; set; }
public Jid? invited_to_group_call = null;
public Jid? group_call_inviter = null;
+ public string? invite_id = null;
public bool accepted { get; private set; default=false; }
public bool we_should_send_audio { get; set; default=false; }
@@ -61,7 +62,7 @@ public class Dino.CallState : Object {
yield stream.get_module(Xep.Muc.Module.IDENTITY).change_affiliation(stream, group_call.muc_jid, real_jid.bare_jid, null, "owner");
}
- stream.get_module(Xep.MujiMeta.Module.IDENTITY).send_invite(stream, muc, group_call.muc_jid, we_should_send_video, message_type);
+ stream.get_module(Xep.CallInvites.Module.IDENTITY).send_invite(stream, muc, group_call.muc_jid, we_should_send_video, message_type);
}
internal PeerState set_first_peer(Jid peer) {
@@ -84,7 +85,7 @@ public class Dino.CallState : Object {
if (invited_to_group_call != null) {
XmppStream stream = stream_interactor.get_stream(call.account);
if (stream == null) return;
- stream.get_module(Xep.MujiMeta.Module.IDENTITY).send_invite_accept_to_peer(stream, group_call_inviter, invited_to_group_call, message_type);
+ stream.get_module(Xep.CallInvites.Module.IDENTITY).send_accept(stream, group_call_inviter, invite_id, message_type);
join_group_call.begin(invited_to_group_call);
} else {
foreach (PeerState peer in peers.values) {
@@ -99,8 +100,7 @@ public class Dino.CallState : Object {
if (invited_to_group_call != null) {
XmppStream stream = stream_interactor.get_stream(call.account);
if (stream == null) return;
- stream.get_module(Xep.MujiMeta.Module.IDENTITY).send_invite_reject_to_self(stream, invited_to_group_call);
- stream.get_module(Xep.MujiMeta.Module.IDENTITY).send_invite_reject_to_peer(stream, group_call_inviter, invited_to_group_call, message_type);
+ stream.get_module(Xep.CallInvites.Module.IDENTITY).send_reject(stream, invited_to_group_call, invite_id, message_type);
}
var peers_cpy = new ArrayList<PeerState>();
peers_cpy.add_all(peers.values);
@@ -133,7 +133,7 @@ public class Dino.CallState : Object {
if (parent_muc != null && group_call != null) {
XmppStream stream = stream_interactor.get_stream(call.account);
if (stream == null) return;
- stream.get_module(Xep.MujiMeta.Module.IDENTITY).send_invite_retract_to_peer(stream, parent_muc, group_call.muc_jid, message_type);
+ stream.get_module(Xep.CallInvites.Module.IDENTITY).send_retract(stream, parent_muc, invite_id, message_type);
}
call.state = Call.State.MISSED;
} else {
@@ -172,9 +172,10 @@ public class Dino.CallState : Object {
debug("[%s] Inviting to muji call %s", call.account.bare_jid.to_string(), invitee.to_string());
yield stream.get_module(Xep.Muc.Module.IDENTITY).change_affiliation(stream, group_call.muc_jid, invitee, null, "owner");
- stream.get_module(Xep.MujiMeta.Module.IDENTITY).send_invite(stream, invitee, group_call.muc_jid, we_should_send_video, message_type);
+ stream.get_module(Xep.CallInvites.Module.IDENTITY).send_invite(stream, invitee, group_call.muc_jid, we_should_send_video, "chat");
// If the peer hasn't accepted within a minute, retract the invite
+ // TODO this should be unset when we retract the invite. otherwise a second invite attempt might break due to this
Timeout.add_seconds(60, () => {
if (this == null) return false;
@@ -187,7 +188,7 @@ public class Dino.CallState : Object {
if (!contains_peer) {
debug("[%s] Retracting invite to %s from %s", call.account.bare_jid.to_string(), group_call.muc_jid.to_string(), invitee.to_string());
- stream.get_module(Xep.MujiMeta.Module.IDENTITY).send_invite_retract_to_peer(stream, invitee, group_call.muc_jid, message_type);
+// stream.get_module(Xep.CallInvites.Module.IDENTITY).send_retract(stream, invitee, invite_id);
stream.get_module(Xep.Muc.Module.IDENTITY).change_affiliation.begin(stream, group_call.muc_jid, invitee, null, "none");
}
return false;
diff --git a/libdino/src/service/calls.vala b/libdino/src/service/calls.vala
index 44790014..7b6a2628 100644
--- a/libdino/src/service/calls.vala
+++ b/libdino/src/service/calls.vala
@@ -79,7 +79,10 @@ namespace Dino {
return (yield get_call_resources(conversation.account, conversation.counterpart)).size > 0 || has_jmi_resources(conversation.counterpart);
} else {
bool is_private = stream_interactor.get_module(MucManager.IDENTITY).is_private_room(conversation.account, conversation.counterpart);
- return is_private && can_initiate_groupcall(conversation.account);
+ EntityInfo entity_info = stream_interactor.get_module(EntityInfo.IDENTITY);
+ bool supports_ussid = yield entity_info.has_feature(conversation.account, conversation.counterpart.bare_jid, Xep.UniqueStableStanzaIDs.NS_URI);
+ bool supports_mam = yield entity_info.has_feature(conversation.account, conversation.counterpart.bare_jid, Xep.MessageArchiveManagement.NS_URI_2);
+ return is_private && (supports_ussid || supports_mam) && can_initiate_groupcall(conversation.account);
}
}
@@ -235,35 +238,43 @@ namespace Dino {
return peer_state;
}
- private CallState? get_call_state_for_groupcall(Account account, Jid muc_jid) {
+ private CallState? get_call_state_by_invite_id(Account account, Jid peer_jid, string invite_id) {
foreach (CallState call_state in call_states.values) {
if (!call_state.call.account.equals(account)) continue;
- if (call_state.group_call != null && call_state.group_call.muc_jid.equals(muc_jid)) return call_state;
- if (call_state.invited_to_group_call != null && call_state.invited_to_group_call.equals(muc_jid)) return call_state;
+ if (call_state.group_call != null && call_state.invite_id == invite_id) {
+ foreach (Jid jid in call_state.peers.keys) {
+ if (jid.equals(peer_jid)) {
+ return call_state;
+ }
+ }
+ }
+ if (call_state.invited_to_group_call != null && call_state.invited_to_group_call.equals(peer_jid)) return call_state;
}
return null;
}
- private async void on_muji_call_received(Account account, Jid inviter_jid, Jid muc_jid, Gee.List<StanzaNode> descriptions, string message_type) {
+ private async void on_muji_call_received(Account account, Jid inviter_jid, Jid muc_jid, string invite_id, bool video, string message_type) {
debug("[%s] Muji call received from %s for MUC %s, type %s", account.bare_jid.to_string(), inviter_jid.to_string(), muc_jid.to_string(), message_type);
foreach (Call call in call_states.keys) {
if (!call.account.equals(account)) return;
- // We already know the call; this is a reflection of our own invite
- if (call_states[call].parent_muc != null && call_states[call].parent_muc.equals_bare(inviter_jid)) return;
+ CallState call_state = call_states[call];
+
+ // If this is a MUC reflection of our own invite, store the sid assigned by the MUC
+ if (call_state.parent_muc != null && call_state.parent_muc.equals_bare(inviter_jid)) {
+ call_state.invite_id = invite_id;
+ return;
+ }
- if (call.counterparts.contains(inviter_jid) && call_states[call].accepted) {
+ if (call.counterparts.contains(inviter_jid) && call_state.accepted) {
// A call is converted into a group call.
- yield call_states[call].join_group_call(muc_jid);
+ yield call_state.join_group_call(muc_jid);
return;
}
}
- bool audio_requested = descriptions.any_match((description) => description.ns_uri == Xep.JingleRtp.NS_URI && description.get_attribute("media") == "audio");
- bool video_requested = descriptions.any_match((description) => description.ns_uri == Xep.JingleRtp.NS_URI && description.get_attribute("media") == "video");
-
Call call = new Call();
call.direction = Call.DIRECTION_INCOMING;
call.ourpart = account.full_jid;
@@ -280,12 +291,13 @@ namespace Dino {
CallState call_state = new CallState(call, stream_interactor);
connect_call_state_signals(call_state);
call_state.we_should_send_audio = true;
- call_state.we_should_send_video = video_requested;
+ call_state.we_should_send_video = video;
call_state.invited_to_group_call = muc_jid;
call_state.group_call_inviter = inviter_jid;
+ call_state.invite_id = invite_id;
debug("[%s] on_muji_call_received accepting", account.bare_jid.to_string());
- call_incoming(call_state.call, call_state, conversation, video_requested);
+ call_incoming(call_state.call, call_state, conversation, video);
}
private void remove_call_from_datastructures(Call call) {
@@ -379,26 +391,43 @@ namespace Dino {
remove_call_from_datastructures(call);
});
- Xep.MujiMeta.Module muji_meta_module = stream_interactor.module_manager.get_module(account, Xep.MujiMeta.Module.IDENTITY);
- muji_meta_module.call_proposed.connect((inviter_jid, to, muc_jid, descriptions, message_type) => {
- if (inviter_jid.equals_bare(account.bare_jid)) return;
- on_muji_call_received.begin(account, inviter_jid, muc_jid, descriptions, message_type);
+ Xep.CallInvites.Module call_invites_module = stream_interactor.module_manager.get_module(account, Xep.CallInvites.Module.IDENTITY);
+ call_invites_module.call_proposed.connect((from_jid, to_jid, video, join_methods, message_stanza) => {
+ if (from_jid.equals_bare(account.bare_jid)) return;
+ foreach (StanzaNode join_method_node in join_methods) {
+ if (join_method_node.ns_uri == Xep.Muji.NS_URI) {
+ string? room_jid_str = join_method_node.get_attribute("room");
+ if (room_jid_str == null) return;
+ Jid room_jid = new Jid(room_jid_str);
+ string? invite_id = null;
+ if (message_stanza.type_ == Xmpp.MessageStanza.TYPE_GROUPCHAT) {
+ invite_id = Xep.UniqueStableStanzaIDs.get_stanza_id(message_stanza, from_jid.bare_jid);
+ } else {
+ invite_id = message_stanza.id;
+ }
+ if (invite_id == null) {
+ warning("Got call invite without ID");
+ return;
+ }
+ on_muji_call_received.begin(account, from_jid, room_jid, id, video, message_stanza.type_);
+ }
+ }
});
- muji_meta_module.call_accepted.connect((from_jid, muc_jid, message_type) => {
+ call_invites_module.call_accepted.connect((from_jid, invite_id, message_type) => {
if (!from_jid.equals_bare(account.bare_jid)) return;
// We accepted the call from another device
- CallState? call_state = get_call_state_for_groupcall(account, muc_jid);
+ CallState? call_state = get_call_state_by_invite_id(account, from_jid, invite_id);
if (call_state == null) return;
call_state.call.state = Call.State.OTHER_DEVICE;
remove_call_from_datastructures(call_state.call);
});
- muji_meta_module.call_retracted.connect((from_jid, to_jid, muc_jid, message_type) => {
+ call_invites_module.call_retracted.connect((from_jid, to_jid, invite_id, message_type) => {
if (from_jid.equals_bare(account.bare_jid)) return;
// The call was retracted by the counterpart
- CallState? call_state = get_call_state_for_groupcall(account, muc_jid);
+ CallState? call_state = get_call_state_by_invite_id(account, from_jid, invite_id);
if (call_state == null) return;
if (call_state.call.state != Call.State.RINGING) {
@@ -411,7 +440,7 @@ namespace Dino {
call_state.call.state = Call.State.MISSED;
remove_call_from_datastructures(call_state.call);
});
- muji_meta_module.call_rejected.connect((from_jid, to_jid, muc_jid, message_type) => {
+ call_invites_module.call_rejected.connect((from_jid, to_jid, muc_jid, message_type) => {
if (from_jid.equals_bare(account.bare_jid)) return;
debug(@"[%s] %s rejected our MUJI invite to %s", account.bare_jid.to_string(), from_jid.to_string(), muc_jid.to_string());
});
diff --git a/libdino/src/service/module_manager.vala b/libdino/src/service/module_manager.vala
index 39ed8a7c..b54b1a1e 100644
--- a/libdino/src/service/module_manager.vala
+++ b/libdino/src/service/module_manager.vala
@@ -82,7 +82,7 @@ public class ModuleManager {
module_map[account].add(new Xep.JingleMessageInitiation.Module());
module_map[account].add(new Xep.JingleRawUdp.Module());
module_map[account].add(new Xep.Muji.Module());
- module_map[account].add(new Xep.MujiMeta.Module());
+ module_map[account].add(new Xep.CallInvites.Module());
module_map[account].add(new Xep.Coin.Module());
initialize_account_modules(account, module_map[account]);
}