diff options
Diffstat (limited to 'libdino/src/service/calls.vala')
-rw-r--r-- | libdino/src/service/calls.vala | 208 |
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) { |