aboutsummaryrefslogtreecommitdiff
path: root/libdino/src/service/calls.vala
diff options
context:
space:
mode:
Diffstat (limited to 'libdino/src/service/calls.vala')
-rw-r--r--libdino/src/service/calls.vala208
1 files changed, 141 insertions, 67 deletions
diff --git a/libdino/src/service/calls.vala b/libdino/src/service/calls.vala
index 7b6a2628..c97b296c 100644
--- a/libdino/src/service/calls.vala
+++ b/libdino/src/service/calls.vala
@@ -19,8 +19,8 @@ namespace Dino {
private StreamInteractor stream_interactor;
private Database db;
- public HashMap<Account, CallState> current_jmi_request_call = new HashMap<Account, CallState>(Account.hash_func, Account.equals_func);
- public HashMap<Account, PeerState> current_jmi_request_peer = new HashMap<Account, PeerState>(Account.hash_func, Account.equals_func);
+// public HashMap<Account, CallState> current_jmi_request_call = new HashMap<Account, CallState>(Account.hash_func, Account.equals_func);
+ public HashMap<Call, PeerState> jmi_request_peer = new HashMap<Call, PeerState>(Call.hash_func, Call.equals_func);
public HashMap<Call, CallState> call_states = new HashMap<Call, CallState>(Call.hash_func, Call.equals_func);
public static void start(StreamInteractor stream_interactor, Database db) {
@@ -55,6 +55,7 @@ namespace Dino {
if (conversation.type_ == Conversation.Type.CHAT) {
call.add_peer(conversation.counterpart);
PeerState peer_state = call_state.set_first_peer(conversation.counterpart);
+ jmi_request_peer[call] = peer_state;
yield peer_state.initiate_call(conversation.counterpart);
} else {
call_state.initiate_groupchat_call.begin(conversation.counterpart);
@@ -167,7 +168,7 @@ namespace Dino {
peer_state.accept();
} else {
debug(@"[%s] Incoming call, but didn't see peer in MUC yet", account.bare_jid.to_string());
- PeerState peer_state = new PeerState(session.peer_full_jid, call_state.call, stream_interactor);
+ PeerState peer_state = new PeerState(session.peer_full_jid, call_state.call, call_state, stream_interactor);
peer_state.set_session(session);
call_state.add_peer(peer_state);
}
@@ -180,15 +181,22 @@ namespace Dino {
debug(@"[%s] Incoming call from %s", account.bare_jid.to_string(), session.peer_full_jid.to_string());
// Check if we already accepted this call via Jingle Message Initiation => accept
- if (current_jmi_request_call.has_key(account) &&
- current_jmi_request_peer[account].sid == session.sid &&
- current_jmi_request_peer[account].we_should_send_video == counterpart_wants_video &&
- current_jmi_request_peer[account].accepted_jmi) {
- current_jmi_request_peer[account].set_session(session);
- current_jmi_request_call[account].accept();
-
- current_jmi_request_peer.unset(account);
- current_jmi_request_call.unset(account);
+ Call? call = null;
+ foreach (PeerState peer_state in jmi_request_peer.values) {
+ CallState call_state = call_states[peer_state.call];
+ if (peer_state.sid == session.sid &&
+ call_state.call.account.equals(account) &&
+ peer_state.jid.equals_bare(session.peer_full_jid) &&
+ call_state.we_should_send_video == counterpart_wants_video &&
+ call_state.accepted) {
+ call = peer_state.call;
+ break;
+ }
+ }
+ if (call != null) {
+ jmi_request_peer[call].set_session(session);
+ jmi_request_peer[call].accept();
+ jmi_request_peer.unset(call);
return;
}
@@ -218,9 +226,7 @@ namespace Dino {
call.encryption = Encryption.UNKNOWN;
Conversation conversation = stream_interactor.get_module(ConversationManager.IDENTITY).create_conversation(call.counterpart.bare_jid, account, Conversation.Type.CHAT);
-
stream_interactor.get_module(CallStore.IDENTITY).add_call(call, conversation);
-
conversation.last_active = call.time;
var call_state = new CallState(call, stream_interactor);
@@ -238,40 +244,58 @@ namespace Dino {
return peer_state;
}
- private CallState? get_call_state_by_invite_id(Account account, Jid peer_jid, string invite_id) {
+ private CallState? get_call_state_by_invite_id(Account account, string invite_id, Jid jid1, Jid jid2) {
+ Jid relevant_jid = jid1.equals_bare(account.bare_jid) ? jid2 : jid1;
+
foreach (CallState call_state in call_states.values) {
if (!call_state.call.account.equals(account)) continue;
- if (call_state.group_call != null && call_state.invite_id == invite_id) {
+ if (call_state.cim_invite_id == invite_id) {
foreach (Jid jid in call_state.peers.keys) {
- if (jid.equals(peer_jid)) {
+ if (jid.equals_bare(relevant_jid)) {
return call_state;
}
}
}
- if (call_state.invited_to_group_call != null && call_state.invited_to_group_call.equals(peer_jid)) return call_state;
+ if (call_state.invited_to_group_call != null && call_state.invited_to_group_call.equals(relevant_jid)) return call_state;
+ }
+ return null;
+ }
+
+ private PeerState? get_peer_by_sid(Account account, string sid, Jid jid1, Jid jid2) {
+ Jid relevant_jid = jid1.equals_bare(account.bare_jid) ? jid2 : jid1;
+
+ foreach (CallState call_state in call_states.values) {
+ if (!call_state.call.account.equals(account)) continue;
+
+ foreach (PeerState peer_state in call_state.peers.values) {
+ if (peer_state.sid != sid) continue;
+ if (peer_state.jid.equals_bare(relevant_jid)) {
+ return peer_state;
+ }
+ }
}
return null;
}
- private async void on_muji_call_received(Account account, Jid inviter_jid, Jid muc_jid, string invite_id, bool video, string message_type) {
+ private CallState? create_recv_muji_call(Account account, Jid inviter_jid, Jid muc_jid, string invite_id, 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;
+ if (!call.account.equals(account)) return null;
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;
+ call_state.cim_invite_id = invite_id;
+ return null;
}
if (call.counterparts.contains(inviter_jid) && call_state.accepted) {
// A call is converted into a group call.
- yield call_state.join_group_call(muc_jid);
- return;
+ call_state.join_group_call.begin(muc_jid);
+ return null;
}
}
@@ -284,27 +308,23 @@ namespace Dino {
call.encryption = Encryption.UNKNOWN;
call.state = Call.State.RINGING;
+ // TODO create conv
Conversation? conversation = stream_interactor.get_module(ConversationManager.IDENTITY).get_conversation(inviter_jid.bare_jid, account);
stream_interactor.get_module(CallStore.IDENTITY).add_call(call, conversation);
conversation.last_active = call.time;
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;
call_state.invited_to_group_call = muc_jid;
- call_state.group_call_inviter = inviter_jid;
- call_state.invite_id = invite_id;
+ call_state.parent_muc = inviter_jid.bare_jid;
debug("[%s] on_muji_call_received accepting", account.bare_jid.to_string());
- call_incoming(call_state.call, call_state, conversation, video);
+
+ return call_state;
}
private void remove_call_from_datastructures(Call call) {
- if (current_jmi_request_call.has_key(call.account) && current_jmi_request_call[call.account].call.equals(call)) {
- current_jmi_request_call.unset(call.account);
- current_jmi_request_peer.unset(call.account);
- }
+ jmi_request_peer.unset(call);
call_states.unset(call);
}
@@ -339,33 +359,36 @@ namespace Dino {
PeerState peer_state = create_received_call(account, from, to, video_requested);
peer_state.sid = sid;
- peer_state.we_should_send_audio = true;
- peer_state.we_should_send_video = video_requested;
- current_jmi_request_peer[account] = peer_state;
- current_jmi_request_call[account] = call_states[peer_state.call];
+ CallState call_state = call_states[peer_state.call];
+ call_state.we_should_send_audio = true;
+ call_state.we_should_send_video = video_requested;
+
+ jmi_request_peer[call_state.call] = peer_state;
});
mi_module.session_accepted.connect((from, to, sid) => {
- if (!current_jmi_request_peer.has_key(account) || current_jmi_request_peer[account].sid != sid) return;
+ PeerState? peer_state = get_peer_by_sid(account, sid, from, to);
+ if (peer_state == null) return;
+ Call call = peer_state.call;
if (from.equals_bare(account.bare_jid)) { // Carboned message from our account
// Ignore carbon from ourselves
if (from.equals(account.full_jid)) return;
- Call call = current_jmi_request_peer[account].call;
call.ourpart = from;
call.state = Call.State.OTHER_DEVICE;
remove_call_from_datastructures(call);
- } else if (from.equals_bare(current_jmi_request_peer[account].jid) && to.equals(account.full_jid)) { // Message from our peer
+ } else if (from.equals_bare(peer_state.jid) && to.equals(account.full_jid)) { // Message from our peer
// We proposed the call
// We know the full jid of our peer now
- current_jmi_request_call[account].rename_peer(current_jmi_request_peer[account].jid, from);
- current_jmi_request_peer[account].call_resource.begin(from);
+ call_states[call].rename_peer(jmi_request_peer[call].jid, from);
+ jmi_request_peer[call].call_resource.begin(from);
}
});
mi_module.session_rejected.connect((from, to, sid) => {
- if (!current_jmi_request_peer.has_key(account) || current_jmi_request_peer[account].sid != sid) return;
- Call call = current_jmi_request_peer[account].call;
+ PeerState? peer_state = get_peer_by_sid(account, sid, from, to);
+ if (peer_state == null) return;
+ Call call = peer_state.call;
bool outgoing_reject = call.direction == Call.DIRECTION_OUTGOING && from.equals_bare(call.counterparts[0]);
bool incoming_reject = call.direction == Call.DIRECTION_INCOMING && from.equals_bare(account.bare_jid);
@@ -379,8 +402,9 @@ namespace Dino {
remove_call_from_datastructures(call);
});
mi_module.session_retracted.connect((from, to, sid) => {
- if (!current_jmi_request_peer.has_key(account) || current_jmi_request_peer[account].sid != sid) return;
- Call call = current_jmi_request_peer[account].call;
+ PeerState? peer_state = get_peer_by_sid(account, sid, from, to);
+ if (peer_state == null) return;
+ Call call = peer_state.call;
bool outgoing_retract = call.direction == Call.DIRECTION_OUTGOING && from.equals_bare(account.bare_jid);
bool incoming_retract = call.direction == Call.DIRECTION_INCOMING && from.equals_bare(call.counterpart);
@@ -392,42 +416,92 @@ namespace Dino {
});
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) => {
+ call_invites_module.call_proposed.connect((from_jid, to_jid, video_requested, join_methods, message_stanza) => {
if (from_jid.equals_bare(account.bare_jid)) return;
+
+ 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;
+ }
+
+ CallState? call_state = null;
+
foreach (StanzaNode join_method_node in join_methods) {
- if (join_method_node.ns_uri == Xep.Muji.NS_URI) {
+ if (join_method_node.name == "muji" && join_method_node.ns_uri == Xep.Muji.NS_URI) {
+
+ // This is a MUJI invite
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_);
+ call_state = create_recv_muji_call(account, from_jid, room_jid, invite_id, message_stanza.type_);
+ break;
+
+ } else if (join_method_node.name == "jingle" && join_method_node.ns_uri == Xep.CallInvites.NS_URI) {
+
+ // This is an invite for a direct Jingle session
+ if (message_stanza.type_ != Xmpp.MessageStanza.TYPE_CHAT) return;
+
+ string? sid = join_method_node.get_attribute("sid");
+ if (sid == null) return;
+
+ PeerState peer_state = create_received_call(account, from_jid, to_jid, video_requested);
+ peer_state.sid = sid;
+
+ call_state = call_states[peer_state.call];
+
+ jmi_request_peer[call_state.call] = peer_state;
+ break;
}
}
- });
- 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_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);
+ call_state.we_should_send_audio = true;
+ call_state.we_should_send_video = video_requested;
+
+ call_state.use_cim = true;
+ call_state.cim_invite_id = invite_id;
+ call_state.cim_counterpart = message_stanza.type_ == MessageStanza.TYPE_GROUPCHAT ? from_jid.bare_jid : from_jid;
+ call_state.cim_message_type = message_stanza.type_;
+
+ Conversation? conversation = stream_interactor.get_module(ConversationManager.IDENTITY).approx_conversation_for_stanza(from_jid, to_jid, account, message_stanza.type_);
+ conversation.last_active = call_state.call.time;
+ if (conversation == null) return;
+
+ call_incoming(call_state.call, call_state, conversation, video_requested);
+ });
+ call_invites_module.call_accepted.connect((from_jid, to_jid, invite_id, message_type) => {
+ CallState? call_state = get_call_state_by_invite_id(account, invite_id, from_jid, to_jid);
+ if (call_state == null) return;
+ Call call = call_state.call;
+
+ if (from_jid.equals_bare(account.bare_jid)) { // Carboned message from our account
+ // Ignore carbon from ourselves
+ if (from_jid.equals(account.full_jid)) return;
+
+ // We accepted the call from another device
+ call.ourpart = from_jid;
+ call.state = Call.State.OTHER_DEVICE;
+ remove_call_from_datastructures(call);
+ } else if (to_jid.equals(account.full_jid)) { // Message from our peer
+ // We proposed the call
+ // We know the full jid of our peer now
+ call_states[call].rename_peer(jmi_request_peer[call].jid, from_jid);
+ jmi_request_peer[call].call_resource.begin(from_jid);
+ }
});
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_by_invite_id(account, from_jid, invite_id);
+ CallState? call_state = get_call_state_by_invite_id(account, invite_id, from_jid, to_jid);
if (call_state == null) return;
if (call_state.call.state != Call.State.RINGING) {